简体   繁体   中英

xslt how to merge product nodes

i need to merge shop products which contains size in name. As you can see i have to cut size from product name and put it to new element inside group-element "SIZES", the same thing with PARTNO and STOCK which are needed to identify product, his sizes and quantity. I created some xslt with template and foreach loop but i dont know how to verify if some node was created before.

Its very important for me because xslt is my new resposibility in my job, im new with xslt so my code is very simple and ugly.

here is example xml:

    <?xml version="1.0" encoding="Windows-1250"?>
    <SHOP xmlns="http://www.b2b.abisaltest.pl">
       <SHOPITEM>
          <PRODUCT>ZBRS180 CZERWONA BRAMKA PIŁKARSKA</PRODUCT>
          <PRICE>167.01</PRICE>
          <PARTNO>5907695527654</PARTNO>
          <STOCK>177</STOCK>
       </SHOPITEM>
       <SHOPITEM>
          <PRODUCT>NJ2117 A NIEBIESKO-RÓŻOWE SIZE. M (34-37)  ŁYŻWOROLKI NILS 
           EXTREME</PRODUCT>
          <PRICE>113.01</PRICE>
          <PARTNO>5907695510333</PARTNO>
          <STOCK>158</STOCK>
       </SHOPITEM>
       <SHOPITEM>
          <PRODUCT>NJ2117 A NIEBIESKO-RÓŻOWE SIZE. L (38-41)  ŁYŻWOROLKI NILS 
          EXTREME</PRODUCT>
          <PRICE>113.01</PRICE>
          <PARTNO>5907695510334</PARTNO>
          <STOCK>35</STOCK>
       </SHOPITEM>
    </SHOP>

**Output file should looks like that:**

    <?xml version="1.0" encoding="Windows-1250"?>
    <SHOP>
       <SHOPITEM>
          <PRODUCT>ZBRS180 CZERWONA BRAMKA PIŁKARSKA</PRODUCT>
          <PRICE>167.01</PRICE>
          <PARTNO>5907695527654</PARTNO>
          <STOCK>177</STOCK>
       </SHOPITEM>
       <SHOPITEM>
          <PRODUCT>NJ2117 A NIEBIESKO-RÓŻOWE ŁYŻWOROLKI NILS EXTREME</PRODUCT>
          <SIZES>
             <SIZE>M (34-37)</SIZE>
             <SIZE>L (38-41)</SIZE>
          </SIZES>
          <PARTNOS>
            <PARTNO>5907695510333</PARTNO>
            <PARTNO>5907695510334</PARTNO>
          </PARTNOS>
          <STOCKS>
            <STOCK>158</STOCK>
            <STOCK>35</STOCK>
          </STOCKS>
          <PRICE>113.01</PRICE>
       </SHOPITEM>
</SHOP>

Here is my xsl code:

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:abi="http://www.b2b.abisaltest.pl">
<xsl:output method="xml" indent="yes" version="1.0" encoding="iso-8859-2"/>


      <xsl:template match="abi:SHOP">
        <xsl:element name="SHOP">
        <xsl:apply-templates select="abi:SHOPITEM">
          <xsl:with-param name="pNodeset" select="abi:SHOPITEM"/>
        </xsl:apply-templates>
        </xsl:element>
      </xsl:template>




