Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
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
 
Old April 26th, 2007, 06:23 AM
Authorized User
 
Join Date: Apr 2007
Posts: 12
Thanks: 0
Thanked 0 Times in 0 Posts
Default Grouping Solution needed

Original Input XML:

<?xml version="1.0" encoding="UTF-8"?>
<bb3:Reservations xmlns:bb3="http://www.ourbedandbreakfast.com/sample1">
    <bb3:Reservation RoomNum="106" InvoiceNum="BB3002">
        <bb3:Customer FirstName="Tom" LastName="Cruise" />
        <bb3:Customer FirstName="Nicole" LastName="Kidman" />
    </bb3:Reservation>
    <bb3:Reservation RoomNum="206" InvoiceNum="BB5010">
        <bb3:Customer FirstName="Tom" LastName="Cruise" />
    </bb3:Reservation>
    <bb3:Reservation RoomNum="506" InvoiceNum="BB6020">
        <bb3:Customer LastName="Madonna" />
    </bb3:Reservation>
</bb3:Reservations>


I want to get a list of all invoice numbers per customer, like below.

Example of Output XML:

<bb3:CustomerVisits>
    <bb3:Booking>
        <bb3:Customer FirstName="Tom" LastName="Cruise" />
        <InvoiceNum>BB3002</InvoiceNum>
        <InvoiceNum>BB5010</InvoiceNum>
    </bb3:Booking>
    <bb3:Booking>
        <bb3:Customer FirstName="Nicole" LastName="Kidman" />
        <InvoiceNum>BB3002</InvoiceNum>
    </bb3:Booking>
    <bb3:Booking>
        <bb3:Customer LastName="Madonna" />
        <InvoiceNum>BB6020</InvoiceNum>
    </bb3:Booking>
</bb3:CustomerVisits>

Not sure where to start. I read something about Grouping by 2 levels, but was confused since I am new to XSLT.
Grouping by 2 levels: http://www.dpawson.co.uk/xsl/sect2/N4486.html#d5891e235
 
Old April 26th, 2007, 06:37 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

This is a straightforward single-level grouping problem, except that your grouping key is a compound key, so you need an expression such as concat(@FirstName, '~', @LastName).

Grouping in XSLT 2.0 is easy using the xsl:for-each-group construct.

In XSLT 1.0 it's surprisingly difficult, but there are coding patterns that you can reuse. See http://www.jenitennison.com/xslt/grouping. For a compound grouping key, I think you'll need to use the Muenchian grouping approach.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old April 26th, 2007, 06:42 AM
Authorized User
 
Join Date: Apr 2007
Posts: 12
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Thanks Michael, I will look at the resources you suggested and give it a go.

Also FirstName is an optional will the concat key you suggest still work then?
 
Old April 26th, 2007, 07:01 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

concat() treats an empty sequence the same as a zero-length string, so @FirstName="" will be treated the same as an element with no @FirstName. If you want to treat them differently, you'll have to refine the grouping key, for example include count(@FirstName) as a component.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old April 27th, 2007, 05:42 AM
Authorized User
 
Join Date: Apr 2007
Posts: 12
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I tried the below in oXygen's XSLT debugger and it is spitting out the names. But how do I get it to output as expected with InvoiceNum as well?

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:bb3="http://www.ourbedandbreakfast.com/sample1">
<xsl:output method="text" indent="yes" encoding="UTF-8"/>
<xsl:template match="bb3:Reservations">
  <xsl:for-each-group select="bb3:Reservation/bb3:Customer" group-by="concat(@FirstName, ' ', @LastName)">
    <xsl:value-of select="current-grouping-key()"/>
    <xsl:for-each select="current-group()">
      <xsl:value-of select="@InvoiceNum"/>
    </xsl:for-each>
  </xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>

I am trying to get my output to look like this:

Tom Cruise
BB3002
BB5010
Nicole Kidman
BB3002
Madonna
BB6020
 
Old April 27th, 2007, 05:56 AM
joefawcett's Avatar
Wrox Author
 
Join Date: Jun 2003
Posts: 3,074
Thanks: 1
Thanked 38 Times in 37 Posts
Default

Did you add the declaration to map bb3 to the appropriate URI?

--

Joe (Microsoft MVP - XML)
 
