2

基本的に次のような XPath のリストを含むファイルがあります。

/Options/File[1]/Settings[1]/Type[1]
/Options/File[1]/Settings[1]/Path[1]
/Options/File[1]/Settings[2]/Type[1]
/Options/File[1]/Settings[2]/Path[1]
/Options/File[2]/Settings[1]/Type[1]
/Options/File[2]/Settings[1]/Path[1]

適度なサイズの XML ファイル (~3-5MB) で、これらの XPath からポイントされた要素から値を取得する必要があります。XPathSelectElement を使用するとうまく機能しますが、非常に遅くなります。Linq to XML で同じことを行う、または手動で XML をトラバースするより迅速な方法はありますか?

関連する質問では、XPath のインデックス値と XElement から返される要素の順序は同じであることが保証されていますか? たとえば、これらは同じものを返します:

xdoc.XPathSelectElement("/Options/File[1]/Settings[2]);

xdoc.root.Elements("File").ElementAt(0).Elements("Settings").ElementAt(1);
4

3 に答える 3

2

私はちょうどあなたと同様の問題を抱えていました.インデックス付きのXPath式の束を使用して、中サイズのxmlファイル(3 MB)でいくつかのノードを選択すると、ひどいパフォーマンスが発生しました.

しかし、あなたのソリューションとは反対に、XPath 式のすべての部分にインデックスがありませんでした。そこで、XPath() を使用して LINQ to XML を捨てようとしましXElement.XPathSelectElementたが、代わりに anXPathNavigatorを作成してXPathDocumentを呼び出して使用しましたCreateNavigator()。使っていたナビについてSelectSingleNode

それを使用XElement.XPathSelectElementすると、すべての選択を行うのに 137.3 秒かかりました (ちなみに、プログラムの残りの部分では約 3 秒しかかかりませんでした)。

選択を使用XPathNavigator.SelectSingleNodeすると、合計で 1.2 秒の int が必要になります...これはほぼ 115 の係数です

したがって、より高速な XPath クエリが必要で、自分でクエリを解析したくない場合は、可能であれば LINQ to XML を使用しないでください。これは、パフォーマンスに関してひどく実装されているようです。

于 2012-09-14T09:39:52.047 に答える
2

インデックス付き XPath (n 番目の子) は、必要な子まですべての子をトラバースする必要があるため、通常は低速です。確認するには - 比較的大きなファイルの場合、最初の子と最後の子を選択して違いを比較してみてください (それぞれについて ~1000 回繰り返し、StopWatch を使用して測定します)。

あなたが示したようなXPathのすべてであれば、繰り返しながら子ノードをキャッシュすることによって手動で選択を行うことができるかもしれません。

XML では要素の順序が重要であるため、通常の XML API は常に要素の順序を維持します。属性の順序は XML にとって重要ではないことに注意してください。そのため、属性の順序は、クエリ間で (可能性は低いですが、理論的には可能です)、異なる API 間で同じではない可能性があります。

于 2012-04-03T21:53:09.567 に答える
1

これが私が行くつもりだと思います。アレクセイの提案など、さらにパフォーマンスが向上する可能性があると確信していますが、これは私の限られたテストではすでに少なくとも 10 倍高速です。

    private XElement GetElementFromXPath(XDocument xDoc, string xPath)
    {
        string[] nodes = xPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
        XContainer xe = xDoc.Root;
        for (int i = 1; i < nodes.Length; i++)
        {
            string[] chunks = nodes[i].Split(new char[] { '[', ']' });

            int index = 0;
            if (Int32.TryParse(chunks[1], out index))
                xe = xe.Elements(chunks[0]).ElementAt(index - 1);
        }
        return (XElement)xe;
    }

これは、ルート以外のすべての要素が XPath にインデックス番号とともにリストされていることを前提としています (これは私のシナリオに当てはまります)。

于 2012-04-04T16:43:38.850 に答える