Xslt 在大量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是否是一个好的解决方案:

我有大小约为50MB到最大2GB的XML文件,其中包含数以万计的
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