Как пропустить узел в XML на основе условия и добавить это значение в узел с соответствующим условием

#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>
  

http://xsltfiddle.liberty-development.net/3NJ38Z9

Ответ №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