XML Editor
Sign up for a WebBoard account Sign Up Keyword Search Search More Options... Options
Chat Rooms Chat Help Help News News Log in to WebBoard Log in Not Logged in
Show tree view Topic
Topic Page 1 2 3 4 5 6 7 8 9 Go to previous topicPrev TopicGo to next topicNext Topic
Postnext
david mareSubject: flat xml to nested xml comversion trouble
Author: david mare
Date: 29 Oct 2007 08:03 PM
I'm new to XSLT and having trouble with what I think should be pretty simple. I have a fairly flat structured XML file like this:
<root>
<customer>
<name>Fred</name>
<acctnum>111</acctnum>
</customer>
<order>
<ordernum>1</ordernum>
<acctnum>111</acctnum>
<amount>100.00</amount>
</order>
<order>
<ordernum>2</ordernum>
<acctnum>111</acctnum>
<amount>200.00</amount>
</order>
<customer>
<name>Bob</name>
<acctnum>222</acctnum>
</customer>
<order>
<ordernum>1</ordernum>
<acctnum>222</acctnum>
<amount>300.00</amount>
</order>
</root>

As you can see the order nodes are NOT nested within the customer nodes, but are instead related by a common key (customer/acctnum and order/acctnum). The first customer has two orders, the second customer has one order.

I want to transform this so the orders are nested within the customer nodes in a parent/child structure, like this:

<root>
<customer>
<name>Fred</name>
<acctnum>111</acctnum>
<order>
<ordernum>1</ordernum>
<acctnum>111</acctnum>
<amount>100.00</amount>
</order>
<order>
<ordernum>2</ordernum>
<acctnum>111</acctnum>
<amount>200.00</amount>
</order>
</customer>
<customer>
<name>Bob</name>
<acctnum>222</acctnum>
<order>
<ordernum>1</ordernum>
<acctnum>222</acctnum>
<amount>300.00</amount>
</order>
</customer>
</root>

Here's my XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<root>
<xsl:for-each select="root/customer">
<customer>
<name>
<xsl:value-of select="name"/>
</name>
<acctnum>
<xsl:value-of select="acctnum"/>
</acctnum>
<xsl:for-each select="../order[acctnum=../customer/acctnum]">
<order>
<ordernum>
<xsl:value-of select="ordernum"/>
</ordernum>
<acctnum>
<xsl:value-of select="acctnum"/>
</acctnum>
<amount>
<xsl:value-of select="amount"/>
</amount>
</order>
</xsl:for-each>
</customer>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>

Here's the result:

<root>
<customer>
<name>Fred</name>
<acctnum>111</acctnum>
<order>
<ordernum>1</ordernum>
<acctnum>111</acctnum>
<amount>100.00</amount>
</order>
<order>
<ordernum>2</ordernum>
<acctnum>111</acctnum>
<amount>200.00</amount>
</order>
<order>
<ordernum>1</ordernum>
<acctnum>222</acctnum>
<amount>300.00</amount>
</order>
</customer>
<customer>
<name>Bob</name>
<acctnum>222</acctnum>
<order>
<ordernum>1</ordernum>
<acctnum>111</acctnum>
<amount>100.00</amount>
</order>
<order>
<ordernum>2</ordernum>
<acctnum>111</acctnum>
<amount>200.00</amount>
</order>
<order>
<ordernum>1</ordernum>
<acctnum>222</acctnum>
<amount>300.00</amount>
</order>
</customer>
</root>

The statement select="../order[acctnum=../customer/acctnum]" is not working correctly. It is giving me all the orders in the file for each customer, not just the orders where the acctnum matches. Is there another way I should be doing this?

many thanks


Documentin.xml
input xml file

Postnext
Tony LavinioSubject: flat xml to nested xml comversion trouble
Author: Tony Lavinio
Date: 29 Oct 2007 10:33 PM
This is the classic XSLT grouping problem.

For XSLT 2.0, you can use xsl:for-each-group.
For XSLT 1.0, Jeni Tennison has an excellent set of examples at
http://www.jenitennison.com/xslt/grouping/index.xml

Postnext
david mareSubject: flat xml to nested xml comversion trouble
Author: david mare
Date: 30 Oct 2007 02:19 AM
many thanks, I'll investigate it...

Posttop
david mareSubject: flat xml to nested xml comversion trouble
Author: david mare
Date: 31 Oct 2007 02:40 AM
Many thanks for your suggestion, it was so simple. Here's the resulting xslt:

<?xml version='1.0' ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<root>
<xsl:for-each-group select="root/customer" group-by="acctnum">
<customer>
<name><xsl:value-of select="name"/></name>
<acctnum><xsl:value-of select="acctnum"/></acctnum>
<!-- get all transactions where ordacctnum = saved key -->
<xsl:for-each select="../order[ordacctnum=current-grouping-key()]">
<order>
<ordernum><xsl:value-of select="ordernum"/></ordernum>
<ordacctnum><xsl:value-of select="ordacctnum"/></ordacctnum>
<amount><xsl:value-of select="amount"/></amount>
</order>
</xsl:for-each>
</customer>
</xsl:for-each-group>
</root>
</xsl:template>
</xsl:stylesheet>


Documentflat2nestedgroup.xsl
xslt example of for-each-group

 
Topic Page 1 2 3 4 5 6 7 8 9 Go to previous topicPrev TopicGo to next topicNext Topic
Download A Free Trial of Stylus Studio 6 XML Professional Edition Today! Powered by Stylus Studio, the world's leading XML IDE for XML, XSLT, XQuery, XML Schema, DTD, XPath, WSDL, XHTML, SQL/XML, and XML Mapping!  
go

Log In Options

Site Map | Privacy Policy | Terms of Use | Trademarks
Stylus Scoop XML Newsletter:
W3C Member
Stylus Studio® and DataDirect XQuery ™are from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2016 All Rights Reserved.