Xslt 在大量XML文本节点中执行文本搜索,并确定模式是否只出现一次
我有大小约为50MB到最大2GB的XML文件,其中包含数以万计的Xslt 在大量XML文本节点中执行文本搜索,并确定模式是否只出现一次,xslt,search,xslt-1.0,Xslt,Search,Xslt 1.0,我有大小约为50MB到最大2GB的XML文件,其中包含数以万计的mycomment元素,这些元素只有一个文本节点。到mycomment节点的路径不是固定的,也没有定义,因此//mycomment是获取所有节点的唯一方法。mycomment/text()的长度约为50到500个字符。我需要在所有mycommenttext节点中搜索一个模式,以便对文件进行分类。如果在其中一个文本节点中找到模式“mypattern1234”,则变量hit设置为1,否则为空。这样计算hit是否是一个好的解决方案:
mycomment
元素,这些元素只有一个文本节点。到mycomment
节点的路径不是固定的,也没有定义,因此//mycomment
是获取所有节点的唯一方法。mycomment/text()
的长度约为50到500个字符。我需要在所有mycomment
text节点中搜索一个模式,以便对文件进行分类。如果在其中一个文本节点中找到模式“mypattern1234”
,则变量hit
设置为1
,否则为空。这样计算hit
是否是一个好的解决方案:
<xsl:variable name="hit">
<xsl:if test="//mycomment[contains(text(),' mypattern1234 ')]">1</xsl:if>
</xsl:variable>
1.
:-)我正在使用XSLT v1.0。谢谢。目前尚不清楚
mycomment
元素是否可以包含混合内容或文本节点,并夹杂注释或处理说明。通常,如果您希望mycomment
元素只包含文本内容,我会检查mycomment[contains(,'foo')]
,不需要选择下到文本节点的子元素。如果您想这样做,那么我将使用mycomment/text()[contains(,'foo')]
,检查text()
作为contains
的参数将选择第一个文本子节点,因此在例如foo mypattern1234
中不会检测到文本
至于效率,这将在很大程度上取决于所使用的XSLT处理器 除非切换到流式XSLT 3.0处理器(如Saxon EE),否则您将无法处理2GB的输入文档 如果您使用的是流式处理器,那么我建议您也这样做
<xsl:source-document href="input.xml" streamable="yes">
<xsl:if test="//text()[parent::comment][contains(.,' mypattern1234 ')]>1</xsl:if>
</xsl:source-document>
除了XML技术之外,ripgrep
使搜索速度提高了几个数量级:
#!/bin/zsh
DATABASE="$1"
SEARCH_PATTERN="$2"
if [ "${#SEARCH_PATTERN}" != 0 ] && [ "${#DATABASE}" != 0 ] ; then
RAWHIT=`rg -C 5 "$SEARCH_PATTERN" "$DATABASE"`
if [ "${#RAWHIT}" != 0 ] ; then
HIT=`echo $RAWHIT | rg -c -U "<comment>.*$SEARCH_PATTERN.*</comment>"`
if [ "${#HIT}" != 0 ] ; then
echo "Pattern found"
else
echo "Pattern not found"
fi
else
echo "Pattern not found"
fi
else
echo "Missing Search Pattern or Database"
fi
数据库下载:比较各种技术——XPath与XQuery或XSLT与ripgrep:
- 解决方案1(M.H.):
//注释[包含(,'searchpattern')]
- 解决方案2(M.S.):
//注释[包含(text(),'searchpattern')]
- 解决方案3(M.K.):
//text()[parent:comment][contains(,'searchpattern')]
平台:
MacBook,i5,macOS v10.15.4,16GB内存
XML数据库:
大小:2.46GB
注释元素节点数(在其中搜索模式的单个文本节点)=5914102
其他元素节点数(非注释)=11829597
XQuery v3.1,BaseX v9.3.2
XSLT v3.0,SaxOne v9-9-1-7J
结果
好例子:至少有一条带有搜索模式的注释
最快(16,13秒):
XSLT v3.0上的解决方案3(M.K.),SaxOne v9-9-1-7J
最慢(30,09秒):
XQuery v3.1、BaseX v9.3.2上的解决方案3(M.K.)
坏情况:没有搜索模式的注释
最快(30,28秒):
XQuery v3.1、BaseX v9.3.2上的解决方案1(M.H.)
最慢(47,26秒):
XQuery v3.1、BaseX v9.3.2上的解决方案3(M.K.)
脚本和XML数据库
使用非XML技术的解决方案
裂谷(rg)
>time rg-c5'Foo4711'db50c100000p.xml | rg-C-U'(?s:[^我已经更新了我的问题。mycomment
元素只有文本节点,没有混合内容。好消息是:检查[…]将选择第一个文本子节点(谢谢!)。然后我将尝试//mycomment[contains(,'foo')]
以及M.K.在上面的回答中的建议。我对这种节点选择和文本搜索感到不舒服,我想知道处理器是否会在测试表达式第一次被评估为无空时停止。但我假设它在找到第一个mycomment[包含(,'foo')时停止
?!?一个好的处理器在找到匹配项后会停止搜索树,但大部分工作不是搜索树,而是通过解析XML来构建树。只有当找到匹配项时,流处理器才会停止解析操作。我们有.NET XSL引擎和FileStream
作为XslCom的输入PilledTransform
,除此之外,它只支持XSLT v1.0:…-(我猜它是一个“流处理器”。因此,原则上,文件大小不是问题,而是随着文件大小的增加,节点数量会增加。我最需要知道的是:“一旦找到匹配项,应立即停止对源文档的扫描”。我假设这对.NET XSLT引擎也是有效的。稍后我将编写一个简短的摘要,并比较建议的XSL查询(我的、你的和下面M.H.的查询)。谢谢您的回答。不,是的,.NET引擎实现了1999年的XSLT 1.0标准,它没有在这20年中添加到XSLT中的任何优点。它不做流式处理;它需要在内存中构建整个文档。我明白了。NET XSL引擎不是您所说的流式处理器,即使有“某种类型”的处理通过将文件从磁盘读取到内存中来实现流式处理。为什么您不断发布答案、删除答案,然后再次发布?
> time ./run.sh DB50C1000000P.xml Foo4711
Pattern found
./run.sh DB50C1000000P.xml Foo4711 0,23s user 0,58s system 98% cpu 0,828 total
> time ./run.sh DB50C1000000P.xml Foo4711a
Pattern not found
./run.sh DB50C1000000P.xml Foo4711a 0,23s user 0,59s system 98% cpu 0,829 total
> time java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX -bsolution=1 -bdatabase=DB50C1000000P -bpattern=Foo4711 run.xqy
Solution 1: Pattern found
java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX run.xq 28,96s user 2,82s system 188% cpu 16,826 total
> time java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX -bsolution=1 -bdatabase=DB50C1000000P -bpattern=Foo4711a run.xqy
Solution 1: Pattern not found
java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX run.xq 42,62s user 4,05s system 140% cpu 33,233 total
> time java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX -bsolution=2 -bdatabase=DB50C1000000P -bpattern=Foo4711 run.xqy
Solution 2: Pattern found
java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX run.xq 29,25s user 2,70s system 196% cpu 16,271 total
> time java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX -bsolution=2 -bdatabase=DB50C1000000P -bpattern=Foo4711a run.xqy
Solution 2: Pattern not found
java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX run.xq 47,45s user 4,84s system 143% cpu 36,341 total
> time java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX -bsolution=3 -bdatabase=DB50C1000000P -bpattern=Foo4711 run.xqy
Solution 3: Pattern found
java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX run.xq 30,09s user 2,70s system 195% cpu 16,773 total
> time java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX -bsolution=3 -bdatabase=DB50C1000000P -bpattern=Foo4711a run.xqy
Solution 3: Pattern not found
java -Xmx10g -cp /Users/ms/Projekte/basex/BaseX.jar org.basex.BaseX run.xq 45,42s user 4,32s system 148% cpu 33,413 total
> time java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xml -xsl:run.xsl -o:out.xml database=DB50C1000000P.xml pattern=Foo4711 solution=1
Solution 1: Pattern found
java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xm 27,43s user 5,88s system 134% cpu 24,719 total
> time java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xml -xsl:run.xsl -o:out.xml database=DB50C1000000P.xml pattern=Foo4711a solution=1
Solution 1: Pattern not found
java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xm 30,28s user 9,06s system 131% cpu 29,964 total
> time java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xml -xsl:run.xsl -o:out.xml database=DB50C1000000P.xml pattern=Foo4711 solution=2
Solution 2: Pattern found
java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xm 27,55s user 4,44s system 158% cpu 20,202 total
> time java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xml -xsl:run.xsl -o:out.xml database=DB50C1000000P.xml pattern=Foo4711a solution=2
Solution 2: Pattern not found
java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xm 34,47s user 5,24s system 177% cpu 22,324 total
> time java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xml -xsl:run.xsl -o:out.xml database=DB50C1000000P.xml pattern=Foo4711 solution=3
Solution 3: Pattern found
java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xm 16,13s user 0,62s system 130% cpu 12,816 total
> time java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xml -xsl:run.xsl -o:out.xml database=DB50C1000000P.xml pattern=Foo4711a solution=3
Solution 3: Pattern not found
java -Xmx10g -jar /Users/ms/Projekte/SaxonEE9-9-1-7J/saxon9ee.jar -s:empty.xm 47,26s user 1,56s system 110% cpu 44,247 total
> time rg -C 5 'Foo4711' DB50C1000000P.xml | rg -c -U '<comment>(?s:[^<]*)Foo4711(?s:[^<]*)</comment>'
4
rg -C 5 'Foo4711' DB50C1000000P.xml 0,27s user 0,72s system 90% cpu 1,094 total
rg -c -U '<comment>(?s:[^<]*)Foo4711(?s:[^<]*)</comment>' 0,01s user 0,01s system 1% cpu 1,092 total
> time rg -C 5 'Foo4711a' DB50C1000000P.xml | rg -c -U '<comment>(?s:[^<]*)Foo4711a(?s:[^<]*)</comment>'
rg -C 5 'Foo4711a' DB50C1000000P.xml 0,24s user 0,66s system 93% cpu 0,957 total
rg -c -U '<comment>(?s:[^<]*)Foo4711a(?s:[^<]*)</comment>' 0,01s user 0,01s system 1% cpu 0,957 total