I am trying to restructure an xml. So needing to split the Product up. I have done a couple of xslt with help from yourselves however these were for splitting the XML into multiple XML. This however seems slightly more challenging. I am struggling with where to begin. Any help would be great. I am using XSLT 2.0.
Cheers
Input XML
<?xml version="1.0"?>
<Order_Root>
<Orders Number="12345">
<Info Name="John Doe" Reference="1/2/2019">
<LineItems>
<LineItem LineItemNumber="01" CustomerProductName="Test">
<LineItemPrice Price="0" Charge="0" />
<Products>
<Product ProductName="A" />
<Product ProductName="B" />
<Product ProductName="C" />
</Products>
</LineItem>
</LineItems>
</Info>
</Orders>
</Order_Root>
Result XML
<?xml version="1.0"?>
<Order_Root>
<Orders Number="12345">
<Info Name="John Doe" Reference="1/2/2019">
<LineItems>
<LineItem LineItemNumber="01" CustomerProductName="Test">
<LineItemPrice Price="0" Charge="0" />
<Products>
<Product ProductName="A" />
</Products>
</LineItem>
<LineItem LineItemNumber="01" CustomerProductName="Test">
<LineItemPrice Price="0" Charge="0" />
<Products>
<Product ProductName="B" />
</Products>
</LineItem>
<LineItem LineItemNumber="01" CustomerProductName="Test">
<LineItemPrice Price="0" Charge="0" />
<Products>
<Product ProductName="C" />
</Products>
</LineItem>
</LineItems>
</Info>
</Orders>
</Order_Root>
I think it can be used as a good example of using XSLT 3's snapshot
function together with a second mode and a tunnel parameter to pass on that LineItemPrice
:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:mode name="price" on-no-match="shallow-copy"/>
<xsl:template match="LineItem">
<xsl:apply-templates select=".//Product!snapshot()/ancestor::LineItem" mode="price">
<xsl:with-param name="price" tunnel="yes" select="LineItemPrice"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="LineItem" mode="price">
<xsl:param name="price" tunnel="yes"/>
<xsl:copy>
<xsl:apply-templates select="@*, $price, node()" mode="#current"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/bFN1y8J
XSLT 3 is available with Saxon 9.8 or later or Altova 2017 and later, so chances are if you use an up-to-date XSLT 2 processor you have a processor that can also use XSLT 3 instead of the tagged XSLT 2.
XSLT 2 doesn't have snapshot
but of course you can try to implement the same approach of pushing each product through a different mode to reconstruct a subtree there as well, only the other templates would now need to exclude all but one Product
:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="2.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="LineItem">
<xsl:apply-templates select=".//Product"/>
</xsl:template>
<xsl:template match="Product">
<xsl:apply-templates select="ancestor::LineItem" mode="price">
<xsl:with-param name="product" tunnel="yes" select="."/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Product" mode="price">
<xsl:param name="product" tunnel="yes"/>
<xsl:if test=". is $product">
<xsl:next-match/>
</xsl:if>
</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.