Match and Merge in XSLT 1.0

2019-09-11 05:18发布

问题:

I have a sample XML message which contains multiple parent node. The requirement is something like if the two parent node are same, merge the child node.

Sample Input Message is

<document>
<party>
    <gtin>1000909090</gtin>
    <pos>
        <attrGroupMany name="temperatureInformation">
            <row>
                <attr name="temperatureCode">STORAGE</attr>
                <attrQualMany name="temperature">
                    <value qual="FAH">10</value>
                    <value qual="CC">20</value>
                </attrQualMany>
                <attrGroupMany name="temperatureStats">
                    <row>
                        <attr name="StatsCode">CODE1</attr>
                    </row>
                    <row>
                        <attr name="StatsCode">CODE2</attr>
                    </row>
                </attrGroupMany>
            </row>
            <row>
                <attr name="temperatureCode">STORAGE</attr>
                <attrQualMany name="temperature">
                    <value qual="FAH">10</value>
                    <value qual="CC">20</value>
                </attrQualMany>
                <attrGroupMany name="temperatureStats">
                    <row>
                        <attr name="StatsCode">CODE3</attr>
                    </row>
                    <row>
                        <attr name="StatsCode">CODE4</attr>
                    </row>
                </attrGroupMany>
            </row>
            <row>
                <attr name="temperatureCode">HANDLING</attr>
                <attrQualMany name="temperature">
                    <value qual="FAH">10</value>                    
                </attrQualMany>
                <attrGroupMany name="temperatureStats">
                    <row>
                        <attr name="StatsCode">CODE5</attr>
                    </row>
                    <row>
                        <attr name="StatsCode">CODE6</attr>
                    </row>
                </attrGroupMany>
            </row>
            <row>
                <attr name="temperatureCode">HANDLING</attr>
                <attrGroupMany name="temperatureStats">
                    <row>
                        <attr name="StatsCode">CODE7</attr>
                    </row>
                    <row>
                        <attr name="StatsCode">CODE8</attr>
                    </row>
                </attrGroupMany>
            </row>
        </attrGroupMany>
    </pos>
</party>
</document>

we need to concat the value of temperatureCode, All value of temperature (if present) for all row and if they are duplicate, then merge the row inside temperatureStats of the child in the parent.

Expected output is in the same structure. You can see the second node is merged with first

<document>
<party>
    <gtin>1000909090</gtin>
    <pos>
        <attrGroupMany name="temperatureInformation">
            <row>
                <attr name="temperatureCode">STORAGE</attr>
                <attrQualMany name="temperature">
                    <value qual="FAH">10</value>
                    <value qual="CC">20</value>
                </attrQualMany>
                <attrGroupMany name="temperatureStats">
                    <row>
                        <attr name="StatsCode">CODE1</attr>
                    </row>
                    <row>
                        <attr name="StatsCode">CODE2</attr>
                    </row>
                    <row>
                        <attr name="StatsCode">CODE3</attr>
                    </row>
                    <row>
                        <attr name="StatsCode">CODE4</attr>
                    </row>
                </attrGroupMany>
            </row>
            <row>
                <attr name="temperatureCode">HANDLING</attr>
                <attrQualMany name="temperature">
                    <value qual="FAH">10</value>                    
                </attrQualMany>
                <attrGroupMany name="temperatureStats">
                    <row>
                        <attr name="StatsCode">CODE5</attr>
                    </row>
                    <row>
                        <attr name="StatsCode">CODE6</attr>
                    </row>
                </attrGroupMany>
            </row>
            <row>
                <attr name="temperatureCode">HANDLING</attr>
                <attrGroupMany name="temperatureStats">
                    <row>
                        <attr name="StatsCode">CODE7</attr>
                    </row>
                    <row>
                        <attr name="StatsCode">CODE8</attr>
                    </row>
                </attrGroupMany>
            </row>
        </attrGroupMany>
    </pos>
</party>
</document>

Any input will be very valuable.

回答1:

I think you got a solution to group in a previous answer https://stackoverflow.com/a/38240246/252228, you can then process the items in a group calling the key function:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:output indent="yes"/>


    <xsl:key name="group" match="attrGroupMany[@name = 'temperatureInformation']/row"
        use="concat(attr[@name = 'temperatureCode'], '|', attrQualMany[@name = 'temperature'])"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="attrGroupMany[@name = 'temperatureInformation']">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="row[generate-id() = generate-id(key('group', concat(attr[@name = 'temperatureCode'], '|', attrQualMany[@name = 'temperature']))[1])]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="attrGroupMany[@name = 'temperatureStats']">
        <xsl:copy>
            <xsl:apply-templates select="@* | key('group', concat(../attr[@name = 'temperatureCode'], '|', ../attrQualMany[@name = 'temperature']))/attrGroupMany[@name = 'temperatureStats']/row"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Note however that the whole approach of taking the string value of an element with varying child elements is brittle, if there is a difference in white space the value might be considered different.