XStreamingElement Classe

Definição

Representa elementos em uma árvore XML que dá suporte à saída de streaming adiada.

public ref class XStreamingElement
public class XStreamingElement
type XStreamingElement = class
Public Class XStreamingElement
Herança
XStreamingElement

Exemplos

O exemplo a seguir primeiro cria uma árvore XML de origem. Em seguida, ele cria uma transformação da árvore XML de origem usando XElement. Essa transformação cria uma nova árvore na memória. Em seguida, ele cria uma transformação da árvore XML de origem usando XStreamingElement. Essa transformação não executa a consulta até que a árvore transformada seja serializada no console. Seu uso de memória é menor.

XElement srcTree = new XElement("Root",
                       new XElement("Child", 1),
                       new XElement("Child", 2),
                       new XElement("Child", 3),
                       new XElement("Child", 4),
                       new XElement("Child", 5)
                   );

XElement dstTree1 = new XElement("NewRoot",
                        from el in srcTree.Elements()
                        where (int)el >= 3
                        select new XElement("DifferentChild", (int)el)
                    );

XStreamingElement dstTree2 = new XStreamingElement("NewRoot",
                        from el in srcTree.Elements()
                        where (int)el >= 3
                        select new XElement("DifferentChild", (int)el)
                    );

Console.WriteLine(dstTree1);
Console.WriteLine("------");
Console.WriteLine(dstTree2);
Dim srcTree As XElement = _
        <Root>
            <Child>1</Child>
            <Child>2</Child>
            <Child>3</Child>
            <Child>4</Child>
            <Child>5</Child>
        </Root>

Dim dstTree1 As XElement = _
    <NewRoot>
        <%= From el In srcTree.Elements _
            Where (el.Value >= 3) _
            Select <DifferentChild><%= el.Value %></DifferentChild> %>
    </NewRoot>

Dim dstTree2 As XStreamingElement = New XStreamingElement("NewRoot", _
                From el In srcTree.Elements _
                Where el.Value >= 3 _
                Select <DifferentChild><%= el.Value %></DifferentChild> _
            )

Console.WriteLine(dstTree1)
Console.WriteLine("------")
Console.WriteLine(dstTree2)

Este exemplo produz a seguinte saída:

<NewRoot>
  <DifferentChild>3</DifferentChild>
  <DifferentChild>4</DifferentChild>
  <DifferentChild>5</DifferentChild>
</NewRoot>
------
<NewRoot>
  <DifferentChild>3</DifferentChild>
  <DifferentChild>4</DifferentChild>
  <DifferentChild>5</DifferentChild>
</NewRoot>

Uma abordagem para processar um arquivo de texto é gravar um método de extensão que transmite ao arquivo de texto uma linha de cada vez usando o yield return constructo. Em seguida, você pode escrever uma consulta LINQ que processa o arquivo de texto de forma adiada lenta. Se você usar a XStreamingElement saída para transmitir, poderá criar uma transformação do arquivo de texto para o XML que usa uma quantidade mínima de memória, independentemente do tamanho do arquivo de texto de origem.

O arquivo de texto a seguir, People.txt, é a origem deste exemplo.

#This is a comment
1,Tai,Yee,Writer
2,Nikolay,Grachev,Programmer
3,David,Wright,Inventor

O código a seguir contém um método de extensão que transmite as linhas do arquivo de texto de forma adiada.

public static class StreamReaderSequence
{
    public static IEnumerable<string> Lines(this StreamReader source)
    {
        String line;

        if (source == null)
            throw new ArgumentNullException("source");
        while ((line = source.ReadLine()) != null)
        {
            yield return line;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        StreamReader sr = new StreamReader("People.txt");
        XStreamingElement xmlTree = new XStreamingElement("Root",
            from line in sr.Lines()
            let items = line.Split(',')
            where !line.StartsWith("#")
            select new XElement("Person",
                       new XAttribute("ID", items[0]),
                       new XElement("First", items[1]),
                       new XElement("Last", items[2]),
                       new XElement("Occupation", items[3])
                   )
        );
        Console.WriteLine(xmlTree);
        sr.Close();
    }
}
Module StreamReaderSequence

