語言

XStreamingElement 類別

定義

代表支援延遲串流輸出的 XML 樹中的元素。

public ref class XStreamingElement
public class XStreamingElement
type XStreamingElement = class
Public Class XStreamingElement
繼承
XStreamingElement

範例

以下範例首先建立一個原始碼 XML 樹。 接著它會使用 XElement。 此轉換會在記憶體中建立新的樹狀結構。 接著它會使用 XStreamingElement。 這個轉換直到轉換後的樹被序列化到主控台時才會執行查詢。 它的記憶體使用量較低。

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)

此範例會產生下列輸出:

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

處理文字檔的一種方法是撰寫擴充方法,利用結構 yield return 一行逐行串流文字檔。 接著你可以寫一個 LINQ 查詢,以懶惰延遲的方式處理文字檔。 如果你接著使用 XStreamingElement to stream 輸出,就能從文字檔轉換成 XML,無論原始文字檔大小大小,都能用最少的記憶體。

以下文字檔 People.txt,即為此範例的來源。

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

以下程式碼包含一種擴充方法,以延遲方式串流文字檔的行數。

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

此範例會產生下列輸出:

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

有時你必須轉換大型 XML 檔案,並撰寫應用程式,使應用程式的記憶體佔用量可預測。 如果你嘗試用非常大的 XML 檔案填充 XML 樹,記憶體使用量會與檔案大小成正比(也就是說,過度使用)。 因此,你應該改用串流技術。

某些標準查詢運算子,如 OrderBy,會迭代其來源,收集所有資料,排序,最後產生序列中的第一個項目。 請注意,如果你使用查詢運算子在產生第一個項目前就已實現其來源,應用程式將不會佔用少量記憶體。

即使你使用中描述的技術,如果你嘗試組合包含轉換後文件的 XML 樹,記憶體使用量也可能過高。

以下範例建立在 《如何串流帶有標頭資訊的 XML 片段》中的範例之上。

此範例利用延遲 XStreamingElement 執行能力來串流輸出。

請注意,自訂軸StreamCustomerItem()特別寫成預期文件 Customer包含 、 Name和 Item 元素,且這些元素的排列方式如下 Source.xml 文件。 然而,更穩健的實作會用 XSD 驗證原始文件,或準備解析無效文件。

以下是原始文件,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>

以下程式碼包含一種使用 來 XmlReader 串流原始碼 XML 的方法。 它用 XStreamingElement 來串流新的 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

此範例會產生下列輸出:

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

備註

這門課允許你建立一個支援延遲串流輸出的 XML 樹。 你可以用這個類別來建立 XML 樹,方式與使用 XElementS 建立 XML 樹非常相似。 然而,兩者有根本的差異。 當你使用 LINQ 查詢來指定內容,並使用 XElement使用 XML樹時,查詢變數會在建構 XML 樹時迭代,查詢結果也會加入 XML 樹中。 相較之下,當你使用 XStreamingElement建立 XML 樹時,查詢變數的參考會儲存在 XML 樹中,且不會被重複。 查詢僅在序列化時重複執行。 這讓你能建立更大的 XML 樹,同時維持較小的記憶體佔用。

如果你是從輸入來源串流,例如文字檔,那麼你可以讀取非常大的文字檔,並在保持少量記憶體佔用的情況下產生非常大的 XML 文件。

另一種情況是你有一個大型 XML 樹已被載入記憶體,你想建立一個轉換後的文件版本。 如果你用 XElement建立新文件,那麼轉換完成後,記憶體中會有兩棵大型 XML 樹。 然而,如果你用 XStreamingElement來建立新的 XML 樹,那麼你的工作集實際上會被切半。

請注意,除錯使用 XStreamingElement的程式時,顯示物件的值會促使其 ToString 方法被呼叫。 這會使 XML 被序列化。 如果你的串流元素查詢的語意是該串流元素只能串流一次,可能會導致除錯體驗出現不良行為。

建構函式

名稱 Description
XStreamingElement(XName, Object)

初始化一個以指定名稱和內容的新類別實例 XStreamingElement 。

XStreamingElement(XName, Object[])

初始化一個以指定名稱和內容的新類別實例 XStreamingElement 。

XStreamingElement(XName)

從指定的XElement類別中初始化一個新的實例XName。

屬性

名稱 Description
Name

取得或設定這個串流元素的名稱。

方法

名稱 Description
Add(Object)

會將指定內容加入子 XStreamingElement節點。

Add(Object[])

會將指定內容加入子 XStreamingElement節點。

Equals(Object)

判斷指定的物件是否等於目前的物件。

(繼承來源 Object)
GetHashCode()

做為預設哈希函式。

(繼承來源 Object)
GetType()

取得目前實例的 Type。

(繼承來源 Object)
MemberwiseClone()

建立目前 Object的淺層複本。

(繼承來源 Object)
Save(Stream, SaveOptions)

輸出 XStreamingElement 為指定的 Stream格式行為,可選擇性地指定格式化。

Save(Stream)

XStreamingElement輸出為指定的 Stream。

Save(String, SaveOptions)

將此串流元素序列化為檔案,並可選擇關閉格式化。

Save(String)

將這個串流元素序列化成一個檔案。

Save(TextWriter, SaveOptions)

將此串流元素序列化為 TextWriter可選擇性停用格式。

Save(TextWriter)

將此串流元素序列化為 TextWriter。

Save(XmlWriter)

將此串流元素序列化為 XmlWriter.

ToString()

回傳此串流元素格式化(縮排)的 XML。

ToString(SaveOptions)

回傳此串流元素的 XML,並可選擇關閉格式化。

WriteTo(XmlWriter)

將這個串流元素寫入 XmlWriter.

適用於

另請參閱