0

The problem, I have data that exists in XML format, however, critical pieces of data are not supplied in separate nodes. Such as an item's size, color, fitment. While I'd normally provide what I've tried, I don't even know where to start. I've found a lot of examples on how to check for if a value is found, but nothing how to take that matched value, and then return it within an element. I can only use xslt 1.0

This is a key section, I need help with, but lower in this post, I include full sample data and my current XSL Template

<partDescription>Black 10" Handlebar</partDescription>
                        <!-- Logic to Figure out Attribute Data from Names, Descriptions -->
                        <!-- If <partDescription> contains Black, Flat Back, Chrome element finish shoud return the value that is found -->

                        <xsl:if test="finishIsFound">
                            <xsl:element name="finish">
                                <xsl:value-of select="$finishFoundFromDescription"/>
                            </xsl:element>
                        </xsl:if>

                        <!-- If <partDescription> contains a number, grab that number and set as value e.g. 8,14,16-->
                        <xsl:if test="sizeIsFound">
                            <xsl:element name="size">
                                <xsl:value-of select="$sizeFoundFromDescription"/>
                            </xsl:element>
                        </xsl:if> 

Here is a sample of the current data

  <part>
    <partNumber>06013464</partNumber>
    <punctuatedPartNumber>0601-3464</punctuatedPartNumber>
    <partStatusDescription>DISCONTINUED</partStatusDescription>
    <partDescription>Flat Black 8" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-18M</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/LzgvQS80LzhBNDg5QjE2LUNEQkMtNDAzMC04NkE0LTlEQjE1MDdGRDYzMQ==</partImage>
    <productId>1136194258</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012660</partNumber>
    <punctuatedPartNumber>0601-2660</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Black 10" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-10B</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/LzkvMC9DLzkwQzQ2MjZGLTQyOEItNDNGRi1CQjYwLTNBREMyOUM1REU4MQ==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012663</partNumber>
    <punctuatedPartNumber>0601-2663</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Chrome 14" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-14</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/LzcvNC81Lzc0NUE3OUM4LTBERDAtNDQ3NS1CMEFBLUVBMDUyRkUzN0Q5OA==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012665</partNumber>
    <punctuatedPartNumber>0601-2665</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Chrome 16" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-16</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/LzMvOC8xLzM4MUQ3NEEwLUM0NEMtNDQxNS05MjA3LUVENjBBQjBCRDhGMQ==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012666</partNumber>
    <punctuatedPartNumber>0601-2666</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Black 16" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-16B</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/LzMvNC84LzM0ODNENTlBLTMwRjYtNDkyQi04MkE0LTQ4MEJFM0Q4MDY2Qg==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012667</partNumber>
    <punctuatedPartNumber>0601-2667</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Chrome 18" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-18</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/L0YvQS9DL0ZBQzMzMEE4LTJDQTItNEI5NS1CNjk0LURFNjA5RTFGODUyQw==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012668</partNumber>
    <punctuatedPartNumber>0601-2668</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Black 18" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-18B</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/L0MvOC8yL0M4MkJENjZDLTc4OTUtNDEwOC04NjVELUFDMEZGODEzOENBQw==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012669</partNumber>
    <punctuatedPartNumber>0601-2669</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Chrome 20" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-20</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/L0IvNS9FL0I1RTk1MzdGLTRDMjItNEY1RC1BMzRGLTJBQzA5MzdFQ0UwOA==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012670</partNumber>
    <punctuatedPartNumber>0601-2670</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Black 20" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-20B</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/LzQvQS8zLzRBMzcyMzJDLTJCMDgtNDk1NS1BNENFLTU5M0EzMTQ5RUNGQQ==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06013460</partNumber>
    <punctuatedPartNumber>0601-3460</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Flat Black 10" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-10M</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/LzIvMS81LzIxNURERkMxLTg5OTctNEJEQS05MUVELUZFNDY4RkQ0QThFMQ==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06013461</partNumber>
    <punctuatedPartNumber>0601-3461</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Flat Black 12" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-12M</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/LzIvQy8yLzJDMkE2NURFLTU4QjYtNEVDOC1BRTVCLTI3M0QyMjY0ODAyNw==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06013462</partNumber>
    <punctuatedPartNumber>0601-3462</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Flat Black 14" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-14M</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/L0EvNC9GL0E0RjJBMkExLUU1QUYtNDJCOC1CQzE2LUY3MEREMTQxRkMwQw==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06013463</partNumber>
    <punctuatedPartNumber>0601-3463</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Flat Black 16" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-16M</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/LzgvMC9GLzgwRjVFN0I1LThGMzgtNEMwNS04N0YwLUNDODA3NEU0RTY0MA==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012662</partNumber>
    <punctuatedPartNumber>0601-2662</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Black 12" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-12B</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/L0UvRS85L0VFOTJEOTEyLTMyNUYtNEI4Ri04NjgyLTIzNDZGRjJERTVGOA==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012661</partNumber>
    <punctuatedPartNumber>0601-2661</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Chrome 12" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-12</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/L0QvOC80L0Q4NDJFQTg1LUMwMUItNERENC05REVGLUUzM0ExOUQxN0ZFRA==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012659</partNumber>
    <punctuatedPartNumber>0601-2659</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Chrome 10" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-10</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/LzQvMy81LzQzNTYwRjE4LTBEMUEtNEU3NS04OUU2LUQ2RURGM0MxMENGQg==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06012664</partNumber>
    <punctuatedPartNumber>0601-2664</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Black 14" Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7321-14B</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>185.0000</baseDealerPrice>
    <yourDealerPrice>185.0000</yourDealerPrice>
    <baseRetailPrice>272.9500</baseRetailPrice>
    <originalRetailPrice>272.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/L0YvRC9DL0ZEQzgwNDU4LUMyQjctNDk1QS04RjMxLTQzRkNERDg2MTBGRQ==</partImage>
    <productId>0243176820</productId>
    <productName>1-1/4" Touring Ape Hanger Handlebar</productName>
  </part>
  <part>
    <partNumber>06010612</partNumber>
    <punctuatedPartNumber>0601-0612</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Beach Bar Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7312-01</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>106.5000</baseDealerPrice>
    <yourDealerPrice>106.5000</yourDealerPrice>
    <baseRetailPrice>157.9500</baseRetailPrice>
    <originalRetailPrice>157.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/L0IvMy8zL0IzM0NGMjQxLTk0NzctNDQ5QS05QzZCLTBFMzQwMDdEQTdDNA==</partImage>
    <productId>0635669078</productId>
    <productName>Hefty 1-1/4" Handlebar — Beach Bar/Hefty</productName>
  </part>
  <part>
    <partNumber>06011482</partNumber>
    <punctuatedPartNumber>0601-1482</punctuatedPartNumber>
    <partStatusDescription>STANDARD</partStatusDescription>
    <partDescription>Black Beach Bar Handlebar</partDescription>
    <unitOfMeasure>Each</unitOfMeasure>
    <brandName>LA CHOPPERS</brandName>
    <supplierNumber>LA-7312-01B</supplierNumber>
    <specialInstructions/>
    <baseDealerPrice>106.5000</baseDealerPrice>
    <yourDealerPrice>106.5000</yourDealerPrice>
    <baseRetailPrice>157.9500</baseRetailPrice>
    <originalRetailPrice>157.9500</originalRetailPrice>
    <partImage>http://asset.lemansnet.com/z/LzMvRS82LzNFNjlFOTdDLTg5NjEtNDU1MC1BRkY3LUExNjU0MTdEQUQ5MQ==</partImage>
    <productId>0635669078</productId>
    <productName>Hefty 1-1/4" Handlebar — Beach Bar/Hefty</productName>
  </part>
