使用XQuery我想从产品中的每篇文章中选择一个特殊值。
我现在有什么:
输入XML(摘录):
<product type="product" id="2246091">
<product type="article">
<attribute identifier="EXAMPLE1" type="BOOLEAN">0</attribute>
<attribute identifier="EXAMPLE2" type="BOOLEAN">1</attribute>
</product>
<product type="article">
<attribute identifier="EXAMPLE1" type="BOOLEAN">1</attribute>
<attribute identifier="EXAMPLE2" type="BOOLEAN">1</attribute>
</product>
<product type="article">
<attribute identifier="EXAMPLE1" type="BOOLEAN">0</attribute>
<attribute identifier="EXAMPLE2" type="BOOLEAN">1</attribute>
</product>
</product>
的XQuery:
for $i in //product
[@type = 'product'
and @id = '2246091']
//attribute
[@type='BOOLEAN'
and @identifier= ('EXAMPLE1', 'EXAMPLE2') ]
where $i = '1'
return $i
这会返回attribute
下每篇文章的每个product
元素,其中内容为&#39; 1&#39;其标识符为EXAMPLE1或EXAMPLE2。
可能的是,在第1条中,与第2条中的attribute
标识符相同(例如,EXAMPLE1)。
我得到了什么:
<?xml version="1.0" encoding="UTF-8"?>
<attribute identifier="EXAMPLE2" type="BOOLEAN">1</attribute>
<attribute identifier="EXAMPLE1" type="BOOLEAN">1</attribute>
<attribute identifier="EXAMPLE2" type="BOOLEAN">1</attribute>
<attribute identifier="EXAMPLE2" type="BOOLEAN">1</attribute>
我尝试在我的for
循环周围添加一个明确的值,但这只会返回给我&#39; 1&#39;。
我想要的只是获取每个属性一次:
<attribute identifier="EXAMPLE2" type="BOOLEAN">1</attribute>
<attribute identifier="EXAMPLE1" type="BOOLEAN">1</attribute>
答案 0 :(得分:2)
听起来好像你想要的是在内容为1的attribute
元素中找到identifier
属性的每个不同值的一个attribute
元素。(或者,更具挑战性的是,每组等效attribute
元素有一个attribute
元素,其中等价由deep-equals()定义。)
distinct-values()函数在这里没有帮助,因为它将任何输入节点强制转换为简单值(此处为1)。
identifier
属性上的匹配就足够了如果identifier
属性足以在元素之间建立等价,那么类似下面的内容就足够了(未经测试):
let $ones := //product[@type = 'product'
and @id = '2246091']
//attribute[@type='BOOLEAN'
and @identifier =
('EXAMPLE1', 'EXAMPLE2') ],
$ids := distinct-values($ones/@identifier)
for $id in $ids
return ($ones[@identifier = $id])[1]
如果@identifier
不足以为您的目的建立等同性,那么您将不得不做一些更复杂的事情;在一般情况下,一种方法是编写两个参数的函数(我称之为local:equivalent()
),如果两个参数对于您的目的是等效的,则返回true。然后编写第二个函数来接受一系列项目并从序列中删除重复项(其中&#39;是重复的&#39;表示&#39;在local:equivalent()
上返回true)。像这样的东西可能作为第一个近似值(未经测试):
(: dedup#1: remove duplicates from a sequence :)
declare function local:dedup(
$items as item()*
) as xs:boolean {
local:dedup($items, ())
};
(: dedup#2: work through the input sequence one
by one, removing duplicates and accumulating
non-duplicates. Cost is n^2 / 2. :)
declare function local:dedup(
$in as item()*,
$out as item()*
) as xs:boolean {
if (empty($in))
then $out
else let $car := head($in)
return if (some $i in $in
satisfies
local:equivalent($i, $car))
then local:dedup(tail($in), $out)
else local:dedup(tail($in), ($car, $out))
};
(: equivalent#2: true iff arguments are equivalent :)
declare function local:equivalent(
$x, $y : item()
) as xs:boolean {
// determine application-specific equivalence
// however you like ...
deep-equal($x, $y)
};
(: Now do the work :)
let $ones := //product[@type = 'product'
and @id = '2246091']
//attribute[@type='BOOLEAN'
and @identifier =
('EXAMPLE1', 'EXAMPLE2') ]
return local:dedup($ones)
那些对高阶函数感兴趣的人希望更进一步,通过允许两个local:equivalent
函数接受提供等价函数的附加参数来消除对具有名为local:dedup
的函数的依赖性。