XStreamingElement Classe

Definição

Representa elementos numa árvore XML que suporta saída de streaming diferida.

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

Exemplos

O exemplo seguinte cria primeiro uma árvore XML de origem. Depois, cria uma transformação da árvore XML de origem usando XElement. Esta transformação cria uma nova árvore na memória. Depois, cria uma transformação da árvore XML de origem usando XStreamingElement. Esta transformação não executa a consulta até que a árvore transformada seja serializada para a consola. O 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 ficheiro de texto é escrever um método de extensão que transmite o ficheiro de texto linha a linha usando o yield return construto. Depois podes escrever uma consulta LINQ que processa o ficheiro de texto de forma preguiçosa e diferida. Se depois usar a XStreamingElement saída do to stream, pode criar uma transformação do ficheiro de texto para XML que use uma quantidade mínima de memória, independentemente do tamanho do ficheiro de texto de origem.

O ficheiro de texto seguinte, People.txt, é a fonte deste exemplo.

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

O código seguinte contém um método de extensão que transmite as linhas do ficheiro de texto de forma diferida.

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>

Por vezes, tem de transformar ficheiros XML grandes e escrever a sua aplicação de forma a que a área de memória da aplicação seja previsível. Se tentares preencher uma árvore XML com um ficheiro XML muito grande, o teu uso de memória será proporcional ao tamanho do ficheiro (ou seja, excessivo). Por isso, deve usar uma técnica de streaming.

Certos operadores de consulta padrão, como OrderBy, iteram a sua fonte, recolhem todos os dados, ordenam-nos e, finalmente, produzem o primeiro item da sequência. Note que, se usar um operador de consulta que materializa a sua fonte antes de fornecer o primeiro item, não manterá uma pequena área de memória para a sua aplicação.

Mesmo que use a técnica descrita em , se tentar montar uma árvore XML que contenha o documento transformado, o uso de memória pode ser demasiado elevado.

O exemplo seguinte baseia-se no exemplo em Como transmitir fragmentos XML com acesso à informação do cabeçalho.

Este exemplo utiliza as capacidades de execução diferida de XStreamingElement para transmitir a saída.

Note que o eixo personalizado (StreamCustomerItem) é especificamente escrito de modo a esperar um documento que tenha Customer, Name, e Item elementos, e que esses elementos sejam organizados como no documento Source.xml seguinte. Uma implementação mais robusta, no entanto, validaria o documento de origem com um XSD, ou estaria preparada para analisar um documento inválido.

Segue-se o documento fonte, 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 seguinte contém um método que utiliza um XmlReader para transmitir o XML de origem. Ele é usado 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>

Observações

Esta classe permite-lhe criar uma árvore XML que suporta saída de streaming diferido. Usa esta classe para criar uma árvore XML de forma muito semelhante à criação de uma árvore XML usando XElement. No entanto, existe uma diferença fundamental. Quando se usa uma consulta LINQ para especificar 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. Em contraste, quando se 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 apenas após serialização. Isto permite criar árvores XML maiores mantendo uma área de memória menor.

Se estiver a transmitir a partir de uma fonte de entrada, como um ficheiro de texto, pode ler um ficheiro de texto muito grande e gerar um documento XML muito grande mantendo uma pequena área de memória.

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

Note-se que, ao depurar um programa que usa XStreamingElement, mostrar o valor de um objeto faz com que o seu ToString método seja chamado. Isto faz com que o XML seja serializado. Se a semântica da sua consulta ao elemento de streaming for tal que o elemento de streaming só pode ser transmitido uma vez, isso pode causar comportamentos indesejáveis na sua experiência de depuração.

Construtores

Name Description
XStreamingElement(XName, Object)

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

XStreamingElement(XName, Object[])

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

XStreamingElement(XName)

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

Propriedades

Name Description
Name

Recebe ou define o nome deste elemento de streaming.

Métodos

Name Description
Add(Object)

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

Add(Object[])

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

Equals(Object)

Determina se o objeto especificado é igual ao objeto atual.

(Herdado de Object)
GetHashCode()

Serve como função de hash predefinida.

(Herdado de Object)
GetType()

Obtém o Type da instância atual.

(Herdado de Object)
MemberwiseClone()

Cria uma cópia superficial do atual Object.

(Herdado de Object)
Save(Stream, SaveOptions)

Exporta isto XStreamingElement para o especificado Stream, opcionalmente especificando o comportamento de formatação.

Save(Stream)

Envia isto XStreamingElement para o especificado Stream.

Save(String, SaveOptions)

Serialize este elemento de streaming para um ficheiro, desativando opcionalmente a formatação.

Save(String)

Serialize este elemento de streaming para um ficheiro.

Save(TextWriter, SaveOptions)

Serialize este elemento de streaming para um TextWriter, desativando opcionalmente a formatação.

Save(TextWriter)

Serialize este elemento de streaming para um TextWriter.

Save(XmlWriter)

Serialize este elemento de streaming para um XmlWriter.

ToString()

Devolve o XML formatado (indentado) para este elemento de streaming.

ToString(SaveOptions)

Devolve o XML deste elemento de streaming, desativando opcionalmente a formatação.

WriteTo(XmlWriter)

Escreve este elemento de streaming num XmlWriter.

Aplica-se a

Ver também