    <Runtime.CompilerServices.Extension>
    Public Iterator Function Lines(source As IO.StreamReader) As IEnumerable(Of String)
        If source Is Nothing Then Throw New ArgumentNullException("source")
        Dim line As String = source.ReadLine()
        While (line <> Nothing)
            Yield line
            line = source.ReadLine()
        End While
    End Function

End Module

Module Module1
    Sub Main()
        Dim sr As New IO.StreamReader("People.txt")
        Dim xmlTree As New XStreamingElement("Root",
            From line In sr.Lines()
            Let items = line.Split(","c)
            Where Not line.StartsWith("#")
            Select <Person ID=<%= items(0) %>>
                       <First><%= items(1) %></First>
                       <Last><%= items(2) %></Last>
                       <Occupation><%= items(3) %></Occupation>
                   </Person>)
        Console.WriteLine(xmlTree)
        sr.Close()
    End Sub
End Module

Este exemplo produz a seguinte saída:

<Root>
  <Person ID="1">
    <First>Tai</First>
    <Last>Yee</Last>
    <Occupation>Writer</Occupation>
  </Person>
  <Person ID="2">
    <First>Nikolay</First>
    <Last>Grachev</Last>
    <Occupation>Programmer</Occupation>
  </Person>
  <Person ID="3">
    <First>David</First>
    <Last>Wright</Last>
    <Occupation>Inventor</Occupation>
  </Person>
</Root>

Às vezes, você precisa transformar arquivos XML grandes e gravar seu aplicativo para que o volume de memória do aplicativo seja previsível. Se você tentar preencher uma árvore XML com um arquivo XML muito grande, o uso da memória será proporcional ao tamanho do arquivo (ou seja, excessivo). Portanto, você deve usar uma técnica de streaming.

Determinados operadores de consulta padrão, como OrderBy, iterar sua origem, coletar todos os dados, classificá-los e, finalmente, produzir o primeiro item na sequência. Observe que, se você usar um operador de consulta que materialize sua origem antes de produzir o primeiro item, não manterá um pequeno volume de memória para seu aplicativo.

Mesmo se você usar a técnica descrita, se você tentar montar uma árvore XML que contenha o documento transformado, o uso de memória poderá ser muito grande.

O exemplo a seguir baseia-se no exemplo em Como transmitir fragmentos XML com acesso a informações de cabeçalho.

Este exemplo usa os recursos de execução adiados para XStreamingElement transmitir a saída.

Observe que o eixo personalizado (StreamCustomerItem) é escrito especificamente para que ele espere um documento que tenha Customer, Namee elementos, e Item que esses elementos serão organizados como no documento Source.xml a seguir. No entanto, uma implementação mais robusta validaria o documento de origem com um XSD ou estaria preparada para analisar um documento inválido.

Veja a seguir o documento de origem, Source.xml:

<?xml version="1.0" encoding="utf-8" ?>
<Root>
  <Customer>
    <Name>A. Datum Corporation</Name>
    <Item>
      <Key>0001</Key>
    </Item>
    <Item>
      <Key>0002</Key>
    </Item>
    <Item>
      <Key>0003</Key>
    </Item>
    <Item>
      <Key>0004</Key>
    </Item>
  </Customer>
  <Customer>
    <Name>Fabrikam, Inc.</Name>
    <Item>
      <Key>0005</Key>
    </Item>
    <Item>
      <Key>0006</Key>
    </Item>
    <Item>
      <Key>0007</Key>
    </Item>
    <Item>
      <Key>0008</Key>
    </Item>
  </Customer>
  <Customer>
    <Name>Southridge Video</Name>
    <Item>
      <Key>0009</Key>
    </Item>
    <Item>
      <Key>0010</Key>
    </Item>
  </Customer>
</Root>

O código a seguir contém um método que usa um XmlReader para transmitir o XML de origem. Ele usa XStreamingElement para transmitir o novo XML.

static IEnumerable<XElement> StreamCustomerItem(string uri)
{
    using (XmlReader reader = XmlReader.Create(uri))
    {
        XElement name = null;
        XElement item = null;

        reader.MoveToContent();

        // Parse the file, save header information when encountered, and yield the
        // Item XElement objects as they are created.

        // loop through Customer elements
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element
                && reader.Name == "Customer")
            {
                // move to Name element
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element &&
                        reader.Name == "Name")
                    {
                        name = XElement.ReadFrom(reader) as XElement;
                        break;
                    }
                }

