XStreamingElement Classe

Definizione

Rappresenta gli elementi in un albero XML che supporta l'output del flusso posticipato.

public ref class XStreamingElement
public class XStreamingElement
type XStreamingElement = class
Public Class XStreamingElement
Ereditarietà
XStreamingElement

Esempio

L'esempio seguente crea prima un albero XML di origine. Crea quindi una trasformazione dell'albero XML di origine usando XElement. Questa trasformazione crea un nuovo albero in memoria. Crea quindi una trasformazione dell'albero XML di origine usando XStreamingElement. Questa trasformazione non esegue la query finché l'albero trasformato non viene serializzato nella console. L'utilizzo della memoria è minore.

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)

Nell'esempio viene prodotto l'output seguente:

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

Uno degli approcci disponibili per l'elaborazione di un file di testo consiste nello scrivere un metodo di estensione che genera un flusso del file di testo, una riga alla volta, tramite il costrutto yield return. È quindi possibile scrivere una query LINQ che elabora il file di testo in modo posticipato lazy. Se si usa quindi per trasmettere l'output XStreamingElement , è possibile creare una trasformazione dal file di testo a XML che usa una quantità minima di memoria, indipendentemente dalle dimensioni del file di testo di origine.

Il file di testo seguente, People.txt, è l'origine di questo esempio.

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

Nel codice seguente è contenuto un metodo di estensione che genera il flusso delle righe del file di testo in modo posticipato.

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

Nell'esempio viene prodotto l'output seguente:

<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>

A volte è necessario trasformare file XML di grandi dimensioni e scrivere l'applicazione in modo tale che il footprint di memoria dell'applicazione sia prevedibile. Se si tenta di popolare un albero XML con un file XML molto grande, l'uso della memoria sarà proporzionale alla dimensione del file (ovvero, eccessivo). Pertanto, è necessario usare una tecnica di flusso in sostituzione.

Determinati operatori di query standard, ad esempio OrderBy, scorrono l'origine, raccolgono tutti i dati, li ordinano e infine restituiscono il primo elemento nella sequenza. Si noti che se si usa un operatore di query che materializza l'origine prima di restituire il primo elemento, non verrà mantenuto un footprint di memoria ridotto per l'applicazione.

Anche se si usa la tecnica descritta in , se si tenta di assemblare un albero XML contenente il documento trasformato, l'utilizzo della memoria potrebbe essere troppo grande.

L'esempio seguente si basa sull'esempio in Come trasmettere frammenti XML con accesso alle informazioni sull'intestazione.

In questo esempio vengono usate le funzionalità di esecuzione posticipata di XStreamingElement per generare il flusso di output.

Si noti che il metodo dell'asse personalizzato (StreamCustomerItem) è stato scritto in modo tale da prevedere un documento contenente elementi Customer, Name e Item, disposti come nel documento Source.xml seguente. Tuttavia, un'implementazione più affidabile convaliderebbe il documento di origine con uno schema XSD oppure verrebbe preparata per analizzare un documento non valido.

Il documento seguente, Source.xml, è il documento di origine:

<?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>

Il codice seguente contiene un metodo che usa un XmlReader oggetto per trasmettere il codice XML di origine. Usa XStreamingElement per trasmettere il nuovo 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

Nell'esempio viene prodotto l'output seguente:

<?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>

Commenti

Questa classe consente di creare un albero XML che supporta l'output di streaming posticipato. Questa classe consente di creare un albero XML in modo molto simile alla creazione di un albero XML usando XElement. Tuttavia, esiste una differenza fondamentale. Quando si usa una query LINQ per specificare il contenuto quando si crea un albero XML usando XElement, la variabile di query viene iterazione al momento della costruzione dell'albero XML e i risultati della query vengono aggiunti all'albero XML. Al contrario, quando si crea un albero XML usando XStreamingElement, un riferimento alla variabile di query viene archiviato nell'albero XML senza essere sottoposto a iterazione. Le query vengono iterate solo dopo la serializzazione. In questo modo è possibile creare alberi XML più grandi mantenendo un footprint di memoria più piccolo.

Se si esegue lo streaming da un'origine di input, ad esempio un file di testo, è possibile leggere un file di testo molto grande e generare un documento XML molto grande mantenendo un footprint di memoria ridotto.

Un altro scenario è che si dispone di un albero XML di grandi dimensioni caricato in memoria e si vuole creare una versione trasformata del documento. Se si crea un nuovo documento usando XElement, si avranno due alberi XML di grandi dimensioni in memoria al termine della trasformazione. Tuttavia, se si crea il nuovo albero XML usando XStreamingElement, il set di lavoro verrà tagliato effettivamente a metà.

Si noti che quando si esegue il debug di un programma che usa XStreamingElement, visualizzando il valore di un oggetto viene chiamato il ToString metodo. In questo modo, il codice XML deve essere serializzato. Se la semantica della query dell'elemento di streaming è tale che l'elemento di streaming può essere trasmesso una sola volta, questo può causare un comportamento indesiderato nell'esperienza di debug.

Costruttori

XStreamingElement(XName)

Inizializza una nuova istanza della classe XElement dall'oggetto XName specificato.

XStreamingElement(XName, Object)

Inizializza una nuova istanza della classe XStreamingElement con il nome e il contenuto specificati.

XStreamingElement(XName, Object[])

Inizializza una nuova istanza della classe XStreamingElement con il nome e il contenuto specificati.

Proprietà

Name

Ottiene o imposta il nome dell'elemento di flusso.

Metodi

Add(Object)

Aggiunge il contenuto specificato come figlio a XStreamingElement.

Add(Object[])

Aggiunge il contenuto specificato come figlio a XStreamingElement.

Equals(Object)

Determina se l'oggetto specificato è uguale all'oggetto corrente.

(Ereditato da Object)
GetHashCode()

Funge da funzione hash predefinita.

(Ereditato da Object)
GetType()

Ottiene l'oggetto Type dell'istanza corrente.

(Ereditato da Object)
MemberwiseClone()

Crea una copia superficiale dell'oggetto Object corrente.

(Ereditato da Object)
Save(Stream)

Restituisce l'oggetto XStreamingElement nell'oggetto Stream specificato.

Save(Stream, SaveOptions)

Restituisce l'oggetto XStreamingElement nell'oggetto Stream specificato, indicando facoltativamente il comportamento di formattazione.

Save(String)

Serializzare questo elemento di flusso in un file.

Save(String, SaveOptions)

Serializzare questo elemento di flusso in un file, disabilitando facoltativamente la formattazione.

Save(TextWriter)

Serializzare questo elemento di flusso in un TextWriter.

Save(TextWriter, SaveOptions)

Serializzare questo elemento di flusso in un TextWriter, disabilitando facoltativamente la formattazione.

Save(XmlWriter)

Serializzare questo elemento di flusso in un XmlWriter.

ToString()

Restituisce il codice XML formattato (con rientro) per questo elemento di flusso.

ToString(SaveOptions)

Restituisce il codice XML per questo elemento di flusso, disabilitando facoltativamente la formattazione.

WriteTo(XmlWriter)

Scrive questo elemento di flusso in un XmlWriter.

Si applica a

Vedi anche