Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Ibland måste du läsa godtyckligt stora XML-filer och skriva ditt program så att programmets minnesfotavtryck är förutsägbart. Om du försöker fylla i ett XML-träd med en stor XML-fil kommer minnesanvändningen att vara proportionell mot filens storlek, dvs. Därför bör du använda en strömningsteknik i stället.
Ett alternativ är att skriva ditt program med hjälp av XmlReader. Men du kanske vill använda LINQ för att köra frågor mot XML-trädet. I så fall kan du skriva en egen anpassad axelmetod. Mer information finns i Skriva en LINQ-till XML-axelmetod.
Om du vill skriva en egen axelmetod skriver du en liten metod som använder XmlReader för att läsa noder tills den når en av de noder som du är intresserad av. Metoden anropar ReadFromsedan , som läser från XmlReader och instansierar ett XML-fragment. Den ger sedan varje fragment till yield return metoden som räknar upp din anpassade axelmetod. Du kan sedan skriva LINQ-frågor på din anpassade axelmetod.
Direktuppspelningstekniker tillämpas bäst i situationer där du bara behöver bearbeta källdokumentet en gång och du kan bearbeta elementen i dokumentordning. Vissa vanliga frågeoperatorer, till exempel OrderBy, itererar sin källa, samlar in alla data, sorterar dem och ger slutligen det första objektet i sekvensen. Om du använder en frågeoperator som materialiserar källan innan du ger det första objektet behåller du inte ett litet minnesfotavtryck.
Exempel: Implementera och använda en anpassad axelmetod som strömmar XML-fragment från filen som anges av en URI
Ibland blir problemet bara lite mer intressant. I följande XML-dokument måste användaren av din anpassade axelmetod också känna till namnet på kunden som varje objekt tillhör.
<?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>
Den metod som används i det här exemplet är att även titta efter den här rubrikinformationen, spara rubrikinformationen och sedan skapa ett litet XML-träd som innehåller både rubrikinformationen och den information som du räknar upp. Axelmetoden ger sedan det här nya, lilla XML-trädet. Frågan har sedan åtkomst till rubrikinformationen samt information om detaljerna.
Den här metoden har ett litet minnesavtryck. Eftersom varje detaljerat XML-fragment returneras sparas inga referenser till det tidigare fragmentet och det är tillgängligt för skräpinsamling. Den här tekniken skapar många kortlivade objekt på högen.
I följande exempel visas hur du implementerar och använder en anpassad axelmetod som strömmar XML-fragment från filen som anges av URI:n. Den här anpassade axeln är skriven så att den förväntar sig ett dokument med Customerelementen , Nameoch Item och att dessa element ordnas som i dokumentet ovan Source.xml . Det är en förenklad implementering. En mer robust implementering skulle vara beredd att parsa ett ogiltigt dokument.
static IEnumerable<XElement> StreamCustomerItem(string uri)
{
    using XmlReader reader = XmlReader.Create(uri);
    reader.MoveToContent();
    // Parse the file, save header information when encountered, and yield the
    // Item XElement objects as they're created.
    // Loop through Customer elements
    do
    {
        if (reader.NodeType == XmlNodeType.Element && reader.Name == "Customer")
        {
            // Move to Name element
            XElement? name = null;
            do
            {
                if (reader.NodeType == XmlNodeType.Element && reader.Name == "Name")
                {
                    name = XNode.ReadFrom(reader) as XElement;
                    break;
                }
            }
            while (reader.Read());
            // Loop through Item elements
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                if (reader.NodeType == XmlNodeType.Element && reader.Name == "Item")
                {
                    if (XNode.ReadFrom(reader) is XElement item && name != null)
                    {
                        XElement tempRoot = new XElement("Root",
                            new XElement(name),
                            item
                        );
                        yield return item;
                    }
                }
                else if (!reader.Read())
                    break;
            }
        }
    }
    while (reader.Read());
}
static void Main(string[] args)
{
    XElement xmlTree = new XElement("Root",
        from el in StreamCustomerItem("Source.xml")
        where (int)el.Element("Key") >= 3 && (int)el.Element("Key") <= 7
        select new XElement("Item",
            new XElement("Customer", (string)el.Parent.Element("Name")),
            new XElement(el.Element("Key"))
        )
    );
    Console.WriteLine(xmlTree);
}
Imports System.Xml
Module Module1
    Public Iterator Function StreamCustomerItem(uri As String) As IEnumerable(Of XElement)
        Using reader As XmlReader = XmlReader.Create(uri)
            reader.MoveToContent()
            ' Parse the file, save header information when encountered, And yield the
            ' Item XElement objects as they're created.
            ' Loop through Customer elements
            Do
                If reader.NodeType = XmlNodeType.Element And reader.Name = "Customer" Then
                    ' Move to Name element
                    Dim name As XElement = Nothing
                    Do
                        If reader.NodeType = XmlNodeType.Element And reader.Name = "Name" Then
                            name = TryCast(XNode.ReadFrom(reader), XElement)
                            Exit Do
                        End If
                    Loop While reader.Read()
                    ' Loop through Item elements
                    While reader.NodeType <> XmlNodeType.EndElement
                        If reader.NodeType = XmlNodeType.Element And reader.Name = "Item" Then
                            Dim item = TryCast(XNode.ReadFrom(reader), XElement)
                            If name IsNot Nothing AndAlso item IsNot Nothing Then
                                Dim tempRoot = <Root>
                                                   <Name><%= name.Value %></Name>
                                                   <%= item %>
                                               </Root>
                                Yield item
                            End If
                        ElseIf Not reader.Read() Then
                            Exit While
                        End If
                    End While
                End If
            Loop While reader.Read()
        End Using
    End Function
    Sub Main()
        Dim xmlTree = <Root>
                          <%=
                              From el In StreamCustomerItem("Source.xml")
                              Let itemKey = CInt(el.<Key>.Value)
                              Where itemKey >= 3 AndAlso itemKey <= 7
                              Select <Item>
                                         <Customer><%= el.Parent.<Name>.Value %></Customer>
                                         <%= el.<Key> %>
                                     </Item>
                          %>
                      </Root>
        Console.WriteLine(xmlTree)
    End Sub
End Module
Den här koden genererar följande utdata:
<Root>
  <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>
</Root>