Megosztás a következőn keresztül:


XML-töredékek streamelése XmlReaderből (LINQ-ból XML-be)

Ha nagy XML-fájlokat kell feldolgoznia, előfordulhat, hogy nem lehet betölteni a teljes XML-fát a memóriába. Ez a cikk bemutatja, hogyan streamelheti a töredékeket c XmlReader # és Visual Basic nyelven.

Az objektumok olvasásának XmlReader XElement egyik leghatékonyabb módja a saját egyéni tengelymetódus írása. A tengelymetódusok általában olyan gyűjteményt adnak vissza, mint IEnumerable<T> XElementpéldául a jelen cikkben szereplő példában. Az egyéni tengely metódusában, miután létrehozta az XML-töredéket a ReadFrom metódus meghívásával, adja vissza a gyűjteményt a következővel yield return: . Ez késleltetett végrehajtási szemantikát biztosít az egyéni tengely metódusához.

Amikor XML-fát hoz létre egy XmlReader objektumból, az XmlReader elemnek egy elemen kell lennie. A ReadFrom metódus csak akkor tér vissza, ha be nem olvassa az elem záró címkéjét.

Ha részleges fát szeretne létrehozni, létrehozhat egy XmlReaderpéldányt, elhelyezheti az olvasót azon a csomóponton, amelyet fává szeretne alakítani XElement , majd létrehozhatja az XElement objektumot.

Az XML-töredékek élőfej-információhoz való hozzáféréssel való streamelése című cikk egy összetettebb dokumentum streamelésére vonatkozó információkat tartalmaz.

A nagy XML-dokumentumok streamelési átalakításának végrehajtása című cikk egy példát tartalmaz arra, hogy a LINQ-t XML-ként használva rendkívül nagy XML-dokumentumokat alakíthat át, miközben kis memóriaigényt tart fenn.

Példa: Egyéni tengelymetódus létrehozása

Ez a példa létrehoz egy egyéni tengelymetódust. A lekérdezést LINQ-lekérdezéssel végezheti el. Az egyéni tengelymetódus StreamRootChildDoc képes olvasni egy ismétlődő Child elemet tartalmazó dokumentumot.

using System.Xml;
using System.Xml.Linq;

static IEnumerable<XElement> StreamRootChildDoc(StringReader stringReader)
{
    using XmlReader reader = XmlReader.Create(stringReader);

    reader.MoveToContent();

    // Parse the file and display each of the nodes.
    while (true)
    {
        // If the current node is an element and named "Child"
        if (reader.NodeType == XmlNodeType.Element && reader.Name == "Child")
        {
            // Get the current node and advance the reader to the next
            if (XNode.ReadFrom(reader) is XElement el)
                yield return el;

        }
        else if (!reader.Read())
            break;
    }
}

string markup = """
                <Root>
                  <Child Key="01">
                    <GrandChild>aaa</GrandChild>
                  </Child>
                  <Child Key="02">
                    <GrandChild>bbb</GrandChild>
                  </Child>
                  <Child Key="03">
                    <GrandChild>ccc</GrandChild>
                  </Child>
                </Root>
                """;

IEnumerable<string> grandChildData =
    from el in StreamRootChildDoc(new StringReader(markup))
    where (int)el.Attribute("Key") > 1
    select (string)el.Element("GrandChild");

foreach (string str in grandChildData)
    Console.WriteLine(str);
Imports System.Xml

Module Module1

    Public Iterator Function StreamRootChildDoc(stringReader As IO.StringReader) As IEnumerable(Of XElement)
        Using reader As XmlReader = XmlReader.Create(stringReader)
            reader.MoveToContent()

            ' Parse the file and display each of the nodes.
            While True

                ' If the current node is an element and named "Child"
                If reader.NodeType = XmlNodeType.Element And reader.Name = "Child" Then

                    ' Get the current node and advance the reader to the next
                    Dim el As XElement = TryCast(XNode.ReadFrom(reader), XElement)

                    If (el IsNot Nothing) Then
                        Yield el
                    End If

                ElseIf Not reader.Read() Then
                    Exit While
                End If

            End While
        End Using
    End Function

    Sub Main()

        Dim markup = "<Root>
                       <Child Key=""01"">
                         <GrandChild>aaa</GrandChild>
                       </Child>
                       <Child Key=""02"">
                         <GrandChild>bbb</GrandChild>
                       </Child>
                       <Child Key=""03"">
                         <GrandChild>ccc</GrandChild>
                       </Child>
                     </Root>"

        Dim grandChildData =
             From el In StreamRootChildDoc(New IO.StringReader(markup))
             Where CInt(el.@Key) > 1
             Select el.<GrandChild>.Value

        For Each s In grandChildData
            Console.WriteLine(s)
        Next

    End Sub
End Module

Ez a példa a következő kimenetet hozza létre:

bbb
ccc

Az ebben a példában használt technika még több millió elem esetében is kis memóriaigényt Child tart fenn.

Lásd még