XStreamingElement 类
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
表示 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
) 经过专门编写,可以处理具有 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 树的方式与使用 XElement创建 XML 树的方式非常相似。 但是,有一个根本的区别。 在使用 创建 XML 树时使用 XElementLINQ 查询指定内容时,将在构造 XML 树时循环访问查询变量,并将查询结果添加到 XML 树中。 相反,使用 XStreamingElement创建 XML 树时,对查询变量的引用存储在 XML 树中,而不进行迭代。 仅在序列化时循环访问查询。 这使你可以创建更大的 XML 树,同时保持较小的内存占用量。
如果要从输入源(如文本文件)进行流式传输,则可以读取非常大的文本文件,并在保持较小的内存占用的同时生成非常大的 XML 文档。
另一种情况是,你有一个大型 XML 树,该树已加载到内存中,并且你想要创建文档的转换版本。 如果使用 创建新文档 XElement,则转换完成后,内存中将有两个大型 XML 树。 但是,如果使用 创建新的 XML 树 XStreamingElement,则工作集将有效地减半。
请注意,在调试使用 XStreamingElement的程序时,显示对象的值会导致调用其 ToString 方法。 这会导致 XML 序列化。 如果流式处理元素查询的语义使得流元素只能流式传输一次,则可能会导致调试体验中出现不良行为。
构造函数
XStreamingElement(XName) | |
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。 |