1

I have to transform the following xml content,

<Standards xmlns="http://ws.wso2.org/dataservice">
    <Standard>
        <ProductID>200057</ProductID>
        <Prefix>ISO</Prefix>
        <SNumber>1001</SNumber>
        <DraftProducts>
            <RelatedProduct>
                <ProductID>1500163</ProductID>
            </RelatedProduct>
        </DraftProducts>
        <ReferenceProducts>
            <RelatedProduct>
                <ProductID>263973</ProductID>
                <RelationId>708519</RelationId>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID>320056</ProductID>
                <RelationId>934789</RelationId>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
        </ReferenceProducts>
        <RelatedIntProducts>
            <RelatedProduct>
                <ProductID xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
                <RelationId>116881</RelationId>
                <Relationship>Identical</Relationship>
                <Designation>NEN ISO 1001</Designation>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID>208076</ProductID>
                <RelationId>116886</RelationId>
                <Relationship>Identical</Relationship>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
        </RelatedIntProducts>
        <S1>1001</S1>
        <S2>1986</S2>
    </Standard>
    <Standard>
        <ProductID>200058</ProductID>
        <Prefix>ISO</Prefix>
        <SNumber>1002</SNumber>
        <DraftProducts>
            <RelatedProduct>
                <ProductID>1500167</ProductID>
            </RelatedProduct>
        </DraftProducts>
        <ReferenceProducts>
            <RelatedProduct>
                <ProductID>263974</ProductID>
                <RelationId>708519</RelationId>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID>320052</ProductID>
                <RelationId>934754</RelationId>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
        </ReferenceProducts>
        <RelatedIntProducts>
            <RelatedProduct>
                <ProductID xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
                <RelationId>116837</RelationId>
                <Relationship>Identical</Relationship>
                <Designation>NEN ISO 1001</Designation>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID>208074</ProductID>
                <RelationId>116843</RelationId>
                <Relationship>Identical</Relationship>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
        </RelatedIntProducts>
        <S1>1005</S1>
        <S2>1983</S2>
    </Standard>
</Standards>

in to this output format,

<Standards xmlns="http://ws.wso2.org/dataservice">
    <Standard>
        <ProductID>200057</ProductID>
        <Prefix>ISO</Prefix>
        <SNumber>1001</SNumber>
        <RelatedProducts>
            <RelatedProduct>
                <ProductID>1500163</ProductID>
                <RelationType>DraftProducts</RelationType>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID>263973</ProductID>
                <RelationId>708519</RelationId>
                <RelationType>ReferenceProducts</RelationType>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID>320056</ProductID>
                <RelationId>934789</RelationId>
                <RelationType>ReferenceProducts</RelationType>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
                <RelationId>116881</RelationId>
                <Relationship>Identical</Relationship>
                <RelationType>RelatedIntProducts</RelationType>
                <Designation>NEN ISO 1001</Designation>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID>208076</ProductID>
                <RelationId>116886</RelationId>
                <RelationType>RelatedIntProducts</RelationType>
                <Relationship>Identical</Relationship>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
        </RelatedProducts>
        <S1>1001</S1>
        <S2>1986</S2>
    </Standard>
    <Standard>
        <ProductID>200058</ProductID>
        <Prefix>ISO</Prefix>
        <SNumber>1002</SNumber>
        <RelatedProducts>
            <RelatedProduct>
                <ProductID>1500167</ProductID>
                <RelationType>DraftProducts</RelationType>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID>263974</ProductID>
                <RelationId>708519</RelationId>
                <RelationType>ReferenceProducts</RelationType>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID>320052</ProductID>
                <RelationId>934754</RelationId>
                <RelationType>ReferenceProducts</RelationType>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
                <RelationId>116837</RelationId>
                <RelationType>RelatedIntProducts</RelationType>
                <Relationship>Identical</Relationship>
                <Designation>NEN ISO 1001</Designation>
            </RelatedProduct>
            <RelatedProduct>
                <ProductID>208074</ProductID>
                <RelationId>116843</RelationId>
                <RelationType>RelatedIntProducts</RelationType>
                <Relationship>Identical</Relationship>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            </RelatedProduct>
        </RelatedProducts>
        <S1>1005</S1>
        <S2>1983</S2>
    </Standard>
</Standards>