<xsl:template match="abi:SHOPITEM">
    <xsl:param name="pNodeset" />
    <xsl:element name="SHOPITEM" >
        <xsl:choose>
            <xsl:when test="contains(abi:PRODUCT/text(), 'SIZE.')">
                <!-- Creating variable with node name -->
                <xsl:variable name="currentCuttedNodeName">
                    <xsl:value-of select="substring-before(abi:PRODUCT/text(), 'SIZE.')"/>
                </xsl:variable>
                <!-- Looking for SIZES -->
                <xsl:element name="SIZES">
                    <xsl:for-each select="$pNodeset">
                        <xsl:if test="contains(abi:PRODUCT/text(), $currentCuttedNodeName)">
                            <xsl:element name="SIZE">
                                <xsl:choose>
                                    <xsl:when test="contains(abi:PRODUCT/text(),')')">
                                        <xsl:variable name="from">
                                            <xsl:value-of select="string-length(substring-before(abi:PRODUCT/text(), '('))+1"/>
                                        </xsl:variable>
                                        <xsl:variable name="to">
                                            <xsl:value-of select="string-length(substring-before(abi:PRODUCT/text(), ')'))"/>
                                        </xsl:variable>
                                        <xsl:value-of select="substring(abi:PRODUCT/text(),$from,7)"/>
                                    </xsl:when>
                                    <xsl:otherwise>
                                        <xsl:variable name="from">
                                            <xsl:value-of select="string-length(substring-before(abi:PRODUCT/text(), 'SIZE.'))"/>
                                        </xsl:variable>
                                        <xsl:value-of select="substring(abi:PRODUCT/text(),$from+7, 2)"/>
                                    </xsl:otherwise>
                                </xsl:choose>
                            </xsl:element>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:element>
                <!-- Looking for EANS -->
                <xsl:element name="EANS">
                    <xsl:for-each select="$pNodeset">
                        <xsl:if test="contains(abi:PRODUCT/text(), $currentCuttedNodeName)">
                            <xsl:element name="EAN">
                                <xsl:value-of select="abi:PARTNO/text()"/>
                            </xsl:element>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:element>
                <!-- Looking for external codes -->
                <xsl:element name="CODES">
                    <xsl:for-each select="$pNodeset">
                        <xsl:if test="contains(abi:PRODUCT/text(), $currentCuttedNodeName)">
                            <xsl:element name="CODE">
                                <xsl:value-of select="abi:PRODUCTNO/text()"/>
                            </xsl:element>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:element>
                <!-- Looking for stocks -->
                <xsl:element name="STOCKS">
                    <xsl:for-each select="$pNodeset">
                        <xsl:if test="contains(abi:PRODUCT/text(), $currentCuttedNodeName)">
                            <xsl:element name="STOCK">
                                <xsl:value-of select="abi:STOCK/text()"/>
                            </xsl:element>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:element>
                <xsl:element name="NAME">
                                <xsl:choose>
                                    <xsl:when test="contains(abi:PRODUCT/text(),')')">
                                        <xsl:variable name="from">
                                            <xsl:value-of select="string-length(substring-before(abi:PRODUCT/text(), 'SIZE.'))"/>
                                        </xsl:variable>
                                        <xsl:variable name="to">
                                            <xsl:value-of select="string-length(substring-before(abi:PRODUCT/text(), ')'))"/>
                                        </xsl:variable>
                                        <xsl:variable name="firstPart">
                                            <xsl:value-of select="substring-before(abi:PRODUCT/text(),'SIZE.')"/>
                                        </xsl:variable>
                                        <xsl:variable name="secondPart">
                                            <xsl:value-of select="substring-after(abi:PRODUCT/text(),')')"/>
                                        </xsl:variable>
                                        <xsl:value-of select="concat($firstPart,$secondPart)"/>
                                    </xsl:when>
                                    <xsl:otherwise>
                                        <xsl:variable name="firstPart">
                                            <xsl:value-of select="substring-before(abi:PRODUCT/text(), 'SIZE.')"/>
                                        </xsl:variable>
                                        <xsl:variable name="fromNumber">
                                            <xsl:value-of select="string-length(substring-after(abi:PRODUCT/text(), 'SIZE.')) +10"/>
                                        </xsl:variable>
                                        <xsl:variable name="secondPart">
                                            <xsl:value-of select="substring(abi:PRODUCT/text(), $fromNumber, string-length(abi:PRODUCT/text()) - $fromNumber)"/>
                                        </xsl:variable>
                                        <xsl:value-of select="concat($firstPart, $secondPart)"/>
                                    </xsl:otherwise>
                                </xsl:choose>
                </xsl:element>
                <xsl:element name="ID">
                    <xsl:value-of select="position()"/>
                </xsl:element>
                <xsl:element name="DESC">
                    <xsl:value-of select="abi:DESCRIPTION/text()"/>
                </xsl:element>
                <xsl:element name="IMGURL">
                    <xsl:value-of select="abi:IMGURL"/>
                </xsl:element>
                <xsl:element name="BRAND">
                    <xsl:value-of select="abi:BRAND"/>
                </xsl:element>
            </xsl:when>
            <xsl:otherwise>
                <!-- Filling elements to no size item -->
                <xsl:element name="SIZES">
                    <xsl:element name="SIZE">
                        <xsl:value-of select="'Uniwersalny'"/>
                    </xsl:element>
                </xsl:element>
                <xsl:element name="EANS">
                    <xsl:element name="EAN">
                        <xsl:value-of select="abi:PARTNO/text()"/>
                    </xsl:element>
                </xsl:element>
                <xsl:element name="CODES">
                    <xsl:element name="CODE">
                        <xsl:value-of select="abi:PRODUCTNO/text()"/>
                    </xsl:element>
                </xsl:element>
                <xsl:element name="STOCKS">
                    <xsl:element name="STOCK">
                        <xsl:value-of select="abi:STOCK/text()"/>
                    </xsl:element>
                </xsl:element>
                <xsl:element name="NAME">
                    <xsl:value-of select="abi:PRODUCT/text()"/>
                </xsl:element>
                <xsl:element name="ID">
                    <xsl:value-of select="position()"/>
                </xsl:element>
                <xsl:element name="DESC">
                    <xsl:value-of select="abi:DESCRIPTION/text()"/>
                </xsl:element>
                <xsl:element name="IMGURL">
                    <xsl:value-of select="abi:IMGURL"/>
                </xsl:element>
                <xsl:element name="BRAND">
                    <xsl:value-of select="abi:BRAND"/>
                </xsl:element>
            </xsl:otherwise>
        </xsl:choose>
      </xsl:element>
