假设有这个XML文件:
<Adam>
<JackSons>
<s1>Jack</s1>
<s2>Sara</s2>
</JackSons>
<PeterSons>
<s1>Peter</s1>
<n>
<s2>Anna</s2>
</n>
</PeterSons>
<DavidSons>
<q>
<s1>David</s1>
</q>
<n>
<s2>Suzann</s2>
</n>
</DavidSons>
</Adam>
我想得到s2
每个s1的兄弟或侄女在循环内调用它们的两个函数,请注意我们对XML的结构一无所知。每个s1
和s2
都有一个共同的祖先,我试过
let $db := doc('test2.xq')
for $s1 in $db//s1
let $s2 := $db//*[//$s1]/(s2, */s2)
return <p> {$s1/text()} marry {$s2/text()} </p>
返回
<p>Jack marry SaraAnnaSuzann</p>
<p>Peter marry SaraAnnaSuzann</p>
<p>David marry SaraAnnaSuzann</p>
我希望
<p>Jack marry Sara</p>
<p>Peter marry Anna</p>
<p>David marry Suzann</p>
答案 0 :(得分:2)
您的查询的问题是您再次在整个文档中搜索s2
个节点,而不是同一个项目。
不要搜索s1
元素,但要查找对并为每个元素打印一条消息。
for $pair in //item
return <p>{ $pair//s1/text() } marry { $pair//s2/text() }</p>
你可能也会查找s1
个元素并找到匹配的s2
个节点,但是这很难阅读和理解,并且可能因为下降回来而表现更差在树下找到item
都属于:
for $s1 in //s1
let $s2 := $s1//ancestor::item//s2
return <p>{ $s1/text() } marry { $s2/text() }</p>
在这两种情况下,根据文档中允许的内容,您可能需要添加一些保护措施,以便只查找两对。可能最具限制性的例子是
for $pair in //item
let $s1 := $pair//s1, $s2 := $pair//s2
where count($s1) = 1 and count($s2) = 1
return <p>{ $s1/text() } marry { $s2/text() }</p>
为了完整性,这甚至可能没有一个明确的for循环(虽然不一定是一个合理的解决方案,因为如果复杂性增加会更难阅读和理解):
//item/element p { concat(.//s1/text(), " marry ", .//s2/text()) }
答案 1 :(得分:0)
根据s1和s2中文本的复杂程度,以下内容对您来说可能就足够了:
//item[starts-with(s2, s1)]/s2
我需要查看更多真实数据,以了解您是否需要更复杂的内容,但这应该适用于您发布的示例。
答案 2 :(得分:0)
当您只知道s1
和s2
有一个共同的祖先时,您可以使用以下代码:
let $db := doc('test2.xq')
for $s1 in $db//s1
let $item := $s1/ancestor::*[.//s1 and .//s2][not(.//*[.//s1 and .//s2])]
let $s2 := $item//s2
return <p>{ $s1/text() } marry { $s2/text() }</p>
对于每个$s1
找到一个包含s1
和s2
的祖先,其后代不包含s1
和s2
。这是第一个共同的祖先(父母)。使用此项目,找到相应的(兄弟或侄女)s2
。