16

XDocumentを使用して新しい を作成する場合XDocument.Load、XML ファイルを開いてローカル コピーを保持しますか?それともハード ドライブからドキュメントを継続的に読み取りますか? 継続的に読み取る場合、XML を解析するより高速な方法はありますか?

XDocument x = XDocument.Load("file.xml");
4

3 に答える 3

12

考慮すべき測定値がいくつかあります。

  1. 直線移動速度 (読み取り/ロードなど)
  2. オンデマンドのクエリ速度

直接の質問に答えるには: XDocumentを使用して、XmlReader各要素を読み取り、対応するインスタンスを作成することにより、ドキュメントをメモリに読み込みXElementます (以下のコードを参照)。そのため、非常に高速である必要があります (ほとんどの目的で十分に高速です) が、大きなドキュメントを解析するときに大量のメモリを消費する可能性があります。

rawXmlReaderは、ドキュメントをメモリに保持せずに実行できるものに制限されている場合に、トラバーサルに最適な選択肢です。重要な構造が作成されたり、他のノードに関連して解決されたりしないため (親ノードと子ノードのリンクなど)、他の方法よりも優れています。ただし、オンデマンドのクエリ機能はほとんど存在しません。各ノードで見つかった値に反応することはできますが、ドキュメント全体をクエリすることはできません。ドキュメントをもう一度見る必要がある場合は、全体をもう一度トラバースする必要があります。

比較すると、XDocumentは新しいオブジェクトをインスタンス化し、基本的な構造タスクを実行するため、トラバースに時間がかかります。また、ソースのサイズに比例してメモリを消費します。これらのトレードオフと引き換えに、優れたクエリ機能が得られます。

Jon Skeet が言及し、ここに示されているように、アプローチを組み合わせることが可能かもしれません: Streaming Into LINQ to XML Using C# Custom Iterators and XmlReader

XDocument Load() のソース

public static XDocument Load(Stream stream, LoadOptions options)
{
    XmlReaderSettings xmlReaderSettings = XNode.GetXmlReaderSettings(options);
    XDocument result;
    using (XmlReader xmlReader = XmlReader.Create(stream, xmlReaderSettings))
    {
        result = XDocument.Load(xmlReader, options);
    }
    return result;
}

// which calls...

