我如何获取同名的所有元素节点,并将它们组合成一个保留每个节点的子元素的节点?
示例输入:
<topic>
<title />
<language />
<more-info>
<itunes />
</more-info>
<more-info>
<imdb />
</more-info>
<more-info>
<netflix />
</more-info>
</topic>
示例输出(所有more-info
都折叠为单个元素):
<topic>
<title />
<language />
<more-info>
<itunes />
<imdb />
<netflix />
</more-info>
</topic>
编辑:我正在寻找一种方法来做到这一点,而不知道哪些节点名称重新出现。因此,通过上面的示例,我无法使用仅定位more-info
的脚本,因为可能还有其他元素也需要应用相同的过程。
答案 0 :(得分:1)
使用强>:
declare option saxon:output "omit-xml-declaration=yes";
<topic>
<title />
<language />
<more-info>
{for $inf in /*/more-info/node()
return $inf
}
</more-info>
</topic>
将此XQuery应用于提供的XML文档:
<topic>
<title />
<language />
<more-info>
<itunes />
</more-info>
<more-info>
<imdb />
</more-info>
<more-info>
<netflix />
</more-info>
</topic>
产生了想要的正确结果:
<topic>
<title/>
<language/>
<more-info>
<itunes/>
<imdb/>
<netflix/>
</more-info>
</topic>
答案 1 :(得分:0)
如果您可以使用它,这对XSLT来说似乎更好。
XML输入
<topic>
<title />
<language />
<more-info>
<itunes />
</more-info>
<more-info>
<imdb />
</more-info>
<more-info>
<netflix />
</more-info>
</topic>
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each-group select="*" group-by="name()">
<xsl:copy>
<xsl:apply-templates select="current-group()/@*"/>
<xsl:apply-templates select="current-group()/*"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML输出
<topic>
<title/>
<language/>
<more-info>
<itunes/>
<imdb/>
<netflix/>
</more-info>
</topic>
答案 2 :(得分:0)
我是这么做的:
for $n in $nodes/node()
let $lname := local-name($n)
group by $lname
return element {$lname} {
$n/node()
}
$nodes
包含输入文档。
它使用group by
将$n
变量绑定到分组节点列表。
因此,表达式$n/node()
代表节点序列。
要使其递归,我们必须声明一个函数并调用它:
declare function local:recurse($node){
for $n in $node/text() return $n,
for $n in $node/element()
let $lname := local-name($n)
group by $lname
return element {$lname} {
for $m in $n return local:recurse($m)
}
};
local:recurse($nodes)
第一行以逗号结尾。这是一个列表串联。因此,我们首先输出文本节点,然后输出具有上述group by
sheningan的元素节点。
<topic>
<title>Test</title>
<language />
<more-info>
<itunes>
<playlist>
<item>2</item>
</playlist>
<playlist>
<item>3</item>
</playlist>
</itunes>
</more-info>
<more-info>
<imdb>Imdb info</imdb>
</more-info>
<more-info>
<netflix>Netflix info</netflix>
</more-info>
</topic>
<title>Test</title>
<language/>
<more-info>
<itunes>
<playlist>
<item>2</item>
<item>3</item>
</playlist>
</itunes>
<imdb>Imdb info</imdb>
<netflix>Netflix info</netflix>
</more-info>
我不知道为什么XSLT更容易。也许apply-templates
伪装了递归,使其不那么令人生畏。
此外,与要求在“循环”内进行匹配的XQuery相比,匹配在“循环”外进行声明这一事实使它更容易(然后必须与模式配对以进行完全控制)。
无论如何,在这个特殊的示例中,XQuery
似乎非常合适。