近段时间在学习XQuery.学得越多感觉XQuery越实用,甚至于感觉用XML-XQuery的搭配比XML-XSLT的组合要发挥出更大的作用些.
特别在XQuery3.0/3.1推出了很多新的功能后.XQuery作为一种独立的语言确实要比XSLT强大得多.
今天偶然在XML论坛上见到多年前有人发布的一道题目:
<element name="abc" id="0001" project="xxx">
<att name="att1" type="string">san you</att>
<att name="att2" type="string">big look</att>
<att name="att3" type="string">san you</att>
<att name="att4" type="number">234</att>
<att name="att5" type="bool">false</att>
</element>
<element name="abcde" id="0002" project="xxx2">
<att name="att1" type="string">aaaa</att>
<att name="att2" type="string">bbbb</att>
<att name="att3" type="string">cccc</att>
<att name="att4" type="number">1234</att>
<att name="att5" type="bool">false</att>
</element>
对于上面的文档,使用xquery实现如下功能是否可行,如果能提供示例,不胜感激:
1 查询具name='att4',并且值等于234(以数值类型比较)的element元素
2 查询同时拥有条件为 name='att1' 值='aaaa'的<att/>元素 和 name='att2' 值=‘bbbb' 的<att/>元素的element,查询结果应为第二个element.
1.由于在强制类型转换如果不成功的话会产生错误.所以理论上来说用数值类型比较att的值是不现实的.
但是可以换一种方式来理解.比如预先判断att的值是否符合数字的匹配模式(正则),另外在XQuery3.0以后提出了try-catch的方式来处理错误.
所以题目1有存在两种方式来解决.代码如下:
declare function local:equal($att as xs:string,$value as xs:integer) as xs:boolean{
if(matches(normalize-space($att),"\d+")) then (xs:integer($att) = $value) else (false())
};
declare function local:equals($att as xs:string,$value as xs:integer) as xs:boolean{
try{
xs:integer($att) = $value
}catch *{
false()
}
};
for $element in doc("source.xml")/elements/element
for $att in $element/att
where $att/@name = "att4" and local:equals(string($att),234)
return if(exists($att)) then($element) else()
通过在XQuery中自定义方法来解决.如果如果传入的参数符合数字的格式则按照数字格式来比较,否则直接返回false().并且在FLWOR中的where来调用函数.
2.题目2相对简单些.主要思想是通过定义两个变量来引用attr,然后分别判断这两个变量是否符合要求.代码如下:
for $element in doc("source.xml")/elements/element
let $attrs as element(att)* := $element/att
for $attr1 in $attrs
for $attr2 in $attrs
where $attr1/@name="att1"
and xs:string($attr1) = "aaaa"
and $attr2/@name="att2"
and xs:string($attr2) = "bbbb"
return $element