                // loop through Item elements
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.EndElement)
                        break;
                    if (reader.NodeType == XmlNodeType.Element
                        && reader.Name == "Item")
                    {
                        item = XElement.ReadFrom(reader) as XElement;
                        if (item != null)
                        {
                            XElement tempRoot = new XElement("Root",
                                new XElement(name)
                            );
                            tempRoot.Add(item);
                            yield return item;
                        }
                    }
                }
            }
        }
    }
}

static void Main(string[] args)
{
    XStreamingElement root = new XStreamingElement("Root",
        from el in StreamCustomerItem("Source.xml")
        select new XElement("Item",
            new XElement("Customer", (string)el.Parent.Element("Name")),
            new XElement(el.Element("Key"))
        )
    );
    root.Save("Test.xml");
    Console.WriteLine(File.ReadAllText("Test.xml"));
}
Iterator Function StreamCustomerItem(uri As String) As IEnumerable(Of XElement)

    Dim name As XElement = Nothing
    Dim item As XElement = Nothing

    Dim reader As XmlReader = XmlReader.Create(uri)
    reader.MoveToContent()

    ' Parse the file, save header information when encountered, and yield the
    ' Item XElement objects as they are created.

    ' Loop through Customer elements.
    While (reader.Read())
        If (reader.NodeType = XmlNodeType.Element And reader.Name = "Customer") Then
            While (reader.Read())
                ' Move to Name element
                If (reader.NodeType = XmlNodeType.Element And reader.Name = "Name") Then
                    name = CType(XElement.ReadFrom(reader), XElement)
                    Exit While
                End If
            End While

            ' Loop through Item elements
            While (reader.Read())
                If (reader.NodeType = XmlNodeType.EndElement) Then
                    Exit While
                End If

                If (reader.NodeType = XmlNodeType.Element And reader.Name = "Item") Then
                    item = CType(XElement.ReadFrom(reader), XElement)
                    If (Not (item Is Nothing)) Then
                        Dim tempRoot = New XElement("Root",
                            New XElement(name)
                        )
                        tempRoot.Add(item)
                        Yield item
                     End If
                End If
            End While
        End If
     End While
    reader.Close()
End Function

Sub Main()
    Dim root As New XStreamingElement("Root",
        From el In StreamCustomerItem("c:\trash\Source.xml")
        Select New XElement("Item",
            New XElement("Customer", CStr(el.Parent.Element("Name"))),
            New XElement(el.Element("Key"))))
    root.Save("c:\trash\Test.xml")
    Console.WriteLine(System.IO.File.ReadAllText("c:\trash\Test.xml"))
End Sub

Este exemplo produz a seguinte saída:

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Item>
    <Customer>A. Datum Corporation</Customer>
    <Key>0001</Key>
  </Item>
  <Item>
    <Customer>A. Datum Corporation</Customer>
    <Key>0002</Key>
  </Item>
  <Item>
    <Customer>A. Datum Corporation</Customer>
    <Key>0003</Key>
  </Item>
  <Item>
    <Customer>A. Datum Corporation</Customer>
    <Key>0004</Key>
  </Item>
  <Item>
    <Customer>Fabrikam, Inc.</Customer>
    <Key>0005</Key>
  </Item>
  <Item>
    <Customer>Fabrikam, Inc.</Customer>
    <Key>0006</Key>
  </Item>
  <Item>
    <Customer>Fabrikam, Inc.</Customer>
    <Key>0007</Key>
  </Item>
  <Item>
    <Customer>Fabrikam, Inc.</Customer>
    <Key>0008</Key>
  </Item>
  <Item>
    <Customer>Southridge Video</Customer>
    <Key>0009</Key>
  </Item>
  <Item>
    <Customer>Southridge Video</Customer>
    <Key>0010</Key>
  </Item>
