I have a xml document, now i want to translate it to another xml document with same content but different element orders.
The original xml document like:
<?xml version = "1.0" encoding = "UTF-8"?>
<order xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" >
<ship>
<zipcode>78712</zipcode>
<street>1234 Main Street</street>
<country>CN</country>
<city>Beijing</city>
</ship>
<items>
<quantity>1</quantity>
<itemno>1234</itemno>
</items>
<items>
<quantity>3</quantity>
<itemno>1235</itemno>
</items>
<price>456</price>
<customer>Tom Hill</customer>
</order>
The expected output xml document like:
<?xml version = "1.0" encoding = "UTF-8"?>
<order xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" >
<customer>Tom Hill</customer>
<ship>
<street>1234 Main Street</street>
<city>Beijing</city>
<zipcode>78712</zipcode>
<country>CN</country>
</ship>
<items>
<itemno>1234</itemno>
<quantity>1</quantity>
</items>
<items>
<itemno>1235</itemno>
<quantity>3</quantity>
</items>
<price>456</price>
</order>
I used following xslt document to translate it.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/order">
<xsl:copy>
<xsl:copy-of select="customer" />
<xsl:copy-of select="ship" >
<xsl:call-template name="TShip" />
</xsl:copy-of>
<xsl:copy-of select="items">
<xsl:call-template name="TItems" />
</xsl:copy-of>
<xsl:copy-of select="price" />
</xsl:copy>
</xsl:template>
<xsl:template name="TShip">
<xsl:copy>
<xsl:copy-of select="street" />
<xsl:copy-of select="city" />
<xsl:copy-of select="zipcode" />
<xsl:copy-of select="country" />
</xsl:copy>
</xsl:template>
<xsl:template name="TItems">
<xsl:for-each select="items">
<xsl:copy>
<xsl:copy-of select="itemno" />
<xsl:copy-of select="quantity" />
</xsl:copy>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
However, the translated result is not my expected.
Translated result xml:
<?xml version = "1.0" encoding = "UTF-8"?>
<order xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" >
<customer>Tom Hill</customer>
<ship>
<zipcode>78712</zipcode>
<street>1234 Main Street</street>
<country>CN</country>
<city>Beijing</city>
</ship>
<items>
<quantity>1</quantity>
<itemno>1234</itemno>
</items>
<items>
<quantity>3</quantity>
<itemno>1235</itemno>
</items>
<price>456</price>
</order>
It just made the first level nodes in expected order. All sub-nodes are kept in original order. How can i make the order of all nodes as my expected ?
xsl:copy-ofcopies all child nodes as well and child nodes of it are not evaluated.So your TShip and TItems templates are never even being evaluated.
<xsl:copy-of select="ship">copies all of<ship>...</ship>.This modification to your template will demonstrate that your TShip and TItems templates are not being called.
Notice that the output does not contain the
<test>elements I added.What you need to do instead is recursive implicit copying. Usually
xsl:copy,xsl:copy-ofandxsl:for-eachare a sign of bad xsl template design–there are very few problems whichxsl:templateandxsl:apply-templatewith an identity transform do not handle better.This is how I would do it:
Notice how many fewer assumptions this template design makes about the structure of your source XML. It is also much easier to change: for example, if you want to silence or rename a particular element that may itself have children, you just add a new
xsl:templatethat matches that element, do whatever you need to do, andxsl:apply-templateson the children.You should learn more about this XSLT pattern because it is very versatile and makes template authoring much less tedious and your templates much less brittle.