</root>

Then, I have my current XSL Template

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

    <xsl:template match="root">
        <xsl:element name="items">
            <xsl:for-each select="part">
                <xsl:if test="supplierNumber != '' and partStatusDescription != 'DISCONTINUED'     "> 
                    <xsl:element name="item">
                        <partNumber>
                            <xsl:value-of select="partNumber"/>
                        </partNumber>
                        <xsl:element name="name">
                             <xsl:value-of select="concat(brandName,' ',productName)"/>
                        </xsl:element>
                        <punctuatedPartNumber>
                            <xsl:value-of select="punctuatedPartNumber"/>
                        </punctuatedPartNumber>
                         <xsl:element name="is_in_stock">
                            <xsl:if test="partStatusDescription = 'STANDARD'">
                                    <xsl:value-of select="1"/>
                            </xsl:if>
                            <xsl:if test="partStatusDescription != 'STANDARD'">
                                <xsl:value-of select="0"/>
                            </xsl:if>    
                        </xsl:element>
                        <partDescription>
                            <xsl:value-of select="partDescription"/>
                        </partDescription>
                        <unitOfMeasure>
                            <xsl:value-of select="unitOfMeasure"/>
                        </unitOfMeasure>
                        <brandName>
                            <xsl:value-of select="brandName"/>
                        </brandName>
                        <supplierNumber>
                            <xsl:value-of select="supplierNumber"/>
                        </supplierNumber>
                        <specialInstructions>
                            <xsl:value-of select="specialInstructions"/>
                        </specialInstructions>
                        <xsl:element name="price">
                            <xsl:value-of select="(originalRetailPrice * 100) div 100"/>
                        </xsl:element>
                        <xsl:element name="special_price">
                            <xsl:if test="baseRetailPrice  &lt; originalRetailPrice">
                                <xsl:value-of select="baseRetailPrice"/>
                            </xsl:if>
                        </xsl:element>
                        <partImage>
                            <xsl:value-of select="partImage"/>
                        </partImage>
                        <productId>
                            <xsl:value-of select="productId"/>
                        </productId>
                        <productImage>
                            <xsl:value-of select="productImage"/>
                        </productImage>
                        <bullet1>
                            <xsl:value-of select="bullet1"/>
                        </bullet1>
                        <bullet2>
                            <xsl:value-of select="bullet2"/>
                        </bullet2>
                        <bullet3>
                            <xsl:value-of select="bullet3"/>
                        </bullet3>
                        <bullet4>
                            <xsl:value-of select="bullet4"/>
                        </bullet4>

                        <!-- Logic to Figure out Attribute Data from Names, Descriptions -->
                        <!-- If <partDescription> contains Black, Flat Back, Chrome element finish shoud return the value that is found -->

                        <xsl:if test="finishIsFound">
                            <xsl:element name="finish">
                                <xsl:value-of select="$finishFoundFromDescription"/>
                            </xsl:element>
                        </xsl:if>

                        <!-- If <partDescription> contains a number, grab that number and set as value e.g. 8,14,16-->
                        <xsl:if test="sizeIsFound">
                            <xsl:element name="size">
                                <xsl:value-of select="$sizeFoundFromDescription"/>
                            </xsl:element>
                        </xsl:if>

                    </xsl:element>
                </xsl:if>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>