</xsl:template>

</xsl:transform>

You can try this:

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:abi="http://www.b2b.abisaltest.pl"
exclude-result-prefixes="abi">
<xsl:output method="xml" indent="yes" version="1.0" encoding="iso-8859-2"/>

<xsl:key name="qualifierKey" match="/abi:SHOP/abi:SHOPITEM" use="concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')'))" />

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

<xsl:template match="abi:SHOP">
    <xsl:element name="SHOP">
        <xsl:for-each select="abi:SHOPITEM[generate-id(.) = generate-id(key('qualifierKey', concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')')))[1])]">
            <xsl:apply-templates select="." />
        </xsl:for-each>
    </xsl:element>
</xsl:template>

<xsl:template match="abi:SHOPITEM">
    <SHOPITEM>
        <xsl:choose>
            <xsl:when test="contains(abi:PRODUCT, 'SIZE.')">
                <xsl:element name="PRODUCT">
                    <xsl:value-of select="concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')'))" />
                </xsl:element>      

                <!-- Looking for SIZES -->
                <xsl:element name="SIZES">
                    <xsl:for-each select="key('qualifierKey', concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')')))">
                        <xsl:element name="SIZE">
                            <xsl:value-of select="normalize-space(concat(substring-after(substring-before(abi:PRODUCT,')'),'SIZE.'), ')'))" />
                        </xsl:element>
                    </xsl:for-each>
                </xsl:element>

                <!-- Looking for EANS -->
                <xsl:element name="PARTNOS">
                    <xsl:for-each select="key('qualifierKey', concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')')))">
                        <xsl:if test="abi:PARTNO != ''">
                            <xsl:element name="PARTNO">
                                <xsl:value-of select="abi:PARTNO/text()" />
                            </xsl:element>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:element>

                <!-- Looking for stocks -->
                <xsl:element name="STOCKS">
                    <xsl:for-each select="key('qualifierKey', concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')')))">
                        <xsl:if test="abi:STOCK != ''">
                            <xsl:element name="STOCK">
                                <xsl:value-of select="abi:STOCK/text()" />
                            </xsl:element>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:element>

                <!-- Looking for external codes -->
                <xsl:element name="CODES">
                    <xsl:for-each select="key('qualifierKey', concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')')))">
                        <xsl:if test="abi:PRODUCTNO != ''">
                            <xsl:element name="CODE">
                                <xsl:value-of select="abi:PRODUCTNO/text()" />
                            </xsl:element>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:element>
                <xsl:element name="PRICE">
                    <xsl:value-of select="abi:PRICE" />
                </xsl:element>
                <xsl:element name="ID">
                    <xsl:value-of select="position()" />
                </xsl:element>
                <xsl:element name="DESC">
                    <xsl:value-of select="abi:DESCRIPTION/text()" />
                </xsl:element>
                <xsl:element name="IMGURL">
                    <xsl:value-of select="abi:IMGURL" />
                </xsl:element>
                <xsl:element name="BRAND">
                    <xsl:value-of select="abi:BRAND" />
                </xsl:element>
            </xsl:when>
            <xsl:otherwise>
                <xsl:element name="PRODUCT">
                    <xsl:value-of select="abi:PRODUCT/text()" />
                </xsl:element>
                <xsl:element name="PRICE">
                    <xsl:value-of select="abi:PRICE" />
                </xsl:element>
                <xsl:element name="PARTNO">
                    <xsl:value-of select="abi:PARTNO/text()" />
                </xsl:element>
                <xsl:element name="STOCK">
                    <xsl:value-of select="abi:STOCK/text()" />
                </xsl:element>
                <xsl:element name="SIZE">
                    <xsl:value-of select="'Uniwersalny'" />
                </xsl:element>
                <xsl:element name="CODE">
                    <xsl:value-of select="abi:PRODUCTNO/text()" />
                </xsl:element>
                <xsl:element name="ID">
                    <xsl:value-of select="position()" />
                </xsl:element>
                <xsl:element name="DESC">
                    <xsl:value-of select="abi:DESCRIPTION/text()" />
                </xsl:element>
                <xsl:element name="IMGURL">
                    <xsl:value-of select="abi:IMGURL" />
                </xsl:element>
                <xsl:element name="BRAND">
                    <xsl:value-of select="abi:BRAND" />
                </xsl:element>
            </xsl:otherwise>
        </xsl:choose>
    </SHOPITEM>
