I am having trouble working out an xslt transformation that I would really appreciate some help with it. I have spent quite a bit of time using a variety of methods in XPath and XQuery. Also, I am restricted to xslt 1.0.
The transformation involves making changes to product items in an xml order file. The original XML file has Items however some of the line Items are discount coupon references (see dsc-102 and dsc-133 below). What I need to achieve is to remove the 'orderDetails' nodes for discount coupon references and add the containing information to their corresponding sibling product items (see the Transformed XML sample below). Each discount coupon reference specifies its corresponding product items at the end of its product name (eg ….[glv-001][glv-003]).
Original XML File - Below is the original XML file that contains 1 order with 3 product items and 2 discount coupon references. The discount reference 'dsc-102' corresponds to 2 product items 'glv-001' and 'glv-003'. The discount reference 'dsc-133' corresponds to 1 product item 'sho-123'.
<xmldata>
<Order>
<orderID>1010</orderID>
<custFirstName>Jim</custFirstName>
<custLastName>Jones</custLastName>
<orderDetails>
<productCode>sho-123</productCode>
<productName>Leather Windsor Shoes - size 10</productName>
</orderDetails>
<orderDetails>
<productCode>glv-001</productCode>
<productName>Leather gloves - size Small</productName>
</orderDetails>
<orderDetails>
<productCode>glv-003</productCode>
<productName>Leather gloves - size XLarge</productName>
</orderDetails>
<orderDetails>
<productCode>dsc-102</productCode>
<productName>10% Discount for Leather Gloves [glv-001][glv-003]</productName>
</orderDetails>
<orderDetails>
<productCode>dsc-133</productCode>
<productName>Free Shipping for Windsor Shoes [sho-123]</productName>
</orderDetails>
</Order>
Transformed XML File - Below is the transformed XML that I want to achieve. The transfer has removed both discount coupon references and added a 'discountCoupon' node to their corresponding sibling product items.
<xmldata>
<Orders>
<orderID>1010</orderID>
<custFirstName>Jim</custFirstName>
<custLastName>Jones</custLastName>
<orderDetails>
<productCode>sho-123</productCode>
<productName>Leather Windsor Shoes - size 10</productName>
<discountCoupon>Free Shipping for Windsor Shoes</discountCoupon>
</orderDetails>
<orderDetails>
<productCode>glv-001</productCode>
<productName>Leather gloves - size Small</productName>
<discountCoupon>10% Discount for Leather Gloves</discountCoupon>
</orderDetails>
<orderDetails>
<productCode>glv-003</productCode>
<productName>Leather gloves - size XLarge</productName>
<discountCoupon>10% Discount for Leather Gloves</discountCoupon>
</orderDetails>
</Orders>
What I have Tried So far - To be totally honest I have had quite limited success with this problem. The closest I have got with it has been with the following. However, it was pretty far off my intended result and 'matches' is a XLST 2.0 function and I am restricted to version 1.
<xsl:if test="../OrderDetails[ProductCode = 'DSC-15'] and matches(ProductCode,'AH010585059',i)">DiscountCoupon</xsl:if>
If someone could give me a hand with this problem or give me a push in the right direction I would really appreciate it.
-Cheers.
A solution similar to that of @lwburk, but simpler -- no <xsl:if> and no <xsl:variable>:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"orderDetails[not(starts-with(productCode, 'dsc-'))]">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<xsl:apply-templates mode="coupon" select=
"../orderDetails[starts-with(productCode, 'dsc-')]
[contains(productName,
concat('[', current()/productCode, ']')
)
]/productName
"/>
</xsl:copy>
</xsl:template>
<xsl:template match="orderDetails[starts-with(productCode, 'dsc-')]"/>
<xsl:template match="productName" mode="coupon">
<discountCoupon>
<xsl:value-of select="substring-before(., ' [')"/>
</discountCoupon>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<Order>
<orderID>1010</orderID>
<custFirstName>Jim</custFirstName>
<custLastName>Jones</custLastName>
<orderDetails>
<productCode>sho-123</productCode>
<productName>Leather Windsor Shoes - size 10</productName>
</orderDetails>
<orderDetails>
<productCode>glv-001</productCode>
<productName>Leather gloves - size Small</productName>
</orderDetails>
<orderDetails>
<productCode>glv-003</productCode>
<productName>Leather gloves - size XLarge</productName>
</orderDetails>
<orderDetails>
<productCode>dsc-102</productCode>
<productName>10% Discount for Leather Gloves [glv-001][glv-003]</productName>
</orderDetails>
<orderDetails>
<productCode>dsc-133</productCode>
<productName>Free Shipping for Windsor Shoes [sho-123]</productName>
</orderDetails>
</Order>
the wanted, correct result is produced:
<Order>
<orderID>1010</orderID>
<custFirstName>Jim</custFirstName>
<custLastName>Jones</custLastName>
<orderDetails>
<productCode>sho-123</productCode>
<productName>Leather Windsor Shoes - size 10</productName>
<discountCoupon>Free Shipping for Windsor Shoes</discountCoupon>
</orderDetails>
<orderDetails>
<productCode>glv-001</productCode>
<productName>Leather gloves - size Small</productName>
<discountCoupon>10% Discount for Leather Gloves</discountCoupon>
</orderDetails>
<orderDetails>
<productCode>glv-003</productCode>
<productName>Leather gloves - size XLarge</productName>
<discountCoupon>10% Discount for Leather Gloves</discountCoupon>
</orderDetails>
</Order>
Explanation: Appropriate use and overriding of the identity rule, and templates/pattern-matching.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With