public static XDocument Load(XmlReader reader, LoadOptions options)
{
    if (reader == null)
    {
        throw new ArgumentNullException("reader");
    }
    if (reader.ReadState == ReadState.Initial)
    {
        reader.Read();
    }
    XDocument xDocument = new XDocument();
    if ((options & LoadOptions.SetBaseUri) != LoadOptions.None)
    {
        string baseURI = reader.BaseURI;
        if (baseURI != null && baseURI.Length != 0)
        {
            xDocument.SetBaseUri(baseURI);
        }
    }
    if ((options & LoadOptions.SetLineInfo) != LoadOptions.None)
    {
        IXmlLineInfo xmlLineInfo = reader as IXmlLineInfo;
        if (xmlLineInfo != null && xmlLineInfo.HasLineInfo())
        {
            xDocument.SetLineInfo(xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
        }
    }
    if (reader.NodeType == XmlNodeType.XmlDeclaration)
    {
        xDocument.Declaration = new XDeclaration(reader);
    }
    xDocument.ReadContentFrom(reader, options);
    if (!reader.EOF)
    {
        throw new InvalidOperationException(Res.GetString("InvalidOperation_ExpectedEndOfFile"));
    }
    if (xDocument.Root == null)
    {
        throw new InvalidOperationException(Res.GetString("InvalidOperation_MissingRoot"));
    }
    return xDocument;
}

// which calls...

internal void ReadContentFrom(XmlReader r, LoadOptions o)
{
    if ((o & (LoadOptions.SetBaseUri | LoadOptions.SetLineInfo)) == LoadOptions.None)
    {
        this.ReadContentFrom(r);
        return;
    }
    if (r.ReadState != ReadState.Interactive)
    {
        throw new InvalidOperationException(Res.GetString("InvalidOperation_ExpectedInteractive"));
    }
    XContainer xContainer = this;
    XNode xNode = null;
    NamespaceCache namespaceCache = default(NamespaceCache);
    NamespaceCache namespaceCache2 = default(NamespaceCache);
    string text = ((o & LoadOptions.SetBaseUri) != LoadOptions.None) ? r.BaseURI : null;
    IXmlLineInfo xmlLineInfo = ((o & LoadOptions.SetLineInfo) != LoadOptions.None) ? (r as IXmlLineInfo) : null;
    while (true)
    {
        string baseURI = r.BaseURI;
        switch (r.NodeType)
        {
        case XmlNodeType.Element:
        {
            XElement xElement = new XElement(namespaceCache.Get(r.NamespaceURI).GetName(r.LocalName));
            if (text != null && text != baseURI)
            {
                xElement.SetBaseUri(baseURI);
            }
            if (xmlLineInfo != null && xmlLineInfo.HasLineInfo())
            {
                xElement.SetLineInfo(xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
            }
            if (r.MoveToFirstAttribute())
            {
                do
                {
                    XAttribute xAttribute = new XAttribute(namespaceCache2.Get((r.Prefix.Length == 0) ? string.Empty : r.NamespaceURI).GetName(r.LocalName), r.Value);
                    if (xmlLineInfo != null && xmlLineInfo.HasLineInfo())
                    {
                        xAttribute.SetLineInfo(xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
                    }
                    xElement.AppendAttributeSkipNotify(xAttribute);
                }
                while (r.MoveToNextAttribute());
                r.MoveToElement();
            }
            xContainer.AddNodeSkipNotify(xElement);
            if (r.IsEmptyElement)
            {
                goto IL_30A;
            }
            xContainer = xElement;
            if (text != null)
            {
                text = baseURI;
                goto IL_30A;
            }
            goto IL_30A;
        }
        case XmlNodeType.Text:
        case XmlNodeType.Whitespace:
        case XmlNodeType.SignificantWhitespace:
            if ((text != null && text != baseURI) || (xmlLineInfo != null && xmlLineInfo.HasLineInfo()))
            {
                xNode = new XText(r.Value);
                goto IL_30A;
            }
            xContainer.AddStringSkipNotify(r.Value);
            goto IL_30A;
        case XmlNodeType.CDATA:
            xNode = new XCData(r.Value);
            goto IL_30A;
        case XmlNodeType.EntityReference:
            if (!r.CanResolveEntity)
            {
                goto Block_25;
            }
            r.ResolveEntity();
            goto IL_30A;
        case XmlNodeType.ProcessingInstruction:
            xNode = new XProcessingInstruction(r.Name, r.Value);
            goto IL_30A;
        case XmlNodeType.Comment:
            xNode = new XComment(r.Value);
            goto IL_30A;
        case XmlNodeType.DocumentType:
            xNode = new XDocumentType(r.LocalName, r.GetAttribute("PUBLIC"), r.GetAttribute("SYSTEM"), r.Value, r.DtdInfo);
            goto IL_30A;
        case XmlNodeType.EndElement:
        {
            if (xContainer.content == null)
            {
                xContainer.content = string.Empty;
            }
            XElement xElement2 = xContainer as XElement;
            if (xElement2 != null && xmlLineInfo != null && xmlLineInfo.HasLineInfo())
            {
                xElement2.SetEndElementLineInfo(xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
            }
            if (xContainer == this)
            {
                return;
            }
            if (text != null && xContainer.HasBaseUri)
            {
                text = xContainer.parent.BaseUri;
            }
            xContainer = xContainer.parent;
            goto IL_30A;
        }
        case XmlNodeType.EndEntity:
            goto IL_30A;
        }
        break;
        IL_30A:
        if (xNode != null)
        {
            if (text != null && text != baseURI)
            {
                xNode.SetBaseUri(baseURI);
            }
            if (xmlLineInfo != null && xmlLineInfo.HasLineInfo())
            {
                xNode.SetLineInfo(xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
            }
            xContainer.AddNodeSkipNotify(xNode);
            xNode = null;
        }
        if (!r.Read())
        {
            return;
        }
    }
    goto IL_2E1;
    Block_25:
    throw new InvalidOperationException(Res.GetString("InvalidOperation_UnresolvedEntityReference"));
    IL_2E1:
    throw new InvalidOperationException(Res.GetString("InvalidOperation_UnexpectedNodeType", new object[]
    {
        r.NodeType
    }));
}
于 2012-12-22T07:19:32.917 に答える
7

呼び出し時に着信ストリームを解析し (ファイルからのものか文字列かは関係ありません) Load()、ドキュメントのローカル インスタンスをメモリに保持します。ソースは何でもかまいません (NetworkStream、DataReader、ユーザーが入力した文字列など) ため、データの状態 (ストリームが閉じられているなど) がわからないため、戻ってデータを再度読み取ることはできませんでした。 )。

一方、本当に速度が必要な場合は、最初にドキュメントを解析してからメモリに保持する必要があるため、XDocument は高速ではありません (操作は簡単ですが)。System.Xml.XmlReaderを使用したアプローチを使用して非常に大きなドキュメントを操作している場合、ドキュメントをストリームとして読み取ることができ、現在の要素以外は何も保持する必要がないため、通常ははるかに高速です。このベンチマークは、これに関する興味深い数値を示しています。

于 2012-12-22T07:23:52.907 に答える
1

継続的に読み込んでいるとは思いません。このメソッドの優れた点 は、XML を XML ツリーに読み込むためXDocument.Loadに使用することです。XmlReaderそして今、ツリーとしてメモリに保存されている可能性が最も高いツリーを作成したので、ドキュメントを常に読み取ることはありません。それはツリーを操作し、ツリーであるため、すべての読み取りと変更がはるかに高速に行われます。実装していませんIDisposableが、自動的に破棄されます。

于 2012-12-22T07:21:31.090 に答える