Old April 27th, 2007, 06:02 AM
Authorized User
 
Join Date: Apr 2007
Posts: 12
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Quote:
quote:Originally posted by joefawcett
 Did you add the declaration to map bb3 to the appropriate URI?

Joe I figured that out and edited my message right before your post. I am getting closer, but still not there yet.

Can you look at where I am at now and assist. Thanks.
 
Old April 27th, 2007, 06:12 AM
Authorized User
 
Join Date: Apr 2007
Posts: 12
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Okay making this change:
<xsl:value-of select="../@InvoiceNum"/>

Seems to get what I am expecting.

I am very new to this and I am wondering if this code looks efficient enough, correct, and resistant to change. Any improvements or suggestions appreciated.

Now onto getting it into the XML format I need. Thanks all!

I might run into some problems getting it formatted into XML like needed so if those who helped and others can check back here in this post, I would appreciate the assistance while I learn the ropes.
 
Old April 27th, 2007, 07:25 AM
Authorized User
 
Join Date: Apr 2007
Posts: 12
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I have this so far, but I need to figure out how to get
<bb3:Customer FirstName="Tom" LastName="Cruise" />
into each Booking
I am only getting: FirstName="Tom" LastName="Cruise">

Obviously this:
<xsl:copy-of select="@*"/>
is not correct, since its missing the <bb3:Customer />.

Can someone help.

Code:
<xsl:template match="bb3:Reservations">
  <bb3:CustomerVisits>
  <xsl:for-each-group select="bb3:Reservation/bb3:Customer" group-by="concat(@FirstName, '~', @LastName)">
         <bb3:Booking>
          <xsl:copy-of select="@*"/>
    <xsl:for-each select="current-group()">
      <InvoiceNum><xsl:value-of select="../@InvoiceNum"/></InvoiceNum>
    </xsl:for-each>
    </bb3:Booking>
  </xsl:for-each-group>
   </bb3:CustomerVisits>
</xsl:template>
 
Old April 27th, 2007, 07:55 AM
Authorized User
 
Join Date: Apr 2007
Posts: 12
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Okay this seems to work (see below). I think the XSL is complete, experts let me know if there are any mistakes as this is my first attempt at learning XSLT.

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:bb3="http://www.ourbedandbreakfast.com/sample1">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="bb3:Reservations">
  <bb3:CustomerVisits>
  <xsl:for-each-group select="bb3:Reservation/bb3:Customer" group-by="concat(@FirstName, '~', @LastName)">
         <bb3:Booking>
             <xsl:copy>
               <xsl:copy-of select="@*"/>
               <xsl:apply-templates mode="copy"/>
             </xsl:copy>
    <xsl:for-each select="current-group()">
      <InvoiceNum><xsl:value-of select="../@InvoiceNum"/></InvoiceNum>
    </xsl:for-each>
    </bb3:Booking>
  </xsl:for-each-group>
   </bb3:CustomerVisits>
</xsl:template>
</xsl:stylesheet>

Final Output:

<?xml version="1.0" encoding="UTF-8"?>
<bb3:CustomerVisits xmlns:bb3="http://www.ourbedandbreakfast.com/sample1">
 <bb3:Booking>
  <bb3:Customer FirstName="Tom" LastName="Cruise"/>
      <InvoiceNum>BB3002</InvoiceNum>
      <InvoiceNum>BB5010</InvoiceNum>
 </bb3:Booking>
 <bb3:Booking>
  <bb3:Customer FirstName="Nicole" LastName="Kidman"/>
      <InvoiceNum>BB3002</InvoiceNum>
 </bb3:Booking>
 <bb3:Booking>
  <bb3:Customer LastName="Madonna"/>
      <InvoiceNum>BB6020</InvoiceNum>
 </bb3:Booking>
</bb3:CustomerVisits>





Similar Threads
Thread Thread Starter Forum Replies Last Post
A serious string problem. Urgent solution needed. asfak XSLT 2 November 28th, 2007 06:08 AM
Protect cells and allow grouping/un-grouping sfreuden Excel VBA 4 December 14th, 2006 08:01 AM
Solution needed very urgent: fcntl and flock hariharan Visual C++ 1 November 22nd, 2005 09:07 AM
Grouping List chemi XSLT 1 October 20th, 2005 09:36 AM





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