XPath拉不止一场比赛

Bra*_*roy 15 xml xpath xquery

(BaseX)错误

我正在BaseX中的大型数据集上运行查询,但是一个XQuery正在崩溃我的程序并出现错误[XPTY0004] Item expected, sequence found: (attribute begin {"6"}, ...)..

在我的查询中,我试图通过比较beginXML中存在的属性来确保一个元素位于另一个元素之前number().但每当我在我的数据集上尝试最基本的XQueries(返回匹配节点)时(例如使用这个在线工具),我得到的错误类似于我之前的错误:

[错误] SaxonCE.XSLT20Processor 14:08:39.692 SEVERE:invokeTransform中的XPathException:不允许多个项目的序列作为number()的第一个参数("6","10")

所以我猜测节点的兄弟节点正在发生一些事情,即这些节点不止一个,并且不清楚应该比较哪个节点.示例如下.

为什么订单很重要?

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

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

node[@cat="np" and node[@pt="art"] and node[@pt="adj"] and node[@pt="n"]]
Run Code Online (Sandbox Code Playgroud)

默认情况下,XPath不关心这些元素的顺序,并做了贪婪搜索,也就是说,它也将匹配的项目,如可用时间(art,n,adj).但我想重新写上面的XPath,以确保该节点的顺序被尊重,所以建筑,如可用时间(art,n,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>
Run Code Online (Sandbox Code Playgroud)

一种方法是使用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>
Run Code Online (Sandbox Code Playgroud)

此XPath应匹配:

/node/node[number(@begin) < number(../node/@begin)]
Run Code Online (Sandbox Code Playgroud)

但是当通过XQuery处理器时,你会得到上述错误.A sequence of more than one item is not allowed as the first argument of 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
Run Code Online (Sandbox Code Playgroud)

数据

<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>
Run Code Online (Sandbox Code Playgroud)

错误

SaxonCE.XSLT20Processor 14:48:49.809 SEVERE:invokeTransform中的XPathException:不允许多个项目的序列作为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]
Run Code Online (Sandbox Code Playgroud)

但随着增加的要求遵循此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
]
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

不过,我想这个cat="np"匹配,并进行not()功能较少攻击性,即只要求在XPath的指定节点(在这个例子中rel="det" pt="vnw" lemma="die",两个rel="mod" pt="adj"节点)按照订单的要求在开始的属性应该比下一个项目较小的XPath结构.cat="np"其中未在XPath中指定的其他项目允许具有大于其下一个兄弟的属性.

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

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

har*_*r07 1

关于您面临的“不允许多个项目的序列”异常.../number(),请注意 XPath 2.0 及更高版本和 XQuery 支持路径步骤 ( ) 上的函数调用。也就是说,您可以调用number()individual一次node传递一个属性以避免异常:begin

/node/node[number(@begin) < ../node/number(@begin)]
Run Code Online (Sandbox Code Playgroud)

然而,上面 XPath 中使用的谓词表达式的计算结果是true,至少有一个同级node的begin属性值大于begincurrent 的属性node,这似乎不是所需的行为。

您可以对建议的 XQuery 应用相同的修复,但显然由于lt用于将值与值序列进行比较而存在另一个类似的问题(需要明确的是,我指的是lt建议的 XQuery 中的第二个)。您可以尝试以下稍作修改的 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
Run Code Online (Sandbox Code Playgroud)

“一种方法是使用begin语料库中可用属性的数字比较。它是数字升序,因此如果我们想确保 XPath 的顺序完整,我们可以说每个子项的数值通过使用 ,的节点@cat="np"应该小于下一个节点number()。”

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

/node/node[
    not(
        node[position() < last()]
            [number(@begin) > following-sibling::node/number(@begin)]
    )
]
Run Code Online (Sandbox Code Playgroud)

demo

XPath 应该返回所有 2nd levelnode元素,其中,对于node当前 2nd level 内的除最后一个子级之外的每个子node级,没有一个后续同级的属性值比当前 child 的node属性值低。beginnode

给定以下示例 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>
Run Code Online (Sandbox Code Playgroud)

node仅选择第二个,因为它是唯一node具有begin按升序排列属性值的第二个级别:

<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>
Run Code Online (Sandbox Code Playgroud)

2017 年 4 月 19 日更新:

“ ...但是,我希望它能够cat="np"匹配,并使not()函数不那么激进,即只要求 XPath 中指定的节点(在本例中rel="det" pt="vnw" lemma="die",以及两个rel="mod" pt="adj"节点)遵循顺序要求,其中 begin 属性应小于XPath 结构的下一项。 ”

然后我们需要添加另一个谓词来指定中的那些节点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)
    ]
Run Code Online (Sandbox Code Playgroud)

所以完整的表达式如下:

//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
]
Run Code Online (Sandbox Code Playgroud)

demo