xml – XPath拉多个匹配

前端之家收集整理的这篇文章主要介绍了xml – XPath拉多个匹配前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
(BaseX)错误

我在BaseX中的一个大型数据集上运行查询,但是一个XQuery正在崩溃我的程序,出现错误[XPTY0004]项目预期,序列找到:(属性begin {“6”},…)..

在我的查询中,我试图通过比较begin(XML中存在的一个属性)和number()来确保一个元素来到另一个元素之前.但是每当我在我的数据集上尝试最基本的XQueries(返回匹配节点)(例如,使用this online tool),我会收到类似于之前的错误

[Error] SaxonCE.XSLT20Processor 14:08:39.692 SEVERE: XPathException in
invokeTransform: A sequence of more than one item is not allowed as
the first argument of number() (“6”,“10”)

所以我猜测节点的兄弟姐妹会发生什么事情,即这些节点有不止一个,而且还不清楚应该比较哪个节点.示例如下.

为什么订单很重要?

XPath用于树形库的查询引擎:语言注释语料库.在某些情况下,我们希望节点按顺序进行匹配,有时并不重要.作为一个简单的例子:有时候,我们想要匹配一些具体的东西,如有关的人,订单文章,形容词,名词重要.在其他查询中,这并不重要,我们也想匹配短语,例如可用的时间,文章,名词的顺序可以是任何顺序.

换句话说,在第一种情况下,要尊重元素的顺序,在第二种情况下,它不应该遵循.这是一个可能的XPath表示,这种结构包含一个文章,一个形容词和一个名词.

node[@cat="np" and node[@pt="art"] and node[@pt="adj"] and node[@pt="n"]]

默认情况下,XPath不关心这些元素的顺序,并且进行贪心搜索,即它也将匹配诸如可用时间(art,n,adj)之类的项目.但是我想重写上述XPath,以确保节点的顺序得到尊重,因此可以使用的时间(art,adj)等构造与有关人员(art,adj,n)是.

# Possible representation of *the time available*
<node id="0" begin="1" cat="np">
    <node id="1" begin="1" pt="art" text="the" />        
    <node id="2" begin="2" pt="n" text="time" />
    <node id="3" begin="3" pt="adj" text="available" />
</node>

# Possible representation of *the concerned man*
<node id="0" begin="1" cat="np">
    <node id="1" begin="1" pt="art" text="the" />        
    <node id="2" begin="2" pt="adj" text="concerned" />
    <node id="3" begin="3" pt="n" text="man" />
</node>

一种方法是使用语料库中可用的begin属性的数字比较.它是数值上升的,所以如果我们要确保XPath的顺序是完整的,我们可以说,@ cat =“np”的每个子节点的数值应该通过使用number()来小于下一个.但是正如我上面显示的,这会导致一个错误 – 在我刚刚显示的简单示例代码中不会出现错误.

另一个例子.

<node id="0" begin="2">
    <node id="1" begin="2">
        <node id="2" begin="2"/>
        <node id="3" begin="3"/>
    </node>
    <node id="4" begin="5">
        <node id="5" begin="5"/>
    </node>
    <node id="6" begin="6"/>
</node>

这个XPath应该匹配:

/node/node[number(@begin) < number(../node/@begin)]

但是,当通过XQuery处理器时,您会得到上述错误.不允许多个项目的序列作为number()(“2”,“5”,…)的第一个参数.

我试过@Michael Kay提供的解决方案,但同样的问题似乎在发挥.

XQuery的

for $node in node[every $n in node[position() lt last()] satisfies (number($n/@begin) lt number($n/following-sibling::node/@begin))]
return $node

数据

<node id="0" begin="2">
    <node id="1" begin="2">
        <node id="2" begin="2"/>
        <node id="3" begin="3"/>
    </node>
    <node id="4" begin="5">
        <node id="5" begin="5"/>
    </node>
    <node id="6" begin="6"/>
</node>

错误

SaxonCE.XSLT20Processor 14:48:49.809 SEVERE: XPathException in
invokeTransform: A sequence of more than one item is not allowed as
the first argument of number() (“5”,“6”)

2017年4月19日更新

我今天碰到一些意想不到的行为,这使得@ har07提供的解决方案不再充分了.我错误地假设not()子句仅对XPath中的节点(而不是XML中的所有节点)产生影响.换句话说,当将not()子句添加到XPath的最顶层节点时,XML中的所有子节点都将具有固定的排序字序. (现在我读了这样,似乎只是正常的.)然而,我实际想要的是,单词顺序只能设置在XPath中指定的节点上,而不是匹配XML中的其他节点.希望和榜样将使这一点更清楚.

假设我想匹配以下XPath,一个cat =“np”,其中包含rel =“det”pt =“vnw”lemma =“die”,至少两次rel =“mod”pt =“adj”.

//node[@cat="np" and node[@rel="det" and @pt="vnw" and @lemma="die"] and count(node[@rel="mod" and @pt="adj"]) > 1]

但是增加的要求是遵循XPath的顺序,即

//node[
    @cat="np" and 
    not(node[
        position() < last()
    ][number(@begin) > following-sibling::node/number(@begin)]) and 
    node[
        @rel="det" and 
        @pt="vnw" and 
        @lemma="die"
    ] and 
    count(node[
        @rel="mod" and 
        @pt="adj"
    ]) > 1
]

