简体   繁体   中英

match and merge in XSLT with optional nodes

I have a sample XML message which contains multiple parent node. The requirement is if the two parent node are same, merge the child node. This works fine when all the nodes are present but doesn't work when the optional node is absent

Sample Message:1 With Optional Nodes present

<document>
<body>
    <party>
        <gtin>1000909090</gtin>
        <pos>
            <attrGroupMany name="temperatureInformation">
                <row>
                    <gtin>1000909090</gtin>
                    <attr name="temperatureCode">STORAGE</attr>
                    <attrQualMany name="temperature">
                        <value qual="FAH">10</value>
                        <value qual="CC">20</value>
                    </attrQualMany>
                    <attrGroupMany name="temperatureStats">   <!--  optional group -->
                        <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">    <!--  optional group -->
                        <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">    <!--  optional group -->
                        <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">      <!--  optional group -->
                        <row>
                            <attr name="StatsCode">CODE7</attr>
                        </row>
                        <row>
                            <attr name="StatsCode">CODE8</attr>
                        </row>
                    </attrGroupMany>
                </row>
            </attrGroupMany>
        </pos>
    </party>    
</body>
</document>

The below sample XSLT works fine to remove the duplicate from 'attrGroupMany name="temperatureInformation" '

XSLT used

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">



<xsl:key name="group" match="party/pos/attrGroupMany[@name = 'temperatureInformation']/row"
    use="concat(generate-id(ancestor::pos), '|', 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(generate-id(ancestor::pos), '|', 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(generate-id(ancestor::pos), '|',../attr[@name = 'temperatureCode'], '|', ../attrQualMany[@name = 'temperature']))/attrGroupMany[@name = 'temperatureStats']/row"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Sample Message 2 which doesnt work with above XSLT is

<document>
<body>
    <party>
        <gtin>1000909090</gtin>
        <pos>
            <attrGroupMany name="temperatureInformation">
                <row>
                    <gtin>1000909090</gtin>
                    <attr name="temperatureCode">STORAGE</attr>
                    <attrQualMany name="temperature">
                        <value qual="FAH">10</value>
                        <value qual="CC">20</value>
                    </attrQualMany>
                </row>
                <row>
                    <attr name="temperatureCode">STORAGE</attr>
                    <attrQualMany name="temperature">
                        <value qual="FAH">10</value>
                        <value qual="CC">20</value>
                    </attrQualMany>
                    <attrGroupMany name="temperatureStats">    <!--  optional group -->
                        <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">    <!--  optional group -->
                        <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">      <!--  optional group -->
                        <row>
                            <attr name="StatsCode">CODE7</attr>
                        </row>
                        <row>
                            <attr name="StatsCode">CODE8</attr>
                        </row>
                    </attrGroupMany>
                </row>
            </attrGroupMany>
        </pos>
    </party>    
</body>
</document>

Can someone please let me know how to handle optional node in match n merge

The expected output for sample message 2 is

<?xml version="1.0" encoding="UTF-8"?>
<document>
<body>
  <party>
     <gtin>1000909090</gtin>
     <pos>
        <attrGroupMany name="temperatureInformation">
           <row>
              <gtin>1000909090</gtin>
              <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>
</body>
</document>

Can someone please let me know how to handle optional node in match n merge. Thanks

You haven't explained the logic behind what you are trying to do, but from looking at the XSLT from this question, and previous questions too, you are grouping the attrGroupMany[@name = 'temperatureInformation']/row elements but a concatenation of the ancestor pos together with "temperatureCode" and "temperature".

Then for each such distinct row it looks like you want to add in all the <attrGroupMany name="temperatureStats"> elements. Having a template matching this element is not going to work if you say it is optional. Instead, have a template matching the parent row and use that to select all the child elements from all elements in the keys.

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

I am assuming all the StatsCode are distinct here. If there could be duplicated, and you want to remove such duplicates, you need to say so in your question.

Try this XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="xml" indent="yes" />

<xsl:key name="group" match="party/pos/attrGroupMany[@name = 'temperatureInformation']/row"
    use="concat(generate-id(ancestor::pos), '|', 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(generate-id(ancestor::pos), '|', attr[@name = 'temperatureCode'], '|', attrQualMany[@name = 'temperature']))[1])]"/>
    </xsl:copy>
</xsl:template>

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

</xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"    version="1.0">

<xsl:output method="xml" indent="yes" />

<xsl:key name="grouptemperatureInformation" match="party/pos/attrGroupMany[@name = 'temperatureInformation']/row"
use="concat(generate-id(ancestor::pos), '|', attr[@name = 'temperatureCode'], '|', attrQualMany[@name = 'temperature'])"/>

<xsl:key name="grouptemperatureStats" 
         match="party/pos/attrGroupMany[@name = 'temperatureInformation']/row/attrGroupMany[@name = 'temperatureStats']/row"
         use="concat(generate-id(ancestor::pos), '|', ../../../attr[@name = 'temperatureCode'], '|', ../../../attrQualMany[@name = 'temperature'], '|', attr[@name = 'StatsCode'])"/>


<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('grouptemperatureInformation', concat(generate-id(ancestor::pos), '|', attr[@name = 'temperatureCode'], '|', attrQualMany[@name = 'temperature']))[1])]"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="attrGroupMany[@name = 'temperatureInformation']/row">
    <xsl:variable name="group" select="key('grouptemperatureInformation', concat(generate-id(ancestor::pos), '|', attr[@name = 'temperatureCode'], '|', attrQualMany[@name = 'temperature']))/attrGroupMany[@name='temperatureStats']/row" />
    <xsl:copy>
        <xsl:apply-templates select="@*|node()[not(self::attrGroupMany[@name = 'temperatureStats'])]"/> 
        <attrGroupMany name="temperatureStats">             
            <xsl:apply-templates select="@* | $group[generate-id() = generate-id(key('grouptemperatureStats', concat(generate-id(ancestor::pos), '|', ../../../attr[@name = 'temperatureCode'], '|', ../../../attrQualMany[@name = 'temperature'], '|', attr[@name = 'StatsCode']))[1])]"/> 
        </attrGroupMany>
    </xsl:copy>
 </xsl:template>
 </xsl:stylesheet>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM