1

I have the following XML document as an input (InputXML) to a Java program that applies a XSL (TransformationXSL) to convert to output XML (OutputXML).

I want to add an extra node as part of the transformation of the input XML. Is there a better way than what is being shown in the (TranformationXSL), as this just tries to match the element and copy what's required??? Any other efficient way / suggestion is much appreciated.

InputXML

<?xml version="1.0" encoding="UTF-8"?>
<tuple>
    <old>
        <Customers>
            <OrderID>10248</OrderID>
            <CustomerID>VINET</CustomerID>
            <EmployeeID>8</EmployeeID>
            <OrderDate>1996-07-04T00:00:00.0</OrderDate>
            <CustomerID>VINET</CustomerID>
            <CompanyName>Vins et alcools Chevalier</CompanyName>
        </Customers>
    </old>
</tuple>

OutputXML

<?xml version="1.0" encoding="UTF-8"?>
<tuple>
    <old>
        <Customers>
            <Orders>
                <OrderID>10248</OrderID>
                <CustomerID>VINET</CustomerID>
                <EmployeeID>8</EmployeeID>
                <OrderDate>1996-07-04T00:00:00.0</OrderDate>
            </Orders>
            <CustomerID>VINET</CustomerID>
            <CompanyName>Vins et alcools Chevalier</CompanyName>                
        </Customers>
    </old>
</tuple>

This is the TransformationXSL that I was talking about. Can this be modified to efficiently transform the input XML to give the desired output XML???

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

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

    <xsl:template match="Customers">
        <Customers>
            <Orders>
                <OrderID>10248</OrderID>
                <CustomerID>VINET</CustomerID>
                <EmployeeID>8</EmployeeID>
                <OrderDate>1996-07-04T00:00:00.0</OrderDate>
            </Orders>
            <CustomerID>VINET</CustomerID>
            <CompanyName>Vins et alcools Chevalier</CompanyName>
        </Customers>
    </xsl:template>
</xsl:stylesheet>
4
  • What's the logic behind grouping few elements inside Orders and few not? Commented Feb 16, 2016 at 10:33
  • Logical differentiator is just that the columns from Orders table (NORTHWIND database, MS SQL Server) to be put under Orders tag, rest of the elements are columns from Customers table. Commented Feb 16, 2016 at 10:35
  • Your XSLT makes no sense to me: why are you hard-coding the values? -- As for the question: will there always be only one record, containing one order and one customer? Commented Feb 16, 2016 at 12:02
  • I'm embarrassed to come up with an XSL as like what I shared, but to achieve the required output I didn't find a better solution. Thanks to @Alexey, I have one! To answer your questions, yes, always one order and a customer. Commented Feb 17, 2016 at 3:24

2 Answers 2

3

The output you show can be obtained easily by:

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:strip-space elements="*"/>

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

<xsl:template match="Customers">
    <xsl:copy>
        <Orders>
            <xsl:copy-of select="OrderID | CustomerID[1] | EmployeeID | OrderDate"/>
        </Orders>
        <xsl:copy-of select="CustomerID[1] | CompanyName"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

Comments

1

If double tag CustomerID in the InputXML is an error, then check my solution below.

<?xml version="1.0" encoding="UTF-8"?>
<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"
                standalone="yes"
                omit-xml-declaration="no"/>

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

    <xsl:template match="OrderID">
        <xsl:element name="Orders">
            <xsl:element name="OrderID">
                <xsl:value-of select="../OrderID/text()"/>
            </xsl:element>
            <xsl:element name="CustomerID">
                <xsl:value-of select="../CustomerID/text()"/>
            </xsl:element>
            <xsl:element name="EmployeeID">
                <xsl:value-of select="../EmployeeID/text()"/>
            </xsl:element>
            <xsl:element name="OrderDate">
                <xsl:value-of select="../OrderDate/text()"/>
            </xsl:element>
        </xsl:element>
    </xsl:template>

    <xsl:template match="EmployeeID"/>
    <xsl:template match="OrderDate"/>
</xsl:stylesheet>

1 Comment

thanks for sharing this. What if, if the CustomerID is required under the Customers tag as well as under the Orders tag? Can something be done to have only one element under Customers? (it is repeating twice now!)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.