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>

以下代码包含一个用于 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 树。 使用此类以与使用 XElementXML 树创建 XML 树非常相似的方式创建 XML 树。 但是,有一个根本的区别。 使用 LINQ 查询在创建 XML 树 XElement时指定内容时,将在 XML 树的构造时迭代查询变量,并将查询结果添加到 XML 树中。 相比之下,使用 XML 树创建 XML 树 XStreamingElement时,对查询变量的引用将存储在 XML 树中,而无需进行迭代。 查询仅在序列化时进行迭代。 这样,可以创建更大的 XML 树,同时保持较小的内存占用。

如果要从输入源(如文本文件)进行流式处理,则可以读取非常大的文本文件,并在保持较小的内存占用的同时生成非常大的 XML 文档。

另一种情况是,你有一个大型的 XML 树,该树已加载到内存中,并且想要创建转换后的文档版本。 如果使用创建新文档 XElement,则在转换完成后,内存中将有两个大 XML 树。 但是,如果使用创建新的 XML 树 XStreamingElement,则工作集将有效削减一半。

请注意,调试使用 XStreamingElement的程序时,显示对象的值会导致调用其 ToString 方法。 这会导致 XML 序列化。 如果流式处理元素查询的语义使得流式处理元素只能流式传输一次,这可能会导致调试体验中出现不良行为。

构造函数

名称 说明
XStreamingElement(XName, Object)

使用指定的名称和内容初始化类的新实例 XStreamingElement

XStreamingElement(XName, Object[])

使用指定的名称和内容初始化类的新实例 XStreamingElement

XStreamingElement(XName)

从指定的XElement实例初始化类的新实例XName

属性

名称 说明
Name

获取或设置此流式处理元素的名称。

方法

名称 说明
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(缩进) XML。

ToString(SaveOptions)

返回此流式处理元素的 XML,可以选择禁用格式设置。

WriteTo(XmlWriter)

将此流式处理元素写入到 .XmlWriter

适用于

另请参阅