我想转换XML,使特定名称的所有节点都包含这些节点下可用的所有元素的超集。
例如,这是输入xml。在此xml中,该组可以包含一个或多个项目节点。呼叫者只会传递该组下可用的项目。
<group>
<item>
<name> item1 </name>
<value> 10 </value>
</item>
</group>
<group>
<item>
<name> item2 </name>
<value> 20 </value>
</item>
</group>
要求是将其转换为如下所示的那个,其中来自所有组的项目节点应该是每个组的一部分。但是,如果该项目在该组下的输入中不可用,则应使用值0填充。
<group>
<item>
<name> item1 </name>
<value> 10 </value>
</item>
<item>
<name> item2 </name>
<value> 0 </value>
</item>
</group>
<group>
<item>
<name> item1 </name>
<value> 0 </value>
</item>
<item>
<name> item2 </name>
<value> 20 </value>
</item>
</group>
您能否告诉我如何使用XSLT实现这一目标?
由于
答案 0 :(得分:1)
以下是我的方法(在XSLT 2.0中,因为你没有指定)......
XML输入(包含在<groups>
中,格式正确)
<groups>
<group>
<item>
<name> item1 </name>
<value> 10 </value>
</item>
</group>
<group>
<item>
<name> item2 </name>
<value> 20 </value>
</item>
</group>
</groups>
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:variable name="names" select="distinct-values(/*/group/item/name)"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="group">
<xsl:variable name="currentItems" select="item/name"/>
<xsl:variable name="items" as="node()*">
<xsl:apply-templates select="item"/>
<xsl:for-each select="$names[not(. = current()/item/name)]">
<item>
<name><xsl:value-of select="."/></name>
<value> 0 </value>
</item>
</xsl:for-each>
</xsl:variable>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:perform-sort select="$items">
<xsl:sort select="name"/>
</xsl:perform-sort>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML输出
<groups>
<group>
<item>
<name> item1 </name>
<value> 10 </value>
</item>
<item>
<name> item2 </name>
<value> 0 </value>
</item>
</group>
<group>
<item>
<name> item1 </name>
<value> 0 </value>
</item>
<item>
<name> item2 </name>
<value> 20 </value>
</item>
</group>
</groups>
答案 1 :(得分:0)
这是XSLT 1.0和XSLT 2.0解决方案:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vGroupContent" select="/*/group/node()"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="group">
<group>
<xsl:apply-templates select=
"node()|@*|$vGroupContent[not(name = current()/item/name)]">
<xsl:with-param name="pGroup" select="."/>
<xsl:sort select="name"/>
</xsl:apply-templates>
</group>
</xsl:template>
<xsl:template match="item">
<xsl:param name="pGroup"/>
<item>
<xsl:apply-templates select="name"/>
<value> <xsl:value-of select=
"value/text()[generate-id($pGroup) = generate-id(../../..)]"/>
<xsl:if test=
"value/text()[not(generate-id($pGroup) = generate-id(../../..))]"> 0 </xsl:if>
</value>
</item>
</xsl:template>
</xsl:stylesheet>
对以下XML文档应用此转换时:
<t>
<group>
<item>
<name> item1 </name>
<value> 10 </value>
</item>
</group>
<group>
<item>
<name> item2 </name>
<value> 20 </value>
</item>
</group>
</t>
产生了想要的正确结果:
<t>
<group>
<item>
<name> item1 </name>
<value> 10 </value>
</item>
<item>
<name> item2 </name>
<value> 0 </value>
</item>
</group>
<group>
<item>
<name> item1 </name>
<value> 0 </value>
</item>
<item>
<name> item2 </name>
<value> 20 </value>
</item>
</group>
</t>