提供されたxmlドキュメントに対してXPath式の評価をストリーミングするための本番環境に対応したライブラリはありますか?私の調査によると、既存のソリューションのほとんどは、xpath式を評価する前にDOMツリー全体をメモリにロードします。
7 に答える
XSLT 3.0 は処理のストリーミング モードを提供し、これは XSLT 3.0 W3C 仕様が W3C 勧告になる標準になります。
この回答を書いている時点 (2011 年 5 月) で、Saxon はXSLT 3.0 ストリーミングのサポートを提供しています。
いくつかのオプションがあります:
DataDirect Technologiesは、可能であればプロジェクションとストリーミングを使用する XQuery 実装を販売しています。複数ギガバイトの範囲のファイルを処理できます。たとえば、使用可能なメモリよりも大きくなります。これはスレッドセーフなライブラリであるため、統合が容易です。Java のみ。
Saxonはオープン ソース バージョンであり、手頃な価格のより高価なバージョンで、一部のコンテキストではストリーミングを行います。Java ですが、.net ポートもあります。
MarkLogicとeXistは XML データベースであり、XML が読み込まれると、かなりインテリジェントな方法で XPath を処理します。
私は実際の経験はありませんが、QuiXProc( http://code.google.com/p/quixproc/ )に言及する価値があると思いました。これはXProcへのストリーミングアプローチであり、とりわけXPathのストリーミングサポートを提供するライブラリを使用します。
Joostを試してみてください。
FWIW、私は非常に大きな (> 3GB) ファイルに対して Nux ストリーミング フィルター xpath クエリを使用しましたが、どちらも問題なく動作し、メモリをほとんど使用しませんでした。私の使用例は少し異なります (検証中心ではありません) が、Nux で試してみることを強くお勧めします。
カスタムコードにしようと思います。.NET ライブラリは、xml ドキュメントのいくつかのパスを読みたいだけの場合、ターゲットにかなり近づけます。
これまでに目にしたすべてのソリューションは XPath サブセットのみを尊重しているため、これもこの種のソリューションです。ただし、サブセットは非常に小さいです。:)
この C# コードは xml ファイルを読み取り、明示的なパスを指定してノードをカウントします。xr["attrName"]
構文を使用して、属性を簡単に操作することもできます。
int c = 0;
var r = new System.IO.StreamReader(asArgs[1]);
var se = new System.Xml.XmlReaderSettings();
var xr = System.Xml.XmlReader.Create(r, se);
var lstPath = new System.Collections.Generic.List<String>();
var sbPath = new System.Text.StringBuilder();
while (xr.Read()) {
//Console.WriteLine("type " + xr.NodeType);
if (xr.NodeType == System.Xml.XmlNodeType.Element) {
lstPath.Add(xr.Name);
}
// It takes some time. If 1 unit is time needed for parsing the file,
// then this takes about 1.0.
sbPath.Clear();
foreach(object n in lstPath) {
sbPath.Append('/');
sbPath.Append(n);
}
// This takes about 0.6 time units.
string sPath = sbPath.ToString();
if (xr.NodeType == System.Xml.XmlNodeType.EndElement
|| xr.IsEmptyElement) {
if (xr.Name == "someElement" && lstPath[0] == "main")
c++;
// And test simple XPath explicitly:
// if (sPath == "/main/someElement")
}
if (xr.NodeType == System.Xml.XmlNodeType.EndElement
|| xr.IsEmptyElement) {
lstPath.RemoveAt(lstPath.Count - 1);
}
}
xr.Close();