【发布时间】:2014-06-16 00:31:51
【问题描述】:
我有一个如下所示的 xml 文档:
<dict>
<word>
<sense>
<definition> This is the text of the definition.
<example>
<quote>This is the text of an example.</quote>
</example>
<source>
<place>This is the name of the place recorded</place>
</source>.
</definition>
</sense>
</word>
</dict>
我需要使用 xQuery 对其进行转换,使<example> 及其子代成为<definition> 的兄弟姐妹,而<source> 及其子代应成为<example> 的子代。换句话说,我需要这个作为输出:
<word>
<sense>
<definition> This is the text of the definition. </definition>
<example>
<quote>This is the text of an example.</quote>
<source>
<place>This is the name of the place recorded.</place>
</source>
</example>
</sense>
</word>
如您所见,原始<source> 元素后面的句号也存在问题,该元素需要成为<place> 关闭之前的最后一个字符串。
我创建了一个 xQuery 文件并想出了如何从层次结构中删除元素,但是我在递归处理节点和在同一函数中添加新元素时遇到了麻烦。
xquery version "3.0";
declare namespace saxon="http://saxon.sf.net/";
declare option saxon:output "indent=yes";
declare option saxon:output "saxon:indent-spaces=3";
declare function local:test($node as item()*) as item()* {
typeswitch($node)
case text() return normalize-space($node)
case element(word) return <word>{local:recurse($node)}</word>
case element(dict) return <dict>{local:recurse($node)}</dict>
case element(sense) return <sense>{local:recurse($node)}</sense>
case element(definition) return local:definition($node)
case element(example) return local:example($node)
case element(source) return local:source($node)
case element(place) return <place>{local:recurse($node)}</place>
default return local:recurse($node)
};
declare function local:definition($nodes as item()*) as item()*{
(: here I need to process children of definition - except <source> and its
children will become children of <example>; and <example> should be returned
as a next sibling of definition. THIS IS THE PART THAT I DON'T KNOW HOW TO DO :)
<definition>
{
for $node in $nodes/node()
return
local:test($node)
}
</definition>
};
declare function local:example($node as item()*) as item()* {
(: here i am removing <example> because I don't want it to be a child
of <definition> any more. THIS BIT WORKS AS IT SHOULD :)
if ($node/parent::definition) then ()
else <example>{$node/@*}{local:recurse($node)}</example>
};
declare function local:source($node as item()*) as item()* {
(: here i am removing <source> because I don't want it to be a child
of <definition> any more. :)
if ($node/parent::definition) then ()
else <example>{$node/@*}{local:recurse($node)}</example>
};
declare function local:recurse($nodes as item()*) as item()* {
for $node in $nodes/node()
return
local:test($node)
};
local:test(doc("file:test.xml"))
这应该不是一件非常困难的事情,但我在 xQuery 如何处理此类问题时遇到了概念上的困难。非常感谢您的帮助。
XSLT 不是一个选项。
【问题讨论】:
标签: xml xpath recursion xml-parsing xquery