XQuery:调试递归函数

时间:2016-04-11 16:00:28

标签: xquery

xqy文件:

import module namespace functx="http://www.functx.com";

declare variable $defaultXMLNS:="http://www.test.com#";
declare variable $defaultXMLBase:=$defaultXMLNS;

declare function local:descriptionConstructorTail(
  $seq as item()*, 
  $i as xs:integer?, 
  $res as item()*
)
{
  if($i <= 0)
  then $res
  else local:descriptionConstructorTail($seq, 
           $i - 1, 
           functx:value-union($res, 
                  (<test1 about="{$seq[$i]/@value}"/>)))
};

declare function local:descriptionConstructor($pnode as node()*)
{
  local:descriptionConstructorTail($pnode//xs:enumeration, 
        count($pnode//xs:enumeration), 
        ())
};

element test
{
  local:descriptionConstructor(doc("./test2.xsd"))
}

xsd文件:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  attributeFormDefault="unqualified" 
  elementFormDefault="qualified">

  <xs:simpleType name="size">
    <xs:restriction base="xs:string">
      <xs:enumeration value="small" />
      <xs:enumeration value="medium" />
      <xs:enumeration value="large" />
    </xs:restriction>
  </xs:simpleType>

</xs:schema>

我一直在搞乱这个小程序2个小时。始终不期望输出。

$ basex test2.xqy
<test/>

对于上面的示例xsd文件,我希望输出如下:

<test>
<test1 about="small"/>
<test1 about="medium"/>
<test1 about="large"/>
</test>

此示例可能看不到逻辑,因为您不必使用递归函数来执行此操作。但我想把它作为递归函数的练习。

1 个答案:

答案 0 :(得分:0)

虽然functx库是一个非常方便的实用程序函数集合,但重要的是要知道这些是什么,这样你就可以避免像这样的惊喜。 functx:value-union(...)的实施方式如下:

declare function functx:value-union(
  $arg1 as xs:anyAtomicType*,
  $arg2 as xs:anyAtomicType*
) as xs:anyAtomicType* {
  distinct-values(($arg1, $arg2))
};

所以它只是将distinct-values(...)应用于其输入的连接。由于此函数适用于类型xs:anyAtomicType的值,因此您的XML节点将被雾化。这只留下了你的元素没有的文本内容。所以你只是反复建立空序列的联合。

这应该可以正常工作:

declare function local:descriptionConstructorTail($seq as item()*, $i as xs:integer?, $res as item()*) {
  if($i <= 0) then $res
  else local:descriptionConstructorTail($seq, $i - 1, distinct-values(($res, $seq[$i]/@value)))
};

declare function local:descriptionConstructor($pnode as node()*) {
  let $enums := $pnode//xs:enumeration
  for $res in local:descriptionConstructorTail($enums, count($enums), ())
  return <test1 about="{$res}"/>
};

element test {
  local:descriptionConstructor(doc("./test2.xsd"))
}

顺便说一句,你的递归函数遵循由高阶函数fold-right(...)编码的递归方案,所以你也可以写:

declare function local:descriptionConstructor($pnode as node()*) {
  for $res in
    fold-right(
      $pnode//xs:enumeration,
      (),
      function($enum, $res) {
        distinct-values(($enum/@value, $res))
      }
    )
  return <test1 about="{$res}"/>
};

element test {
  local:descriptionConstructor(doc("./test2.xsd"))
}