所以rel =“det”必须在XML中的两个rel =“mod”之前发生.这工作正常,所有匹配都是正确的,但并不是所有的预期匹配都找到.原因是not()行显然是针对所有的XML节点而不是XPath指定的节点.如果找到不符合不规则的节点的行,则不会有匹配 – 即使在XPath中没有指定该节点.例如,上述XPath将不匹配以下XML,因为在cat =“np”内部存在一个开始属性大于其下一个兄弟节点的节点,这不是不允许的.

<node begin="4" cat="np" id="8" rel="obj1">
    <node begin="4" id="9" pos="det" pt="vnw" rel="det" word="die" lemma="die" />
    <node begin="5" id="10" pos="adj" pt="adj" rel="mod" word="veelzijdige" />
    <node begin="6" id="11" pos="adj" pt="adj" rel="mod" word="getalenteerde" />
    <node begin="7" id="12" pos="noun" pt="n" rel="hd" word="figuren" />
    <node begin="8" id="31" index="1" rel="obj1" />
    <node begin="2" id="32" index="2" rel="obj2" />
</node>

然而,我希望这个cat =“np”匹配,并且使not()函数更不具有攻击性,即只需要在XPath中指定的节点(在这个例子中,rel =“det”pt =“vnw”lemma =“die “,并且两个rel =”mod“pt =”adj“节点)遵循begin属性应小于XPath结构的下一个项的顺序要求.在XPath中未指定的cat =“np”中的其他项目允许具有大于其下一个兄弟节点的属性.

请注意,XPath结构的最后一个项目(与示例XML中的id =“11”匹配)不一定必须具有低于XML中以下节点的begin属性(在XPath中未指定) .

像以前一样,我对如何用纯XPath选项来解决这个问题特别感兴趣,但XQuery的替代方案也是受欢迎的.优选地,作为将XPath结构作为输入的函数,并且将“单词顺序”应用于其最上面的节点及其所有后代.鼓励使用XPath作为示例的示例代码用法.

关于您正在面对的一个以上的一个项目不允许的异常,请注意,XPath 2.0及更高版本和XQuery支持在路径步骤(… / number(…)上的函数调用)).也就是说,您可以在单个节点上调用number()一次传递一个begin属性,以避免异常:
/node/node[number(@begin) < ../node/number(@begin)]

但是,当至少存在一个具有begin属性值的同级节点大于当前节点的begin属性时,上述XPath中使用的谓词表达式将为true,这似乎不是所需的行为.

您可以对建议的XQuery应用相同的修复,但显然还有另一个类似的问题,因为用于将值与一系列值进行比较(很明显,我指的是建议的XQuery中的第2个) .您可以尝试以下,轻微修改XQuery:

for $node in node[
    every $n in node[position() lt last()] 
    satisfies not($n/following-sibling::node[number(@begin) lt number($n/@begin)])
]
return $node

“One way to go about is to use a numeric comparison of the begin attribute that is available in the corpus. It is numerical ascending,so if we want to ensure the order of XPath is intact,we can say that the numeric value of each child node of @cat="np" should be less than the next by using number().”

如果我正确理解,您可以使用以下XPath:

/node/node[
    not(
        node[position() < last()]
            [number(@begin) > following-sibling::node/number(@begin)]
    )
]

demo

XPath应该返回所有第二级节点元素,其中,除了当前第二级节点中最后一个之外的每个子节点,以下兄弟节点中没有一个与当前子节点相比数字较小的begin属性值.

给出以下示例XML:

<node id="0" begin="2">
    <node id="0" begin="1" cat="np">
        <node id="1" begin="1" pt="art" text="the" />
        <node id="2" begin="3" pt="n" text="time" />
        <node id="3" begin="2" pt="adj" text="available" />
    </node>
    <node id="0" begin="1" cat="np">
        <node id="1" begin="1" pt="art" text="the" />
        <node id="2" begin="2" pt="adj" text="concerned" />
        <node id="3" begin="3" pt="n" text="man" />
    </node>
</node>

只能选择第二个节点,因为它是唯一的以升序开始属性值的二级节点:

<node id="0" begin="1" cat="np">
   <node id="1" begin="1" pt="art" text="the"/>
   <node id="2" begin="2" pt="adj" text="concerned"/>
   <node id="3" begin="3" pt="n" text="man"/>
</node>

2017年4月19日更新:

…However,I would like this cat="np" to match,and make the not() function less aggressive,i.e. only require that nodes specified in XPath (in this example rel="det" pt="vnw" lemma="die",and the two rel="mod" pt="adj" nodes) follow the order requirement where the begin attribute should be smaller than the next item of the XPath structure.

那么我们需要添加另一个谓词来指定not()中的那些节点,那就是我们检查属性顺序需求的地方:

node[(@rel="det" and @pt="vnw" and @lemma="die") or (@rel="mod" and @pt="adj")]
    [position() < last()]
    [number(@begin) > 
         following-sibling::node[(@rel="det" and @pt="vnw" and @lemma="die") or (@rel="mod" and @pt="adj")]/number(@begin)
    ]

所以完整的表达如下:

//node[@cat="np" and 
    not(node[(@rel="det" and @pt="vnw" and @lemma="die") or (@rel="mod" and @pt="adj")]
            [position() < last()]
            [number(@begin) > 
                 following-sibling::node[
                    (@rel="det" and @pt="vnw" and @lemma="die") or (@rel="mod" and @pt="adj")
                 ]/number(@begin)
            ]
    ) 
    and node[@rel="det" and @pt="vnw" and @lemma="die"] 
    and count(node[@rel="mod" and @pt="adj"]) > 1
]

demo

原文链接:https://www.f2er.com/xml/292945.html

猜你在找的XML相关文章