Rob
  • 953
  • 7
  • 12

1 Answers1

1

This is a fine mess.

It's a mess, because XSLT is designed to handle structured data, but your data provider chose not to take advantage of the structure XML provides. The type of processing required here would be much better handled by regex - however, regex support was only introduced in XSLT 2.0.

That said, let's see what can be done:

The first task:

If <partDescription> contains Black, Flat Back, Chrome element finish shoud return the value that is found

is relatively easy: assuming that the possible finish options are mutually exclusive, you could do:

<xsl:choose>
    <xsl:when test="contains(partDescription, 'Black')">
        <finish>Black</finish>
    </xsl:when>
    <xsl:when test="contains(partDescription, 'Flat Back')">
        <finish>Flat Back</finish>
    </xsl:when>
    <xsl:when test="contains(partDescription, 'Chrome')">
        <finish>Chrome</finish>
    </xsl:when>
</xsl:choose>

Note that this also assumes that one option is not contained in another. If that's not the case, make sure to test for the containing option before the contained one.

Now regarding size, you say:

If <partDescription> contains a number, grab that number

Taking this literally, you could do:

<xsl:variable name="size" select="translate(partDescription, translate(partDescription, '0123456789', ''), '')" />
<xsl:if test="$size">
    <size>
        <xsl:value-of select="$size"/>
    </size>
