使用 XSLT 合并 XML 中的条目
Merge entries in XML with XSLT
这是我的 XML 文件中的一个片段,每个产品都是独立的 <SHOPITEM>
:
<?xml version="1.0" encoding="UTF-8"?>
<SHOP>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,00</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,99</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>red / green</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
</SHOP>
可以在同一个 <PRODUCT>
上对产品选项进行分组,如下所示:
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
<PRODUCT_VARIANT id="2">
<COLOR>red / green</COLOR>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,99</CODE>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<AVAILABLE>NO</AVAILABLE>
<NOTE>Available 15.2.2015</NOTE>
</PRODUCT_VARIANT>
<PRODUCT_VARIANT id="3">
<COLOR>black / white</COLOR>
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<AVAILABLE>NO</AVAILABLE>
<NOTE>Available 15.2.2015</NOTE>
</PRODUCT_VARIANT>
</SHOPITEM>
注意:这是基于这样的假设,即应根据 <PRODUCT>
子节点的相同值对商店商品进行分组。如果必须比较其他节点值,请将其添加到问题中。
以下 XSLT
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" doctype-public="XSLT-compat"
omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM[not(PRODUCT=preceding-sibling::SHOPITEM/PRODUCT)]">
<xsl:variable name="currentProduct" select="PRODUCT"/>
<xsl:copy>
<xsl:apply-templates/>
<xsl:if test="following-sibling::SHOPITEM[PRODUCT=$currentProduct]">
<xsl:apply-templates select="following-sibling::SHOPITEM
[PRODUCT=$currentProduct]" mode="variant"/>
</xsl:if>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM" mode="variant">
<xsl:variable name="currentProduct" select="PRODUCT"/>
<PRODUCT_VARIANT>
<xsl:attribute name="id">
<xsl:value-of select="count(preceding-sibling::SHOPITEM/PRODUCT
[.=$currentProduct]) + 1"/>
</xsl:attribute>
<xsl:apply-templates/>
</PRODUCT_VARIANT>
</xsl:template>
<xsl:template match="SHOPITEM[PRODUCT=preceding-sibling::SHOPITEM/PRODUCT]"/>
</xsl:transform>
当应用于您的输入时 XML 会生成所需的输出。
模板
<xsl:template match="SHOPITEM[not(PRODUCT=preceding-sibling::SHOPITEM/PRODUCT)]">
复制所有 SHOPITEM
个节点,这些节点有一个 PRODUCT
个子节点,该子节点不是前面商店商品的子节点。如果此 SHOPITEM
有以下具有相同 PRODUCT
的兄弟姐妹
<xsl:if test="following-sibling::SHOPITEM[PRODUCT=$currentProduct]">
使用
将这些复制为变体
<xsl:template match="SHOPITEM" mode="variant">
此模板创建元素 <PRODUCT_VARIANT>
并将与当前 SHOPITEM
+ 1 的产品具有相同值的所有前面产品的计数设置为属性 id
:
<xsl:value-of select="count(preceding-sibling::SHOPITEM/PRODUCT
[.=$currentProduct]) + 1"/>
模板匹配
<xsl:template match="SHOPITEM[PRODUCT=preceding-sibling::SHOPITEM/PRODUCT]"/>
为空,移除SHOPITEM
个已经写成变体的节点。
更新: 对于评论中的问题,是否可以将 CODE
作为 PRIMARY_CODE
添加到每个变体 - 按照调整后的 XSLT
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" doctype-public="XSLT-compat"
omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM[not(PRODUCT=preceding-sibling::SHOPITEM/PRODUCT)]">
<xsl:variable name="currentProduct" select="PRODUCT"/>
<xsl:variable name="currentCode" select="CODE"/>
<xsl:copy>
<xsl:apply-templates/>
<xsl:if test="following-sibling::SHOPITEM[PRODUCT=$currentProduct]">
<xsl:apply-templates select="following-sibling::SHOPITEM
[PRODUCT=$currentProduct]" mode="variant">
<xsl:with-param name="code" select="$currentCode"/>
</xsl:apply-templates>
</xsl:if>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM" mode="variant">
<xsl:param name="code"/>
<xsl:variable name="currentProduct" select="PRODUCT"/>
<PRODUCT_VARIANT>
<xsl:attribute name="id">
<xsl:value-of select="count(preceding-sibling::SHOPITEM/PRODUCT
[.=$currentProduct]) + 1"/>
</xsl:attribute>
<PRIMARY_CODE>
<xsl:value-of select="$code"/>
</PRIMARY_CODE>
<xsl:apply-templates/>
</PRODUCT_VARIANT>
</xsl:template>
<xsl:template match="SHOPITEM[PRODUCT=preceding-sibling::SHOPITEM/PRODUCT]"/>
</xsl:transform>
生成所需的输出,只是相关部分:
<PRODUCT_VARIANT id="2">
<PRIMARY_CODE>032,00</PRIMARY_CODE>
<CATEGORY>Full</CATEGORY>
...
调整只是在模板匹配SHOPITEM
中设置<xsl:variable name="currentCode" select="CODE"/>
,然后应用模板mode="variant"
,参数为currentCode
:
<xsl:apply-templates select="following-sibling::SHOPITEM
[PRODUCT=$currentProduct]" mode="variant">
<xsl:with-param name="code" select="$currentCode"/>
</xsl:apply-templates>
在<xsl:template match="SHOPITEM" mode="variant">
中参数添加为<xsl:param name="code"/>
并简单写为
<PRIMARY_CODE><xsl:value-of select="$code"/></PRIMARY_CODE>
在 <PRODUCT_VARIANT>
.
之后
为了方便起见,我把这个保存在这里:http://xsltransform.net/bFDb2Cd
这是另一个使用 xsl:key
...
的选项
XML 输入
<SHOP>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,00</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,99</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>red / green</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
</SHOP>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="products" match="SHOPITEM" use="PRODUCT"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/SHOP">
<xsl:copy>
<xsl:for-each select="SHOPITEM[generate-id() = generate-id(key('products',PRODUCT)[1])]">
<SHOPITEM>
<xsl:for-each select="/*/SHOPITEM[key('products',PRODUCT)]">
<xsl:apply-templates select="."/>
</xsl:for-each>
</SHOPITEM>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM[position()=1]">
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
<xsl:template match="SHOPITEM">
<PRODUCT_VARIANT>
<xsl:attribute name="id">
<xsl:number/>
</xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</PRODUCT_VARIANT>
</xsl:template>
</xsl:stylesheet>
XML输出
<SHOP>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,00</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL/>
<IMGURL1/>
<IMGURL2/>
<IMGURL3/>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
<PRODUCT_VARIANT id="2">
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,99</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>red / green</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL/>
<IMGURL1/>
<IMGURL2/>
<IMGURL3/>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</PRODUCT_VARIANT>
<PRODUCT_VARIANT id="3">
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL/>
<IMGURL1/>
<IMGURL2/>
<IMGURL3/>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</PRODUCT_VARIANT>
</SHOPITEM>
</SHOP>
这与您想要的输出不同,因为它包含变体的 SHOPITEM
的所有原始子项。这里有一个修改版本,只保留与组中第一个SHOPITEM
不同的元素:
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="products" match="SHOPITEM" use="PRODUCT"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/SHOP">
<xsl:copy>
<xsl:for-each select="SHOPITEM[generate-id() = generate-id(key('products',PRODUCT)[1])]">
<SHOPITEM>
<xsl:for-each select="/*/SHOPITEM[key('products',PRODUCT)]">
<xsl:apply-templates select="."/>
</xsl:for-each>
</SHOPITEM>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM[position()=1]">
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
<xsl:template match="SHOPITEM">
<PRODUCT_VARIANT>
<xsl:attribute name="id">
<xsl:number/>
</xsl:attribute>
<xsl:apply-templates select="*" mode="variant"/>
</PRODUCT_VARIANT>
</xsl:template>
<xsl:template match="SHOPITEM/*" mode="variant">
<xsl:if test="not(key('products',../PRODUCT)[1]/*[name()=name(current())]=.)">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
XML输出
<SHOP>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,00</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL/>
<IMGURL1/>
<IMGURL2/>
<IMGURL3/>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
<PRODUCT_VARIANT id="2">
<CODE>032,99</CODE>
<COLOR>red / green</COLOR>
</PRODUCT_VARIANT>
<PRODUCT_VARIANT id="3">
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
</PRODUCT_VARIANT>
</SHOPITEM>
</SHOP>
这是我的 XML 文件中的一个片段,每个产品都是独立的 <SHOPITEM>
:
<?xml version="1.0" encoding="UTF-8"?>
<SHOP>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,00</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,99</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>red / green</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
</SHOP>
可以在同一个 <PRODUCT>
上对产品选项进行分组,如下所示:
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
<PRODUCT_VARIANT id="2">
<COLOR>red / green</COLOR>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,99</CODE>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<AVAILABLE>NO</AVAILABLE>
<NOTE>Available 15.2.2015</NOTE>
</PRODUCT_VARIANT>
<PRODUCT_VARIANT id="3">
<COLOR>black / white</COLOR>
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<AVAILABLE>NO</AVAILABLE>
<NOTE>Available 15.2.2015</NOTE>
</PRODUCT_VARIANT>
</SHOPITEM>
注意:这是基于这样的假设,即应根据 <PRODUCT>
子节点的相同值对商店商品进行分组。如果必须比较其他节点值,请将其添加到问题中。
以下 XSLT
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" doctype-public="XSLT-compat"
omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM[not(PRODUCT=preceding-sibling::SHOPITEM/PRODUCT)]">
<xsl:variable name="currentProduct" select="PRODUCT"/>
<xsl:copy>
<xsl:apply-templates/>
<xsl:if test="following-sibling::SHOPITEM[PRODUCT=$currentProduct]">
<xsl:apply-templates select="following-sibling::SHOPITEM
[PRODUCT=$currentProduct]" mode="variant"/>
</xsl:if>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM" mode="variant">
<xsl:variable name="currentProduct" select="PRODUCT"/>
<PRODUCT_VARIANT>
<xsl:attribute name="id">
<xsl:value-of select="count(preceding-sibling::SHOPITEM/PRODUCT
[.=$currentProduct]) + 1"/>
</xsl:attribute>
<xsl:apply-templates/>
</PRODUCT_VARIANT>
</xsl:template>
<xsl:template match="SHOPITEM[PRODUCT=preceding-sibling::SHOPITEM/PRODUCT]"/>
</xsl:transform>
当应用于您的输入时 XML 会生成所需的输出。
模板
<xsl:template match="SHOPITEM[not(PRODUCT=preceding-sibling::SHOPITEM/PRODUCT)]">
复制所有 SHOPITEM
个节点,这些节点有一个 PRODUCT
个子节点,该子节点不是前面商店商品的子节点。如果此 SHOPITEM
有以下具有相同 PRODUCT
<xsl:if test="following-sibling::SHOPITEM[PRODUCT=$currentProduct]">
使用
将这些复制为变体<xsl:template match="SHOPITEM" mode="variant">
此模板创建元素 <PRODUCT_VARIANT>
并将与当前 SHOPITEM
+ 1 的产品具有相同值的所有前面产品的计数设置为属性 id
:
<xsl:value-of select="count(preceding-sibling::SHOPITEM/PRODUCT
[.=$currentProduct]) + 1"/>
模板匹配
<xsl:template match="SHOPITEM[PRODUCT=preceding-sibling::SHOPITEM/PRODUCT]"/>
为空,移除SHOPITEM
个已经写成变体的节点。
更新: 对于评论中的问题,是否可以将 CODE
作为 PRIMARY_CODE
添加到每个变体 - 按照调整后的 XSLT
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" doctype-public="XSLT-compat"
omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM[not(PRODUCT=preceding-sibling::SHOPITEM/PRODUCT)]">
<xsl:variable name="currentProduct" select="PRODUCT"/>
<xsl:variable name="currentCode" select="CODE"/>
<xsl:copy>
<xsl:apply-templates/>
<xsl:if test="following-sibling::SHOPITEM[PRODUCT=$currentProduct]">
<xsl:apply-templates select="following-sibling::SHOPITEM
[PRODUCT=$currentProduct]" mode="variant">
<xsl:with-param name="code" select="$currentCode"/>
</xsl:apply-templates>
</xsl:if>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM" mode="variant">
<xsl:param name="code"/>
<xsl:variable name="currentProduct" select="PRODUCT"/>
<PRODUCT_VARIANT>
<xsl:attribute name="id">
<xsl:value-of select="count(preceding-sibling::SHOPITEM/PRODUCT
[.=$currentProduct]) + 1"/>
</xsl:attribute>
<PRIMARY_CODE>
<xsl:value-of select="$code"/>
</PRIMARY_CODE>
<xsl:apply-templates/>
</PRODUCT_VARIANT>
</xsl:template>
<xsl:template match="SHOPITEM[PRODUCT=preceding-sibling::SHOPITEM/PRODUCT]"/>
</xsl:transform>
生成所需的输出,只是相关部分:
<PRODUCT_VARIANT id="2">
<PRIMARY_CODE>032,00</PRIMARY_CODE>
<CATEGORY>Full</CATEGORY>
...
调整只是在模板匹配SHOPITEM
中设置<xsl:variable name="currentCode" select="CODE"/>
,然后应用模板mode="variant"
,参数为currentCode
:
<xsl:apply-templates select="following-sibling::SHOPITEM
[PRODUCT=$currentProduct]" mode="variant">
<xsl:with-param name="code" select="$currentCode"/>
</xsl:apply-templates>
在<xsl:template match="SHOPITEM" mode="variant">
中参数添加为<xsl:param name="code"/>
并简单写为
<PRIMARY_CODE><xsl:value-of select="$code"/></PRIMARY_CODE>
在 <PRODUCT_VARIANT>
.
为了方便起见,我把这个保存在这里:http://xsltransform.net/bFDb2Cd
这是另一个使用 xsl:key
...
XML 输入
<SHOP>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,00</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,99</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>red / green</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL></URL>
<IMGURL1></IMGURL1>
<IMGURL2></IMGURL2>
<IMGURL3></IMGURL3>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</SHOPITEM>
</SHOP>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="products" match="SHOPITEM" use="PRODUCT"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/SHOP">
<xsl:copy>
<xsl:for-each select="SHOPITEM[generate-id() = generate-id(key('products',PRODUCT)[1])]">
<SHOPITEM>
<xsl:for-each select="/*/SHOPITEM[key('products',PRODUCT)]">
<xsl:apply-templates select="."/>
</xsl:for-each>
</SHOPITEM>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM[position()=1]">
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
<xsl:template match="SHOPITEM">
<PRODUCT_VARIANT>
<xsl:attribute name="id">
<xsl:number/>
</xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</PRODUCT_VARIANT>
</xsl:template>
</xsl:stylesheet>
XML输出
<SHOP>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,00</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL/>
<IMGURL1/>
<IMGURL2/>
<IMGURL3/>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
<PRODUCT_VARIANT id="2">
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,99</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>red / green</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL/>
<IMGURL1/>
<IMGURL2/>
<IMGURL3/>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</PRODUCT_VARIANT>
<PRODUCT_VARIANT id="3">
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL/>
<IMGURL1/>
<IMGURL2/>
<IMGURL3/>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
</PRODUCT_VARIANT>
</SHOPITEM>
</SHOP>
这与您想要的输出不同,因为它包含变体的 SHOPITEM
的所有原始子项。这里有一个修改版本,只保留与组中第一个SHOPITEM
不同的元素:
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="products" match="SHOPITEM" use="PRODUCT"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/SHOP">
<xsl:copy>
<xsl:for-each select="SHOPITEM[generate-id() = generate-id(key('products',PRODUCT)[1])]">
<SHOPITEM>
<xsl:for-each select="/*/SHOPITEM[key('products',PRODUCT)]">
<xsl:apply-templates select="."/>
</xsl:for-each>
</SHOPITEM>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="SHOPITEM[position()=1]">
<xsl:apply-templates select="@*|node()"/>
</xsl:template>
<xsl:template match="SHOPITEM">
<PRODUCT_VARIANT>
<xsl:attribute name="id">
<xsl:number/>
</xsl:attribute>
<xsl:apply-templates select="*" mode="variant"/>
</PRODUCT_VARIANT>
</xsl:template>
<xsl:template match="SHOPITEM/*" mode="variant">
<xsl:if test="not(key('products',../PRODUCT)[1]/*[name()=name(current())]=.)">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
XML输出
<SHOP>
<SHOPITEM>
<CATEGORY>Full</CATEGORY>
<WHEEL>27.5</WHEEL>
<FRAMESIZE>MD</FRAMESIZE>
<CODE>032,00</CODE>
<PRODUCT>POINT</PRODUCT>
<COLOR>black / white</COLOR>
<NOTE>Available 15.2.2015</NOTE>
<URL/>
<IMGURL1/>
<IMGURL2/>
<IMGURL3/>
<PRICE>3199.99</PRICE>
<CURRENCY>EUR</CURRENCY>
<YEAR>2015</YEAR>
<AVAILABLE>NO</AVAILABLE>
<PRODUCT_VARIANT id="2">
<CODE>032,99</CODE>
<COLOR>red / green</COLOR>
</PRODUCT_VARIANT>
<PRODUCT_VARIANT id="3">
<FRAMESIZE>LG</FRAMESIZE>
<CODE>032,01</CODE>
</PRODUCT_VARIANT>
</SHOPITEM>
</SHOP>