次の方法で共有


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>

テキスト ファイルを処理する方法の 1 つは、yield return 構造を使用して、テキスト ファイルを一度に 1 行ずつストリーム出力する拡張メソッドを記述することです。 その後、テキスト ファイルをレイジー遅延方式で処理する 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 ツリーを作成できます。 このクラスを使用すると、 を使用して XML ツリーを作成するのとよく似た方法で XML ツリー XElementを作成できます。 ただし、根本的な違いがあります。 を使用して XML ツリーを作成するときに LINQ クエリを使用して XElementコンテンツを指定すると、クエリ変数は XML ツリーの作成時に反復処理され、クエリの結果が XML ツリーに追加されます。 これに対し、 を使用して XStreamingElementXML ツリーを作成すると、クエリ変数への参照が反復処理されずに XML ツリーに格納されます。 クエリは、シリアル化時にのみ反復処理されます。 これにより、より小さなメモリ占有領域を維持しながら、より大きな XML ツリーを作成できます。

テキスト ファイルなどの入力ソースからストリーミングする場合は、非常に大きなテキスト ファイルを読み取り、小さなメモリ占有領域を維持しながら非常に大きな XML ドキュメントを生成できます。

もう 1 つのシナリオは、メモリに読み込まれた大きな XML ツリーがあり、変換されたバージョンのドキュメントを作成することです。 を使用して新しいドキュメントを XElement作成すると、変換の完了時に 2 つの大きな XML ツリーがメモリに格納されます。 ただし、 を使用して新しい XML ツリーを XStreamingElement作成すると、ワーキング セットは実質的に半分に切り取られます。

を使用 XStreamingElementするプログラムをデバッグするときに、 オブジェクトの値を表示すると、その ToString メソッドが呼び出されることに注意してください。 これにより、XML がシリアル化されます。 ストリーミング要素クエリのセマンティクスがストリーミング要素を 1 回しかストリーミングできない場合は、デバッグ エクスペリエンスで望ましくない動作が発生する可能性があります。

コンストラクター

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 に書き込みます。

適用対象

こちらもご覧ください