</xsl:template>

</xsl:transform>

http://xsltfiddle.liberty-development.net/gWvjQfg

This is not exactly simple - but I think it could be much simpler than what you're trying to do:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:abi="http://www.b2b.abisaltest.pl"
exclude-result-prefixes="abi">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="item" match="abi:SHOPITEM" use="substring-before(abi:PRODUCT, ' ')" />

<xsl:template match="/abi:SHOP">
    <SHOP>
        <!-- MUENCHIAN GROUPING -->
        <xsl:for-each select="abi:SHOPITEM[count(. | key('item', substring-before(abi:PRODUCT, ' '))[1]) = 1]">
            <xsl:variable name="current-group" select="key('item', substring-before(abi:PRODUCT, ' '))" />
            <xsl:choose>
                <xsl:when test="count($current-group) > 1">
                    <SHOPITEM>
                        <PRODUCT>
                            <xsl:value-of select="substring-before(abi:PRODUCT, 'SIZE.')"/>
                            <xsl:value-of select="substring-after(substring-after(abi:PRODUCT, 'SIZE. '), ')')"/>                                                   
                        </PRODUCT>
                        <SIZES>
                            <xsl:for-each select="$current-group">
                                <SIZE>
                                    <xsl:value-of select="substring-before(substring-after(abi:PRODUCT, 'SIZE. '), ')')"/>
                                    <xsl:text>)</xsl:text>
                                </SIZE>
                            </xsl:for-each>
                        </SIZES>
                        <PARTNOS>
                            <xsl:apply-templates select="$current-group/abi:PARTNO"/>
                        </PARTNOS>
                        <STOCKS>
                            <xsl:apply-templates select="$current-group/abi:STOCK"/>
                        </STOCKS>
                     </SHOPITEM>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="$current-group"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </SHOP>
</xsl:template>

<xsl:template match="abi:*">
    <xsl:element name="{local-name()}">
        <xsl:apply-templates/>
     </xsl:element>
</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