I have used following xslt, but still does not give the output as expected. The given xslt works only when there's one standard. But with multiple standards it gives duplicated results due to the xsl template which I used here.

<?xml version="1.0" encoding="UTF-8"?>

<!-- When matching RelatedIntProducts: do nothing -->
<xsl:template match="//x:Standards/x:Standard/x:DraftProducts" />
<xsl:template match="//x:Standards/x:Standard/x:RelatedIntProducts" />
<xsl:template match="//x:Standards/x:Standard/x:SupersdProducts" />
<xsl:template match="//x:Standards/x:Standard/x:LinkProducts" />


    <xsl:template match="//x:Standards/x:Standard/x:ReferenceProducts">
        <RelatedProducts>
            <xsl:for-each select="//x:Standards/x:Standard/*/x:RelatedProduct">
                <RelatedProduct>
                    <ProductID>
                        <xsl:value-of select="x:ProductID">
                        </xsl:value-of>
                    </ProductID>
                    <RelationId>
                        <xsl:value-of select="x:RelationId">
                        </xsl:value-of>
                    </RelationId>

                    <RelationType>
                        <xsl:value-of select="name(..)" />
                    </RelationType>
                </RelatedProduct>
            </xsl:for-each>
        </RelatedProducts>
    </xsl:template>

</xsl:stylesheet>

For each standard I need to merge all the different types of RelatedProducts into one list named RelatedProducts. Also I need to keep the other stuffs as it is. Could you please help me to achieve this.

Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63

1 Answers1

2

Switching from imperative "pull" processing (<xsl:for-each...>) to "push" processing, where you depend on the natural processing loop of the XSL engine, simplifies the stylesheet significantly.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:x="http://ws.wso2.org/dataservice"
    xmlns="http://ws.wso2.org/dataservice"
    exclude-result-prefixes="x"
    version="1.0">

    <xsl:output indent="yes" method="xml" />

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

    <xsl:template match="x:Standard">
        <xsl:copy>
            <xsl:copy-of select="x:ProductID"/>
            <xsl:copy-of select="x:Prefix"/>
            <xsl:copy-of select="x:SNumber"/>
            <RelatedProducts>
                <xsl:apply-templates select=".//x:RelatedProduct"/>
            </RelatedProducts>
            <xsl:copy-of select="x:S1"/>
            <xsl:copy-of select="x:S2"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="x:RelatedProduct">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <RelationType><xsl:value-of select="name(..)"/></RelationType>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

This is essentially an "identity transform" plus one template to match Standard, and output only what we want from within it. The template for x:RelatedProduct copies those elements to the output verbatim and adds the RelationType element whose text is the name of the containing element.

Output is

<?xml version="1.0" encoding="UTF-8"?>
<Standards xmlns="http://ws.wso2.org/dataservice">
    <Standard>
      <ProductID>200057</ProductID>
      <Prefix>ISO</Prefix>
      <SNumber>1001</SNumber>
      <RelatedProducts>
         <RelatedProduct>
                <ProductID>1500163</ProductID>
            <RelationType>DraftProducts</RelationType>
         </RelatedProduct>
         <RelatedProduct>
                <ProductID>263973</ProductID>
                <RelationId>708519</RelationId>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            <RelationType>ReferenceProducts</RelationType>
         </RelatedProduct>
         <RelatedProduct>
                <ProductID>320056</ProductID>
                <RelationId>934789</RelationId>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            <RelationType>ReferenceProducts</RelationType>
         </RelatedProduct>
         <RelatedProduct>
                <ProductID xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
                <RelationId>116881</RelationId>
                <Relationship>Identical</Relationship>
                <Designation>NEN ISO 1001</Designation>
            <RelationType>RelatedIntProducts</RelationType>
         </RelatedProduct>
         <RelatedProduct>
                <ProductID>208076</ProductID>
                <RelationId>116886</RelationId>
                <Relationship>Identical</Relationship>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            <RelationType>RelatedIntProducts</RelationType>
         </RelatedProduct>
      </RelatedProducts>
      <S1>1001</S1>
      <S2>1986</S2>
   </Standard>
    <Standard>
      <ProductID>200058</ProductID>
      <Prefix>ISO</Prefix>
      <SNumber>1002</SNumber>
      <RelatedProducts>
         <RelatedProduct>
                <ProductID>1500167</ProductID>
            <RelationType>DraftProducts</RelationType>
         </RelatedProduct>
         <RelatedProduct>
                <ProductID>263974</ProductID>
                <RelationId>708519</RelationId>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            <RelationType>ReferenceProducts</RelationType>
         </RelatedProduct>
         <RelatedProduct>
                <ProductID>320052</ProductID>
                <RelationId>934754</RelationId>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            <RelationType>ReferenceProducts</RelationType>
         </RelatedProduct>
         <RelatedProduct>
                <ProductID xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
                <RelationId>116837</RelationId>
                <Relationship>Identical</Relationship>
                <Designation>NEN ISO 1001</Designation>
            <RelationType>RelatedIntProducts</RelationType>
         </RelatedProduct>
         <RelatedProduct>
                <ProductID>208074</ProductID>
                <RelationId>116843</RelationId>
                <Relationship>Identical</Relationship>
                <Designation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
            <RelationType>RelatedIntProducts</RelationType>
         </RelatedProduct>
      </RelatedProducts>
      <S1>1005</S1>
      <S2>1983</S2>
   </Standard>