</Root>

Comentários

Essa classe permite que você crie uma árvore XML que dê suporte à saída de streaming adiada. Use essa classe para criar uma árvore XML de forma muito semelhante à criação de uma árvore XML usando XElement. No entanto, há uma diferença fundamental. Quando você usa uma consulta LINQ para especificar o conteúdo ao criar uma árvore XML usando XElement, a variável de consulta é iterada no momento da construção da árvore XML e os resultados da consulta são adicionados à árvore XML. Por outro lado, quando você cria uma árvore XML usando XStreamingElement, uma referência à variável de consulta é armazenada na árvore XML sem ser iterada. As consultas são iteradas somente após a serialização. Isso permite que você crie árvores XML maiores, mantendo um volume de memória menor.

Se você estiver transmitindo de uma fonte de entrada, como um arquivo de texto, poderá ler um arquivo de texto muito grande e gerar um documento XML muito grande, mantendo um volume de memória pequeno.

Outro cenário é que você tem uma árvore XML grande que foi carregada na memória e deseja criar uma versão transformada do documento. Se você criar um novo documento usando XElement, terá duas árvores XML grandes na memória após a conclusão da transformação. No entanto, se você criar a nova árvore XML usando XStreamingElement, o conjunto de trabalho será efetivamente cortado pela metade.

Observe que, ao depurar um programa que usa XStreamingElement, exibir o valor de um objeto faz com que seu ToString método seja chamado. Isso faz com que o XML seja serializado. Se a semântica da consulta do elemento de streaming for tal que o elemento de streaming só poderá ser transmitido uma vez, isso poderá causar um comportamento indesejável em sua experiência de depuração.

Construtores

Nome Description
XStreamingElement(XName, Object)

Inicializa uma nova instância da XStreamingElement classe com o nome e o conteúdo especificados.

XStreamingElement(XName, Object[])

Inicializa uma nova instância da XStreamingElement classe com o nome e o conteúdo especificados.

XStreamingElement(XName)

Inicializa uma nova instância da classe do XElement especificado XName.

Propriedades

Nome Description
Name

Obtém ou define o nome desse elemento de streaming.

Métodos

Nome Description
Add(Object)

Adiciona o conteúdo especificado como filhos a isso XStreamingElement.

Add(Object[])

Adiciona o conteúdo especificado como filhos a isso XStreamingElement.

Equals(Object)

Determina se o objeto especificado é igual ao objeto atual.

(Herdado de Object)
GetHashCode()

Serve como a função hash predefinida.

(Herdado de Object)
GetType()

Obtém o Type da instância atual.

(Herdado de Object)
MemberwiseClone()

Cria uma cópia superficial do Objectatual.

(Herdado de Object)
Save(Stream, SaveOptions)

Gera isso XStreamingElement para o comportamento de formatação especificado Stream, opcionalmente.

Save(Stream)

Gera isso XStreamingElement para o especificado Stream.

Save(String, SaveOptions)

Serialize esse elemento de streaming em um arquivo, opcionalmente desabilitando a formatação.

Save(String)

Serialize esse elemento de streaming em um arquivo.

Save(TextWriter, SaveOptions)

Serialize esse elemento de streaming para um TextWriter, opcionalmente desabilitando a formatação.

Save(TextWriter)

Serialize esse elemento de streaming para um TextWriter.

Save(XmlWriter)

Serialize esse elemento de streaming para um XmlWriter.

ToString()

Retorna o XML formatado (recuado) para esse elemento de streaming.

ToString(SaveOptions)

Retorna o XML para esse elemento de streaming, opcionalmente desabilitando a formatação.

WriteTo(XmlWriter)

Grava esse elemento de streaming em um XmlWriter.

Aplica-se a

Confira também