我有一个名为employees.xml的XML文档:
<employees>
<row>
<emp_no>10001</emp_no>
<first_name>Georgi</first_name>
<last_name>Facello</last_name>
</row>
<row>
<emp_no>10002</emp_no>
<first_name>Bezalel</first_name>
<last_name>Simmel</last_name>
</row>
</employees>
我想编写一个名为my-remove-elements
的函数,它将删除未选择的属性。例如,只在XML文档中保留first_name
和last_name
:
<employees>
<row>
<first_name>Georgi</first_name>
<last_name>Facello</last_name>
</row>
<row>
<first_name>Bezalel</first_name>
<last_name>Simmel</last_name>
</row>
</employees>
我的功能定义是:
declare function local:my-remove-elements($input as element(), $remove-names as xs:string*) as element() {
element {node-name($input) }
{$input/@*,
for $child in $input/node()[name(.)=$remove-names]
return
if ($child instance of element())
then local:my-remove-elements($child, $remove-names)
else $child
}
};
这就是我称之为的方式:
let $doc := doc("employees.xml")
return
local:my-remove-elements($doc, ('first_name', 'last_name'))
它引发了我&#34;错误:XPTY0004 ...不是元素的子类型()...&#34; 我更改了代码:
let $rows:= doc("employees.xml")//row
return
local:my-remove-elements($rows, ('first_name', 'last_name'))
这次仍然是:&#34;错误:XPTY0004:参数1的实际基数与函数签名中的基数不匹配...&#34;。你知道如何解决这个问题并让它发挥作用吗?
答案 0 :(得分:0)
这是一个可能的解决方案:
declare function local:remove-elements(
$node as node(),
$keep-names as xs:string*
) as node()? {
if($node instance of element()) then (
let $name := name($node)
where $name = $keep-names
return element { $name } {
$node/@*,
for $child in $node/node()
return local:remove-elements($child, $keep-names)
}
) else (
$node
)
};
local:remove-elements(
doc("employees.xml")/employees,
('employees', 'row', 'first_name', 'last_name')
)
这是另一个使用XQuery Update的方法:
declare function local:remove-elements(
$node as node(),
$keep-names as xs:string*
) as node()? {
copy $c := $node
modify delete node $c//*[not(name() = $keep-names)]
return $c
};
local:remove-elements(
doc("employees.xml")/employees,
('employees', 'row', 'first_name', 'last_name')
)
答案 1 :(得分:0)
错误err:XPTY0004
是因为您正在调用传递document-node()
作为第一个参数的函数,但第一个参数需要是element()
。
更改您调用它的方式,传入文档元素(即$doc/*
)而不是document-node()
然后,您需要调整函数中的逻辑。如果您只选择$child
等于$remove-names
的节点(这会令人困惑,请考虑重命名为$ keep-leaf-names),那么employees
元素将是排除。向下移动该过滤器,如果元素有子项,或者name()
等于$remove-names
中的任何一个,则添加要处理的逻辑。
declare function local:my-remove-elements($input as element(), $remove-names as xs:string*) as element() {
element {node-name($input) }
{$input/@*,
for $child in $input/node()
return
if ($child instance of element()) then
if ($child/* or name($child)=$remove-names) then
local:my-remove-elements($child, $remove-names)
else ()
else $child
}
};