我在BaseX中的大型数据集上运行查询,但是一个XQuery使我的程序崩溃并出现错误[XPTY0004] Item expected, sequence found: (attribute begin {"6"}, ...).
。
在我的查询中,我试图通过比较begin
(XML中存在的属性)与number()
来确保一个元素位于另一个元素之前。但每当我在我的数据集上尝试最基本的XQueries(返回匹配节点)时(例如使用this online tool),我得到的错误类似于我之前的错误:
[错误] SaxonCE.XSLT20Processor 14:08:39.692严重:XPathException in invokeTransform:不允许包含多个项目的序列 number()的第一个参数(" 6"," 10")
所以我猜这个节点的兄弟姐妹正在发生一些事情,即这些节点不止一个,并且不清楚应该比较哪些节点。示例如下。
XPath用于树库的查询引擎:语言注释语料库。在某些情况下,我们希望节点按顺序匹配,有时无关紧要。作为一个简单的例子:有时我们希望匹配某些特定的东西,如有关的人,其中订单文章,形容词,名词很重要。在其他查询中它并不重要,我们希望匹配短语,例如可用时间,其中文章,形容词,名词的顺序可以是任何顺序。
换句话说,在第一种情况下,应该尊重元素的顺序,在第二种情况下,它不应该被尊重。这是一个可能包含文章,形容词和名词的结构的XPath表示。
node[@cat="np" and node[@pt="art"] and node[@pt="adj"] and node[@pt="n"]]
默认情况下,XPath不关心这些元素的顺序并执行贪婪搜索,即它还会匹配可用时间(art
,{{1 },n
)。但是我想重新编写上面的XPath以确保节点的顺序得到遵守,因此构造如可用时间(adj
,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>
属性的数字比较。它是数字递增的,所以如果我们想确保XPath的顺序完好无损,我们可以说begin
的每个子节点的数值应该小于下一个使用@cat="np"
。但正如我在上面所示,这会导致错误 - 在我刚刚展示的简单示例代码中不会出现错误。
另一个例子。
number()
此XPath应匹配:
<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>
但是当通过XQuery处理器时,你会得到上述错误。 /node/node[number(@begin) < number(../node/@begin)]
。
我尝试了@Michael Kay提供的解决方案,但似乎也出现了同样的问题。
的XQuery
A sequence of more than one item is not allowed as the first argument of number() ("2", "5", ...)
数据
for $node in node[every $n in node[position() lt last()] satisfies (number($n/@begin) lt number($n/following-sibling::node/@begin))]
return $node
错误
SaxonCE.XSLT20Processor 14:48:49.809严重:XPathException in invokeTransform:不允许包含多个项目的序列 number()的第一个参数(&#34; 5&#34;,&#34; 6&#34;)
我今天遇到了一些意想不到的行为,这使得@ har07提供的解决方案不再充分。我错误地认为<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中的节点有影响(而不是XML中的所有节点)。换句话说,当not()
子句添加到XPath的最顶层节点时,XML中的所有子节点都将具有固定的排序单词顺序。 (现在我这样读了它,看起来很正常。)但是,我真正想要的是单词顺序只在XPath中指定的节点上设置,而不是匹配XML中的其他节点。希望和榜样能让这一点更清晰。
我们想要匹配以下XPath,not()
包含cat="np"
且至少两次rel="det" pt="vnw" lemma="die"
。
rel="mod" pt="adj"
但是,并且要求遵循此XPath的顺序,即
//node[@cat="np" and node[@rel="det" and @pt="vnw" and @lemma="die"] and count(node[@rel="mod" and @pt="adj"]) > 1]
所以//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
]
必须在之前发生 XML中的两个rel="det"
。这工作正常,所有匹配都是正确的,但找不到所有预期的匹配。原因是rel="mod"
行显然是针对所有XML节点而不是XPath指定的节点。如果找到一个不符合not()
规则的节点,那么即使在XPath中未指定该节点,也不会成为匹配。例如,上面的XPath将不匹配以下XML,因为在not
内有一个节点,其begin属性大于其下一个兄弟节点,{{1}不允许}} 规则。
cat="np"
但是,我希望此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>
函数不那么激进,即只需要在XPath中指定的节点(在此示例中为cat="np"
),以及两个not()
个节点)遵循订单要求,其中begin属性应小于XPath结构的下一个项 。 {/ 1}}中未在XPath中指定的其他项目允许具有大于其下一个兄弟的属性。
请注意,XPath结构的最后一项(与示例XML中的rel="det" pt="vnw" lemma="die"
匹配)不一定必须具有低于XML中的后续节点的begin属性(未在XPath)。
和以前一样,我对如何使用纯XPath选项解决这个问题特别感兴趣,但也欢迎使用XQuery替代方案。优选地,作为将XPath结构作为输入的函数,并应用&#39;字顺序&#39;到它的最顶层节点及其所有后代。我们鼓励使用此处所示的XPath示例代码和用法作为示例。
答案 0 :(得分:1)
我认为我理解的部分问题是:
假设我想匹配XML,其中根的每个直接子项的属性开始小于下一个兄弟。
<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)]
现在,相当清楚为什么会给你一个错误。在谓词中,..
选择id = 0的节点,它有三个子节点(带有id 1,4和6),并且每个节点都有一个@begin
属性,所以{{1选择三个属性的序列。
您的查询似乎与散文要求没有任何关系,即
其中root的每个直接子项的属性begin小于下一个兄弟
条件是
node [node [position()lt last()]中的每个$ n都满足 (number($ n / @ begin)lt number($ n / following-sibling :: node / @ begin)]
答案 1 :(得分:1)
关于 a-sequence-of-more-than-item-is-not-allowed 异常,请注意XPath 2.0及更高版本和XQuery支持函数调用在路径步骤(.../number()
)。也就是说,您可以在单个number()
上调用node
,一次传递一个begin
属性,以避免异常:
/node/node[number(@begin) < ../node/number(@begin)]
但是,如果至少有一个兄弟true
且node
属性值大于begin
当前属性,则上面XPath中使用的谓词表达式的计算结果为begin
node
,这似乎不是理想的行为。
您可以对建议的XQuery应用相同的修复,但显然还有另一个类似的问题,因为lt
用于将值与值序列进行比较(要清楚,我指的是建议的XQuery中的第二个lt
。您可以尝试以下,稍加修改,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
“一种方法是使用语料库中可用的
begin
属性的数字比较。它是数字升序,所以如果我们想确保XPath的顺序是完整的,我们可以说使用@cat="np"
,number()
的每个子节点的数值应该小于下一个子节点。“
如果我理解正确,您可以使用以下XPath:
/node/node[
not(
node[position() < last()]
[number(@begin) > following-sibling::node/number(@begin)]
)
]
<强> demo
强>
XPath应该返回所有第二级node
元素,其中,对于除了当前第二级node
中的最后一个之外的每个子node
,以下任何一个node
都没有} begin
属性的值在数值上低于当前子node
的值。
给出以下示例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
,因为它是唯一具有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>
2017年4月19日更新:
“ ...但是,我希望此
cat="np"
匹配,并使not()
函数不那么激进,即只需要在XPath中指定的节点(在此示例中为rel="det" pt="vnw" lemma="die"
,并且两个rel="mod" pt="adj"
节点)遵循订单要求,其中begin属性应小于XPath结构的下一项。“
然后我们需要向{strong>指定 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
强>
答案 2 :(得分:-1)
就您的递归搜索请求而言:
从xml树的内层使用//node[@pt=("art" or "adj" or "n")]/ancestor::*
搜索。在您的示例xml中,这将以递归方式返回(每个元素组)每个顶级。