Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
| Search | Today's Posts | Mark Forums Read
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
  #1 (permalink)  
Old February 4th, 2006, 07:42 PM
Registered User
 
Join Date: Feb 2006
Location: , , .
Posts: 2
Thanks: 0
Thanked 0 Times in 0 Posts
Default From flat to hierarchical

I'm currently working on a project that requires me to transform a "flat" XML file into a hierarchical structure.

I'm just getting started with XSLT and wanted to know if I'm heading in the right direction with this approach.

This is my source file (somewhat simplified)

<?xml version="1.0" standalone="yes"?>
<DocumentElement>
  <Orders>
    <OrderID>10248</OrderID>
    <CustomerID>VINET</CustomerID>
    <ProductID>11</ProductID>
    <Quantity>12</Quantity>
    <Discount>0</Discount>
  </Orders>
  <Orders>
    <OrderID>10248</OrderID>
    <CustomerID>VINET</CustomerID>
    <ProductID>42</ProductID>
    <Quantity>10</Quantity>
    <Discount>0</Discount>
  </Orders>
  <Orders>
    <OrderID>10248</OrderID>
    <CustomerID>VINET</CustomerID>
    <ProductID>72</ProductID>
    <Quantity>5</Quantity>
    <Discount>0</Discount>
  </Orders>
  <Orders>
    <OrderID>10250</OrderID>
    <CustomerID>HANAR</CustomerID>
    <ProductID>41</ProductID>
    <Quantity>10</Quantity>
    <Discount>0</Discount>
  </Orders>
  <Orders>
    <OrderID>10250</OrderID>
    <CustomerID>HANAR</CustomerID>
    <ProductID>51</ProductID>
    <Quantity>35</Quantity>
    <Discount>0.15</Discount>
  </Orders>
  <Orders>
    <OrderID>10250</OrderID>
    <CustomerID>HANAR</CustomerID>
    <ProductID>65</ProductID>
    <Quantity>15</Quantity>
    <Discount>0.15</Discount>
  </Orders>
</DocumentElement>


And this is what I want to end up with

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<MyOrders>
  <Order>
    <OrderNumber>10248</OrderNumber>
    <CustomerNumber>VINET</CustomerNumber>
    <OrderLines>
      <ProductID>11</ProductID>
      <ProductID>42</ProductID>
      <ProductID>72</ProductID>
    </OrderLines>
  </Order>
  <Order>
    <OrderNumber>10250</OrderNumber>
    <CustomerNumber>HANAR</CustomerNumber>
    <OrderLines>
      <ProductID>41</ProductID>
      <ProductID>51</ProductID>
      <ProductID>65</ProductID>
    </OrderLines>
  </Order>
</MyOrders>

And here is my attempt to write a stylesheet to produce the result.
It works, but I'm not sure about the for-each part.
Is this the optimal way to go or is it a bad implementation.
I also wonder why I have to put the OrderID into a variable before I can use it as an argument in the for-each select.
Could I access the OrderID directly somehow?


<?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"/>
  <xsl:template match="DocumentElement">
    <MyOrders>
      <xsl:apply-templates select="Orders[not(OrderID = preceding::OrderID)]"/>
    </MyOrders>
   </xsl:template>

  <xsl:template match="Orders">
    <xsl:variable name="OrderID" select="OrderID"/>
    <Order>
      <xsl:element name="OrderNumber">
        <xsl:value-of select="OrderID"/>
      </xsl:element>

      <CustomerNumber>
        <xsl:value-of select="CustomerID"/>
      </CustomerNumber>
      <OrderLines>
        <xsl:for-each select="ancestor::*/Orders[OrderID = $OrderID]">
          <ProductID>
            <xsl:value-of select="ProductID"/>
           </ProductID>
        </xsl:for-each>
      </OrderLines>
    </Order>

  </xsl:template>

</xsl:stylesheet>

Thanks in advance

May the source be with you

//seesharper




  #2 (permalink)  
Old February 5th, 2006, 03:56 AM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

It's a viable approach, but not very efficient. As a simple improvement, you could replace the use of the "preceding" axis with preceding-sibling.

The problem you are tackling is generally called "grouping", and there is a whole literature on the subject. Start with http://www.jenitennison.com/xslt/grouping. Grouping using keys (Muenchian grouping) is hard to understand at first but much more efficient for large files. XSLT 2.0 has an <xsl:for-each-group> construct which makes this kind of problem very easy to code.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
  #3 (permalink)  
Old February 5th, 2006, 06:48 AM
Registered User
 
Join Date: Feb 2006
Location: , , .
Posts: 2
Thanks: 0
Thanked 0 Times in 0 Posts
Default


I will look into XSLT 2.0, but since the 2.0 .Net Framework don't support XSLT 2.0, I'm stuck with solutions like this.
Can u believe they didn't put that in, by the way?

Thanks a lot, mhkay





Similar Threads
Thread Thread Starter Forum Replies Last Post
flat vs. hierarchical style asker XML 0 March 28th, 2007 06:16 AM
transform from flat to hierarchical kkt XSLT 5 November 27th, 2006 02:15 AM
flat XML to hierarchical XML eduijs XSLT 1 April 28th, 2006 05:43 AM
translating a flat xml to a hierarchical xml stevea XSLT 4 June 13th, 2005 05:55 PM
How to make hierarchical data "lay flat" using SQL tinlong SQL Language 1 August 1st, 2003 01:38 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.