XSLT将同名同级节点的值合并/连接到单个节点中
输入xmlXSLT将同名同级节点的值合并/连接到单个节点中,xslt,merge,siblings,Xslt,Merge,Siblings,输入xml <catalog> <product id="1"> <name>abc</name> <category>aaa</category> <category>bbb</category> <category>ccc</category> </product> <
<catalog>
<product id="1">
<name>abc</name>
<category>aaa</category>
<category>bbb</category>
<category>ccc</category>
</product>
<product id="2">
<name>cde</name>
<category>aaa</category>
<category>bbb</category>
</product>
</catalog>
abc
aaa
bbb
ccc
cde
aaa
bbb
预期输出xml
<products>
<product>
<id>1</id>
<name>abc</name>
<category>aaa,bbb,ccc</category>
</product>
<product>
<id>2</id>
<name>cde</name>
<category>aaa,bbb</category>
</product>
</products>
1.
abc
aaa、bbb、ccc
2.
cde
aaa,bbb
用于转换的XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/catalog">
<products>
<xsl:for-each select="product">
<product>
<id><xsl:value-of select="@id"/></id>
<name><xsl:value-of select="name"/></name>
<category><xsl:value-of select="category" /></category>
</product>
</xsl:for-each>
</products>
</xsl:template>
</xsl:stylesheet>
实际输出xml:(
1.
abc
aaa
2.
cde
aaa
通过每个“产品”下的名称“category”循环通过所有同级节点并合并/连接到单个节点(用逗号分隔)所需的代码。“category”的数量因每个产品而异,因此计数未知。使用此定义的方便连接调用模板,这变得非常简单:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/catalog">
<products>
<xsl:for-each select="product">
<product>
<id>
<xsl:value-of select="@id"/>
</id>
<name>
<xsl:value-of select="name"/>
</name>
<category>
<xsl:call-template name="join">
<xsl:with-param name="list" select="category" />
<xsl:with-param name="separator" select="','" />
</xsl:call-template>
</category>
</product>
</xsl:for-each>
</products>
</xsl:template>
<xsl:template name="join">
<xsl:param name="list" />
<xsl:param name="separator"/>
<xsl:for-each select="$list">
<xsl:value-of select="." />
<xsl:if test="position() != last()">
<xsl:value-of select="$separator" />
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
输出:
<products>
<product>
<id>1</id>
<name>abc</name>
<category>aaa,bbb,ccc</category>
</product>
<product>
<id>2</id>
<name>cde</name>
<category>aaa,bbb</category>
</product>
</products>
1.
abc
aaa、bbb、ccc
2.
cde
aaa,bbb
在XSLT 2.0中,只需对代码做一个小的更改:
<category><xsl:value-of select="category" separator=","/></category>
请注意,如果您需要XSLT 1.0解决方案,最好这样说。在某些环境中,有些人坚持使用1.0,但很多人不这样做。这里是另一个XSLT 1.0解决方案 当此XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="product">
<xsl:copy>
<xsl:apply-templates select="*[not(self::category)]" />
<category>
<xsl:apply-templates select="category/text()" />
</category>
</xsl:copy>
</xsl:template>
<xsl:template match="category/text()">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
<catalog>
<product id="1">
<name>abc</name>
<category>aaa</category>
<category>bbb</category>
<category>ccc</category>
</product>
<product id="2">
<name>cde</name>
<category>aaa</category>
<category>bbb</category>
</product>
</catalog>
<?xml version="1.0"?>
<catalog>
<product>
<name>abc</name>
<category>aaa,bbb,ccc</category>
</product>
<product>
<name>cde</name>
<category>aaa,bbb</category>
</product>
</catalog>
,
…应用于OP的原始XML:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="product">
<xsl:copy>
<xsl:apply-templates select="*[not(self::category)]" />
<category>
<xsl:apply-templates select="category/text()" />
</category>
</xsl:copy>
</xsl:template>
<xsl:template match="category/text()">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
<catalog>
<product id="1">
<name>abc</name>
<category>aaa</category>
<category>bbb</category>
<category>ccc</category>
</product>
<product id="2">
<name>cde</name>
<category>aaa</category>
<category>bbb</category>
</product>
</catalog>
<?xml version="1.0"?>
<catalog>
<product>
<name>abc</name>
<category>aaa,bbb,ccc</category>
</product>
<product>
<name>cde</name>
<category>aaa,bbb</category>
</product>
</catalog>
abc
aaa
bbb
ccc
cde
aaa
bbb
…产生所需结果:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="product">
<xsl:copy>
<xsl:apply-templates select="*[not(self::category)]" />
<category>
<xsl:apply-templates select="category/text()" />
</category>
</xsl:copy>
</xsl:template>
<xsl:template match="category/text()">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
<catalog>
<product id="1">
<name>abc</name>
<category>aaa</category>
<category>bbb</category>
<category>ccc</category>
</product>
<product id="2">
<name>cde</name>
<category>aaa</category>
<category>bbb</category>
</product>
</catalog>
<?xml version="1.0"?>
<catalog>
<product>
<name>abc</name>
<category>aaa,bbb,ccc</category>
</product>
<product>
<name>cde</name>
<category>aaa,bbb</category>
</product>
</catalog>
abc
aaa、bbb、ccc
cde
aaa,bbb
说明:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="product">
<xsl:copy>
<xsl:apply-templates select="*[not(self::category)]" />
<category>
<xsl:apply-templates select="category/text()" />
</category>
</xsl:copy>
</xsl:template>
<xsl:template match="category/text()">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
<catalog>
<product id="1">
<name>abc</name>
<category>aaa</category>
<category>bbb</category>
<category>ccc</category>
</product>
<product id="2">
<name>cde</name>
<category>aaa</category>
<category>bbb</category>
</product>
</catalog>
<?xml version="1.0"?>
<catalog>
<product>
<name>abc</name>
<category>aaa,bbb,ccc</category>
</product>
<product>
<name>cde</name>
<category>aaa,bbb</category>
</product>
</catalog>
- 第一个模板——匹配所有节点和属性,并按原样将它们复制到结果文档中
- 第二个模板通过创建新的
元素并处理文档当前位置中每个
元素的文本子元素来覆盖标识模板 - 最终模板根据需要输出文本值和逗号