</xsl:if>

However, this has two flaws:

  1. it removes the units (and also the decimal separator, if the size is not an integer);
  2. it will concatenate ALL digits contained in partDescription together, even if they are not part of the same number.

A better (though still not perfect) solution would tokenize the description by the space character, and look for a token that starts with a digit. Fortunately, the libxslt processor supports the EXSLT str:tokenize() extension function, so you can do:

<xsl:variable name="size" select="str:tokenize(partDescription, ' ')[starts-with(translate(., '123456789', '000000000'), '0')]" />
<xsl:if test="$size">
    <size>
        <xsl:value-of select="$size"/>
    </size>
</xsl:if>

But this will still fail if the description contains more than one word that starts with a digit and size is not the first one of them.


Here's a minimal implementation of the two suggestions:

XSLT 1.0 + EXSLT

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/root">
    <items>
        <xsl:for-each select="part[supplierNumber/text() and partStatusDescription != 'DISCONTINUED']">
            <item>
                <xsl:copy-of select="partNumber"/>
                <!-- finish -->
                <xsl:choose>
                    <xsl:when test="contains(partDescription, 'Black')">
                        <finish>Black</finish>
                    </xsl:when>
                    <xsl:when test="contains(partDescription, 'Flat Back')">
                        <finish>Flat Back</finish>
                    </xsl:when>
                    <xsl:when test="contains(partDescription, 'Chrome')">
                        <finish>Chrome</finish>
                    </xsl:when>
                </xsl:choose>
                <!-- size -->
                <xsl:variable name="size" select="str:tokenize(partDescription, ' ')[starts-with(translate(., '23456789', '1'), '1')]" />
                <xsl:if test="$size">
                    <size>
                        <xsl:value-of select="$size"/>
                    </size>
                </xsl:if>
            </item>
        </xsl:for-each>
    </items>        
</xsl:template>

</xsl:stylesheet>

When applied to your input example, this will return:

Result

<?xml version="1.0" encoding="UTF-8"?>
<items>
  <item>
    <partNumber>06012660</partNumber>
    <finish>Black</finish>
    <size>10"</size>
  </item>
  <item>
    <partNumber>06012663</partNumber>
    <finish>Chrome</finish>
    <size>14"</size>
  </item>
  <item>
    <partNumber>06012665</partNumber>
    <finish>Chrome</finish>
    <size>16"</size>
  </item>
  <item>
    <partNumber>06012666</partNumber>
    <finish>Black</finish>
    <size>16"</size>
  </item>
  <item>
    <partNumber>06012667</partNumber>
    <finish>Chrome</finish>
    <size>18"</size>
  </item>
  <item>
    <partNumber>06012668</partNumber>
    <finish>Black</finish>
    <size>18"</size>
  </item>
  <item>
    <partNumber>06012669</partNumber>
    <finish>Chrome</finish>
    <size>20"</size>
  </item>
  <item>
    <partNumber>06012670</partNumber>
    <finish>Black</finish>
    <size>20"</size>
  </item>
  <item>
    <partNumber>06013460</partNumber>
    <finish>Black</finish>
    <size>10"</size>
  </item>
  <item>
    <partNumber>06013461</partNumber>
    <finish>Black</finish>
    <size>12"</size>
  </item>
  <item>
    <partNumber>06013462</partNumber>
    <finish>Black</finish>
    <size>14"</size>
  </item>
  <item>
    <partNumber>06013463</partNumber>
    <finish>Black</finish>
    <size>16"</size>
  </item>
  <item>
    <partNumber>06012662</partNumber>
    <finish>Black</finish>
    <size>12"</size>
  </item>
  <item>
    <partNumber>06012661</partNumber>
    <finish>Chrome</finish>
    <size>12"</size>
  </item>
  <item>
    <partNumber>06012659</partNumber>
    <finish>Chrome</finish>
    <size>10"</size>
  </item>
  <item>
    <partNumber>06012664</partNumber>
    <finish>Black</finish>
    <size>14"</size>
  </item>
  <item>
    <partNumber>06010612</partNumber>
  </item>
  <item>
    <partNumber>06011482</partNumber>
    <finish>Black</finish>
  </item>