</Standards>
Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
  • Hi Jim, Thanks a lot for the elegant answer. You saved me ! :) – Ravindra Ranwala Mar 12 '16 at 09:05
  • How can I change the above xslt to include the RelationType element for each RelatedProduct item, which is the name of it's immediate parent node. Any help is appreciated. – Ravindra Ranwala Mar 12 '16 at 13:26
  • I can answer your question but first please delete your "answer" that is really just another question. On StackOverflow answers are not for asking additional questions. – Jim Garrison Mar 12 '16 at 16:36
  • As per your comment I have removed that question from answers section. But it didn't let me delete it, since it is already deleted. Instead I changed the content accordingly. Could you please let me know how this can be achieved. – Ravindra Ranwala Mar 12 '16 at 21:09
  • Also for reference purposes I have posted a new question here and referenced this thread from there. You may find the new question here http://stackoverflow.com/questions/35963434/merge-different-products-belong-to-each-standard-v2 – Ravindra Ranwala Mar 12 '16 at 21:18
  • I hope you study this carefully to understand why and how it works, and learn how to use "push" processing. `xsl:for-each` has its uses but if you learn to work _with_ the XSL engine instead of against it you will write much better stylesheets. I suggest you get a copy of Evan Lenz's [XSLT 1.0 Pocket Reference](http://shop.oreilly.com/product/9780596100087.do) and read it carefully. It explains the push processing model very well. – Jim Garrison Mar 12 '16 at 21:31
  • Yes, I was carefully going through your answer, it was an elegant answer than mine. Sure We'll go through above reference book and learn push-processing. Thanks for all the guidance. :) – Ravindra Ranwala Mar 12 '16 at 21:38
  • I need to have a small modification to my initial requirement here. Suppose I need to exclude RelationId from each RelatedProduct, How can the above xslt be changed to cater that requirement. Any help would be appreciated. Could you please help me to change the above xslt so that it excludes the element from each RelatedProduct when it generates the output. – Ravindra Ranwala Mar 14 '16 at 00:22
  • I changed above given template as follows and seems to work. What I did was copied each element belong to RelatedProduct rather than copying whole node at once while skipping the RelationID element. Is there any other better way of doing this? If so please do let me know. – Ravindra Ranwala Mar 14 '16 at 00:53
  • You could also change the apply-templates to exclude the element you don't want by modifying the _select=_ expression. – Jim Garrison Mar 14 '16 at 00:57
  • I tried as you said. But no luck. – Ravindra Ranwala Mar 14 '16 at 01:25
  • `select="@*|*[not(name()='RelationId')]"` You're on your own after this. Use Google and experiment. If you don't have an IDE like Oxygen/XML, get one. If you have to do XSLT regularly they are worth whatever they cost. – Jim Garrison Mar 14 '16 at 03:06
  • Hi, now I need to rename all the elements currently named as Standard into Product. I tried following .... , but still no luck. I posted the same question here http://stackoverflow.com/questions/36025236/renaming-an-element-with-name-standard-into-product-using-xslt. I am running in a tight schedule. :( Any help is appreciated. – Ravindra Ranwala Mar 16 '16 at 03:23