XStreamingElement Класс
Определение
Важно!
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Представляет элементы в дереве XML, поддерживающем отложенный потоковый выход.
public ref class XStreamingElement
public class XStreamingElement
type XStreamingElement = class
Public Class XStreamingElement
- Наследование
-
XStreamingElement
Примеры
В следующем примере сначала создается исходное XML-дерево. Затем он создает преобразование исходного XML-дерева с помощью XElement. Это преобразование создает новое дерево в памяти. Затем он создает преобразование исходного XML-дерева с помощью 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 для потоковой передачи выходных данных, можно создать преобразование из текстового файла в 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-дерева очень похоже на создание XML-дерева с помощью XElement. Тем не менее, существует фундаментальное различие. При использовании запроса LINQ для указания содержимого при создании XML-дерева с помощью XElementпеременной запроса выполняется итерация во время создания дерева XML, а результаты запроса добавляются в XML-дерево. Напротив, при создании XML-дерева с помощью XStreamingElementссылки на переменную запроса сохраняется в XML-дереве без итерации. Запросы итерируются только при сериализации. Это позволяет создавать большие XML-деревья при сохранении меньшего объема памяти.
При потоковой передаче из источника входных данных, например текстового файла, можно прочитать очень большой текстовый файл и создать очень большой XML-документ, сохраняя небольшой объем памяти.
Другой сценарий заключается в том, что у вас есть большое XML-дерево, загруженное в память, и вы хотите создать преобразованную версию документа. Если вы создаете новый документ, XElementто после завершения преобразования у вас будет два больших XML-дерева в памяти. Однако если вы создаете новое XML-дерево с помощью XStreamingElement, рабочий набор будет эффективно вырезан в два раза.
Обратите внимание, что при отладке программы, которая использует XStreamingElement, отображение значения объекта приводит к вызову метода ToString . Это приводит к сериализации XML. Если семантика запроса элемента потоковой передачи такова, что потоковый элемент можно передавать только один раз, это может привести к нежелательному поведению в интерфейсе отладки.
Конструкторы
XStreamingElement(XName) |
Инициализирует новый экземпляр класса XElement из указанного потока 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. |