match and merge in XSLT with optional nodes

本秂侑毒 提交于 2019-12-18 09:44:33

问题


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


回答1:


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>



回答2:


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


来源:https://stackoverflow.com/questions/38993864/match-and-merge-in-xslt-with-optional-nodes

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!