XQuery:调试递归函数
XQuery: debugging recursive function
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>
这个例子可能看起来不合逻辑,因为你不必使用递归函数来做这个。但我想把它作为递归函数的练习。
虽然 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"))
}
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>
这个例子可能看起来不合逻辑,因为你不必使用递归函数来做这个。但我想把它作为递归函数的练习。
虽然 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"))
}