#xml #xslt
#xml #xslt
Вопрос:
У меня есть XML-файл, содержащий несколько узлов продукта, который содержит элементы Amount. Если обнаружены повторяющиеся элементы, то мне нужно пропустить этот элемент и суммировать сумму с уже существующим элементом.
Это XML-код, в котором я хочу объединить сумму на основе названия продукта и идентификатора.
<List>
<ProductCatList>
<ProductCatListListID identity="new"/>
<ProductCategory name="abc">
<Product name="plastic">
<ProductID identity="prod"/>
<Amount value="3"/>
</Product>
</ProductCategory>
</ProductCatList>
<ProductCatList>
<ProductCatListListID identity="new"/>
<ProductCategory name="pqrs">
<Product name="other">
<ProductID identity="test"/>
<Amount value="58"/>
</Product>
</ProductCategory>
</ProductCatList>
<ProductCatList>
<ProductCatListListID identity="new"/>
<ProductCategory name="xyz">
<Product name="plastic">
<ProductID identity="prod"/>
<Amount value="6"/>
</Product>
</ProductCategory>
</ProductCatList>
</List>
Я ожидаю вывода, как показано ниже.
<List>
<ProductCatList>
<ProductCatListListID identity="new"/>
<ProductCategory name="abc">
<Product name="plastic">
<ProductID identity="prod"/>
<Amount value="9"/>
</Product>
</ProductCategory>
</ProductCatList>
<ProductCatList>
<ProductCatListListID identity="new"/>
<ProductCategory name="pqrs">
<Product name="other">
<ProductID identity="test"/>
<Amount value="58"/>
</Product>
</ProductCategory>
</ProductCatList>
</List>
Комментарии:
1. Это вопрос группировки . Выполните поиск — это, вероятно, наиболее часто задаваемый вопрос XSLT здесь. Обратите внимание, что ответы отличаются для XSLT 1.0 или 2.0.
Ответ №1:
Если вы используете версию 1.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:key name="productKey" match="/List/ProductCatList/ProductCategory/Product" use="ProductID/@identity" />
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="/List/ProductCatList">
<xsl:for-each select="ProductCategory/Product[generate-id() = generate-id(key('productKey', ProductID/@identity)[1])]">
<xsl:variable name="pkeyGroup" select="key('productKey', ProductID/@identity)" />
<ProductCatList>
<ProductCatListListID><xsl:attribute name="identity"><xsl:value-of select="../../ProductCatListListID/@identity"/></xsl:attribute>
<ProductCategory><xsl:attribute name="name"><xsl:value-of select="../@name"/></xsl:attribute>
<Product><xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
<ProductID><xsl:attribute name="identity"><xsl:value-of select="ProductID/@identity"/></xsl:attribute></ProductID>
<Amount><xsl:attribute name="value"><xsl:value-of select="sum($pkeyGroup/Amount/@value)"/></xsl:attribute></Amount>
</Product>
</ProductCategory>
</ProductCatListListID>
</ProductCatList>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Ответ №2:
В XSLT 2.0
<!-- Identical Template -->
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<!-- Grouping ProductCatList -->
<xsl:template match="List">
<xsl:copy>
<xsl:for-each-group select="ProductCatList" group-by="descendant::Product/@name">
<xsl:apply-templates/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<!-- Sum for Amount/@value -->
<xsl:template match="Amount/@value">
<xsl:attribute name="value" select="sum(//Amount[../@name = current()/../../@name]/@value)"/>
</xsl:template>
Вы можете увидеть преобразование на https://xsltfiddle.liberty-development.net/94rmq6d