XStreamingElement 類別

定義

代表 XML 樹狀結構中的元素,該樹狀結構支援延後的資料流輸出。

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

範例

下列範例會先建立來源 XML 樹狀結構。 然後,它會使用 XElement 建立來源 XML 樹狀結構的轉換。 此轉換會在記憶體中建立新的樹狀結構。 然後,它會使用 XStreamingElement 建立來源 XML 樹狀結構的轉換。 在轉換的樹狀結構序列化至主控台之前,此轉換不會執行查詢。 其記憶體使用量較少。

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 來串流輸出,則不論來源文字檔的大小為何,您都可以從文字檔建立轉換到使用最少記憶體量的 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) 是特別撰寫的,讓它預備擁有 CustomerNameItem 項目的文件,並預期這些項目將會與下列 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>

下列程式碼包含用來串流來源 XML 的方法 XmlReader 。 它會使用 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 樹狀結構,以使用 XElement 建立 XML 樹狀結構。 不過,有基本差異。 當您使用 LINQ 查詢來指定使用 XElement 建立 XML 樹狀結構時的內容時,會在建構 XML 樹狀結構時逐一查看查詢變數,並將查詢的結果新增至 XML 樹狀結構。 相反地,當您使用 XStreamingElement 建立 XML 樹狀結構時,查詢變數的參考會儲存在 XML 樹狀結構中,而不會進行逐一查看。 查詢只會在序列化時逐一查看。 這可讓您建立較大的 XML 樹狀結構,同時維持較小的記憶體使用量。

如果您要從輸入來源串流處理,例如文字檔,則您可以讀取非常大的文字檔,並產生非常大的 XML 檔,同時維持較小的記憶體使用量。

另一個案例是,您有已載入記憶體的大型 XML 樹狀結構,而您想要建立已轉換的檔版本。 如果您使用 建立新的檔 XElement ,則完成轉換時,記憶體中會有兩個大型 XML 樹狀結構。 不過,如果您使用 建立新的 XML 樹狀結構 XStreamingElement ,則您的工作集將會有效地剪下一半。

請注意,偵錯使用 XStreamingElement 的程式時,顯示 物件的值會導致呼叫其 ToString 方法。 這會導致 XML 序列化。 如果串流專案查詢的語意如此,串流元素只能串流一次,這可能會導致偵錯體驗中不想要的行為。

建構函式

XStreamingElement(XName)

從指定的 XName 初始化 XElement 類別的新執行個體。

XStreamingElement(XName, Object)

使用指定的名稱和內容初始化 XStreamingElement 類別的新執行個體。

XStreamingElement(XName, Object[])

使用指定的名稱和內容初始化 XStreamingElement 類別的新執行個體。

屬性

Name

取得或設定這個資料流項目的名稱。

方法

Add(Object)

將指定的內容當做子系加入至這個 XStreamingElement

Add(Object[])

將指定的內容當做子系加入至這個 XStreamingElement

Equals(Object)

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

(繼承來源 Object)
GetHashCode()

做為預設雜湊函式。

(繼承來源 Object)
GetType()

取得目前執行個體的 Type

(繼承來源 Object)
MemberwiseClone()

建立目前 Object 的淺層複製。

(繼承來源 Object)
Save(Stream)

將這個 XStreamingElement 輸出到指定的 Stream

Save(Stream, SaveOptions)

將這個 XStreamingElement 輸出至指定的 Stream,選擇性地指定格式化行為。

Save(String)

將這個資料流項目序列化成檔案。

Save(String, SaveOptions)

將這個資料流項目序列化成檔案 (可選擇是否停用格式設定)。

Save(TextWriter)

將這個資料流項目序列化成 TextWriter

Save(TextWriter, SaveOptions)

將這個資料流項目序列化成 TextWriter (可選擇是否停用格式設定)。

Save(XmlWriter)

將這個資料流項目序列化成 XmlWriter

ToString()

傳回這個資料流項目之格式化 (縮排) 的 XML。

ToString(SaveOptions)

傳回這個資料流項目的 XML (可選擇是否停用格式設定)。

WriteTo(XmlWriter)

將這個資料流項目寫入 XmlWriter

適用於

另請參閱