</items>

Added:

Here's the same thing in pure XSLT 1.0, using a recursive named template instead of the extension function:

XSLT 1.0

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

<xsl:template match="/root">
    <items>
        <xsl:for-each select="part[supplierNumber/text() and partStatusDescription != 'DISCONTINUED']">
            <item>
                <xsl:copy-of select="partNumber"/>
                <!-- finish -->
                <xsl:choose>
                    <xsl:when test="contains(partDescription, 'Black')">
                        <finish>Black</finish>
                    </xsl:when>
                    <xsl:when test="contains(partDescription, 'Flat Back')">
                        <finish>Flat Back</finish>
                    </xsl:when>
                    <xsl:when test="contains(partDescription, 'Chrome')">
                        <finish>Chrome</finish>
                    </xsl:when>
                </xsl:choose>
                <!-- size -->
                <xsl:call-template name="find-size">
                    <xsl:with-param name="text" select="partDescription"/>
                </xsl:call-template>
            </item>
        </xsl:for-each>
    </items>        
</xsl:template>

<xsl:template name="find-size">
    <xsl:param name="text"/>
    <xsl:param name="delimiter" select="' '"/>
    <xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
    <xsl:choose>
        <xsl:when test="starts-with(translate($token, '123456789', '000000000'), '0')">
            <size>
                <xsl:value-of select="$token"/>
            </size>
        </xsl:when>
        <xsl:when test="contains($text, $delimiter)">
            <!-- recursive call -->
            <xsl:call-template name="find-size">
                <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
            </xsl:call-template>
        </xsl:when>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • First, thanks for spending your time answering my vague question! The finish part works correctly, however, the "size" one does not. I get the following error: Warning: XSLTProcessor::transformToDoc(): xmlXPathCompOpEval: function tokenize bound to undefined prefix str in /importexport/Model/Output/Xslt.php on line 118. I did try anything using str:tokenize and I get the same error. I'm marking this as correct, since this likely will work in an unmolested xslt 1.0 processor, but I'm struggling here. Is there a parameter I need to pass to XSLT to make this function available. – Rob Dec 22 '20 at 00:25
  • 1
    Did you declare the `str` prefix in your `xsl:stylesheet` start-tag (as I did in mine)? – michael.hor257k Dec 22 '20 at 00:52
  • Good call, I guess I missed that.. I copied exactly what you provided. I got this error. Warning: XSLTProcessor::importStylesheet(): compilation error: file //pub/ line 4 element stylesheet in /vendor/firebear/importexport/Model/Output/Xslt.php on line 107 – Rob Dec 22 '20 at 01:27
  • I don't know. I don't use PHP myself and I don't recognize the error. If you like, I will post a version that does not rely on any extension functions. Perhaps your implementation does not support them. – michael.hor257k Dec 22 '20 at 01:37
  • You’d be my hero, this is my first time with XSLT, and I’ve been really struggling here. – Rob Dec 22 '20 at 04:04
  • OK, try it now. – michael.hor257k Dec 22 '20 at 07:02
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/226317/discussion-between-rob-and-michael-hor257k). – Rob Dec 22 '20 at 19:26
  • Thanks, this appears to have worked very very well – Rob Dec 22 '20 at 19:28