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 June 7th, 2011, 06:55 AM
Authorized User
 
Join Date: Apr 2006
Posts: 24
Thanks: 0
Thanked 0 Times in 0 Posts
Default Recursive Call Help

I’m trying to obtain the following output:

<?xmlversion="1.0"encoding="utf-8"?>
<TripXMLxmlns:msxsl="urn:schemas-microsoft-com:xslt">
<TripSection>
<DetailSegNum="2"From="GIG"To="PTY"TripItem="1" />
<DetailSegNum="4"From="PTY"To="BOG"TripItem="2" />
<DetailSegNum="8"From="LIM"To="SCL"TripItem="4" />
<DetailSegNum="10"From="SCL"To="GIG"TripItem="5" />
</TripSection>
</TripXML>

From the following input:

<?xmlversion="1.0"encoding="utf-8"?>
<Trip>
<FlightSection>
<FlightSegNbr="002"OrigAir="GIG"DestAir="PTY" />
<FlightSegNbr="004"OrigAir="PTY"DestAir="BOG" />
<FlightSegNbr="008"OrigAir="LIM"DestAir="SCL" />
<FlightSegNbr="010"OrigAir="SCL"DestAir="GIG" />
</FlightSection>
</Trip>

There is no Tripitem 3 as the “To” on SegNum 4 differs to the “From” on SegNum 8 (i.e. an unknown trip to get from “BOG” to “LIM” - & I know it could be more than 1, but that’s not an issue)

Within main template I have this:

<xsl:attributename="TripItem">
<xsl:call-templatename="GetTripItem">
<xsl:with-paramname="thisSeg"select="number(@SegNbr)"/>
<xsl:with-paramname="lastSeg"select="0"/>
<xsl:with-paramname="previousDest"select="***"/>
<xsl:with-paramname="previousCoupon"select="0"/>
</xsl:call-template>
</xsl:attribute>

& the GetTripItem template is as follows:

<xsl:templatename="GetTripItem">
<xsl:paramname="thisSeg" />
<xsl:paramname="lastSeg" />
<xsl:paramname="previousDest" />
<xsl:paramname="previousCoupon" />

<xsl:for-eachselect="/Trip/FlightSection/Flight[number(@SegNbr) &gt; $lastSeg]">
<xsl:choose>
<xsl:whentest="number(@SegNbr) = $thisSeg">
<xsl:value-ofselect="$previousCoupon + 1"/>
</xsl:when>

<xsl:otherwise>
<xsl:iftest="@OrigAir = $previousDest or $previousDest = '***'" >
<xsl:call-templatename="GetTripItem">
<xsl:with-paramname="thisSeg"select="$thisSeg" />
<xsl:with-paramname="lastSeg"select="number(@SegNbr)"/>
<xsl:with-paramname="previousDest"select="@DestAir" />
<xsl:with-paramname="previousCoupon"select="$previousCoupon + 1"/>
</xsl:call-template>
</xsl:if>

<xsl:iftest="@OrigAir != $previousDest">
<xsl:call-templatename="GetTripItem">
<xsl:with-paramname="thisSeg"select="$thisSeg" />
<xsl:with-paramname="lastSeg"select="number(@SegNbr)"/>
<xsl:with-paramname="previousDest"select="@DestAir" />
<xsl:with-paramname="previousCoupon"select="$previousCoupon + 2"/>
</xsl:call-template>
</xsl:if>

</xsl:otherwise>

</xsl:choose>

</xsl:for-each>

</xsl:template>

This however gives me:

<?xmlversion="1.0"encoding="utf-8"?>
<TripXMLxmlns:msxsl="urn:schemas-microsoft-com:xslt">
<TripSection>
<DetailSegNum="2"From="GIG"To="PTY"TripItem="1" />
<DetailSegNum="4"From="PTY"To="BOG"TripItem="31" />
<DetailSegNum="8"From="LIM"To="SCL"TripItem="4331" />
<DetailSegNum="10"From="SCL"To="GIG"TripItem="64535331" />
</TripSection>
</TripXML>


It appears (to me) that as each recursive call is doing a for-each, the more flights the more characters in the TripItem

Any help much appreciated; otherwise it’s dusting down the .net skills
Regards
Nigel
 
Old June 7th, 2011, 07:51 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Can you edit or repost your code samples so that they have any required white space to be readable and well-formed markup?
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old June 7th, 2011, 08:02 AM
Authorized User
 
Join Date: Apr 2006
Posts: 24
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I’m trying to obtain the following output:
Code:
<?xmlversion="1.0"encoding="utf-8"?>
<TripXMLxmlns:msxsl="urn:schemas-microsoft-com:xslt">
<TripSection>
  <DetailSegNum="2"From="GIG"To="PTY"TripItem="1" />
  <DetailSegNum="4"From="PTY"To="BOG"TripItem="2" />
  <DetailSegNum="8"From="LIM"To="SCL"TripItem="4" />
  <DetailSegNum="10"From="SCL"To="GIG"TripItem="5" />
</TripSection>
</TripXML>
From the following input:
Code:
<?xmlversion="1.0"encoding="utf-8"?>
<Trip>
     <FlightSection>
            <FlightSegNbr="002"OrigAir="GIG"DestAir="PTY" />
            <FlightSegNbr="004"OrigAir="PTY"DestAir="BOG" />
            <FlightSegNbr="008"OrigAir="LIM"DestAir="SCL" />
            <FlightSegNbr="010"OrigAir="SCL"DestAir="GIG" />
     </FlightSection>
</Trip>
There is no Tripitem 3 as the “To” on SegNum 4 differs to the “From” on SegNum 8 (i.e. an unknown trip to get from “BOG” to “LIM” - & I know it could be more than 1, but that’s not an issue)
Within main template I have this:
Code:
                                        <xsl:attributename="TripItem">
 
                                              <xsl:call-templatename="GetTripItem">
                                                     <xsl:with-paramname="thisSeg"select="number(@SegNbr)"/>
                                                     <xsl:with-paramname="lastSeg"select="0"/>
                                                     <xsl:with-paramname="previousDest"select="***"/>
                                                     <xsl:with-paramname="previousCoupon"select="0"/>
                                              </xsl:call-template>
 
                                       </xsl:attribute>
& the GetTripItem template is as follows:
Code:
<xsl:templatename="GetTripItem">
            <xsl:paramname="thisSeg" />
            <xsl:paramname="lastSeg" />
            <xsl:paramname="previousDest" />
            <xsl:paramname="previousCoupon" />
 
            <xsl:for-eachselect="/Trip/FlightSection/Flight[number(@SegNbr) &gt; $lastSeg]">
 
                         <xsl:choose>
                                <xsl:whentest="number(@SegNbr) = $thisSeg">
                                       <xsl:value-ofselect="$previousCoupon + 1"/>
                                </xsl:when>
 
                                <xsl:otherwise>
                                       <xsl:iftest="@OrigAir = $previousDest or $previousDest = '***'" >
                                              <xsl:call-templatename="GetTripItem">
                                                     <xsl:with-paramname="thisSeg"select="$thisSeg" />
                                                     <xsl:with-paramname="lastSeg"select="number(@SegNbr)"/>
                                                     <xsl:with-paramname="previousDest"select="@DestAir" />
                                                     <xsl:with-paramname="previousCoupon"select="$previousCoupon + 1"/>
                                              </xsl:call-template>
                                       </xsl:if>
 
                                       <xsl:iftest="@OrigAir != $previousDest">
                                              <xsl:call-templatename="GetTripItem">
                                                     <xsl:with-paramname="thisSeg"select="$thisSeg" />
                                                     <xsl:with-paramname="lastSeg"select="number(@SegNbr)"/>
                                                     <xsl:with-paramname="previousDest"select="@DestAir" />
                                                     <xsl:with-paramname="previousCoupon"select="$previousCoupon + 2"/>
                                              </xsl:call-template>
                                       </xsl:if>
 
                                </xsl:otherwise>
 
                         </xsl:choose>
 
            </xsl:for-each>
 
     </xsl:template>
This however gives me:
Code:
<?xmlversion="1.0"encoding="utf-8"?>
<TripXMLxmlns:msxsl="urn:schemas-microsoft-com:xslt">
<TripSection>
  <DetailSegNum="2"From="GIG"To="PTY"TripItem="1" />
  <DetailSegNum="4"From="PTY"To="BOG"TripItem="31" />
  <DetailSegNum="8"From="LIM"To="SCL"TripItem="4331" />
  <DetailSegNum="10"From="SCL"To="GIG"TripItem="64535331" />
</TripSection>
</TripXML>
It appears (to me) that as each recursive call is doing a for-each, the more flights the more characters in the TripItem
 
Old June 7th, 2011, 08:11 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Sorry but stuff like
Code:
<DetailSegNum="2"From="GIG"To="PTY"TripItem="1" />
is not well-formed XML.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old June 7th, 2011, 08:21 AM
Authorized User
 
Join Date: Apr 2006
Posts: 24
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Sorry, didn't even notice that - some copy& paste "feature"


I’m trying to obtain the following output:
Code:
<?xml version="1.0" encoding="utf-8"?>
<TripXML xmlns:msxsl="urn:schemas-microsoft-com:xslt">
  <TripSection>
    <Detail SegNum="2" From="GIG" To="PTY" TripItem="1" />
    <Detail SegNum="4" From="PTY" To="BOG" TripItem="2" />
    <Detail SegNum="8" From="LIM" To="SCL" TripItem="4" />
    <Detail SegNum="10" From="SCL" To="GIG" TripItem="5" />
  </TripSection>
</TripXML>
From the following input:
Code:
<?xml version="1.0" encoding="utf-8"?>
<Trip>
 <FlightSection>
  <Flight SegNbr="002" OrigAir="GIG" DestAir="PTY" />
  <Flight SegNbr="004" OrigAir="PTY" DestAir="BOG" />
  <Flight SegNbr="008" OrigAir="LIM" DestAir="SCL" />
  <Flight SegNbr="010" OrigAir="SCL" DestAir="GIG" />
 </FlightSection>
</Trip>
There is no Tripitem 3 as the “To” on SegNum 4 differs to the “From” on SegNum 8 (i.e. an unknown trip to get from “BOG” to “LIM” - & I know it could be more than 1, but that’s not an issue)
Within main template I have this:
Code:
      <xsl:attribute name="TripItem">
       <xsl:call-template name="GetTripItem">
        <xsl:with-param name="thisSeg" select="number(@SegNbr)"/>
        <xsl:with-param name="lastSeg"  select="0"/>
        <xsl:with-param name="previousDest" select="***"/>
        <xsl:with-param name="previousCoupon" select="0"/>
       </xsl:call-template>
      </xsl:attribute>
& the GetTripItem template is as follows:
Code:
 <xsl:template name="GetTripItem">
  <xsl:param name="thisSeg" />
  <xsl:param name="lastSeg" />
  <xsl:param name="previousDest" />
  <xsl:param name="previousCoupon" />
  <xsl:for-each select="/Trip/FlightSection/Flight[number(@SegNbr) &gt; $lastSeg]">
    <xsl:choose>
     <xsl:when test="number(@SegNbr) = $thisSeg">
      <xsl:value-of select="$previousCoupon + 1"/>
     </xsl:when>
     <xsl:otherwise>
      <xsl:if test="@OrigAir = $previousDest or $previousDest = '***'" >
       <xsl:call-template name="GetTripItem">
        <xsl:with-param name="thisSeg" select="$thisSeg" />
        <xsl:with-param name="lastSeg" select="number(@SegNbr)"/>
        <xsl:with-param name="previousDest" select="@DestAir" />
        <xsl:with-param name="previousCoupon" select="$previousCoupon + 1"/>
       </xsl:call-template>
      </xsl:if>
      <xsl:if test="@OrigAir != $previousDest">
       <xsl:call-template name="GetTripItem">
        <xsl:with-param name="thisSeg" select="$thisSeg" />
        <xsl:with-param name="lastSeg" select="number(@SegNbr)"/>
        <xsl:with-param name="previousDest" select="@DestAir" />
        <xsl:with-param name="previousCoupon" select="$previousCoupon + 2"/>
       </xsl:call-template>
      </xsl:if>
     </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each>
 </xsl:template>
This however gives me:
Code:
<?xml version="1.0" encoding="utf-8"?>
<TripXML xmlns:msxsl="urn:schemas-microsoft-com:xslt">
  <TripSection>
    <Detail SegNum="2" From="GIG" To="PTY" TripItem="1" />
    <Detail SegNum="4" From="PTY" To="BOG" TripItem="31" />
    <Detail SegNum="8" From="LIM" To="SCL" TripItem="4331" />
    <Detail SegNum="10" From="SCL" To="GIG" TripItem="64535331" />
  </TripSection>
</TripXML>
It appears (to me) that as each recursive call is doing a for-each, the more flights the more characters in the TripItem
 
Old June 7th, 2011, 09:29 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Can you explain in plain English what that template is supposed to compute? It is obviously not doing what you want and you have posted the output you want but I am currently not sure how the output you want relates to the input you have.
And what is the context node when you call the template?
Do you use (or want to use) XSLT 2.0 or 1.0 to solve the problem?
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old June 7th, 2011, 09:47 AM
Authorized User
 
Join Date: Apr 2006
Posts: 24
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hi Martin,

In English, that hopefully makes sense, it's to do with flights within a trip. The first item is by default 1, the next will be 2 if the arrival of the previous one is the same as the departure of the current one, if not it will be 3. So a trip from London to New York is 1 if the next flight is New York to Chicago it's 2, but if it's Boston to Chicago it's 3. (in the latter however they get from New York to Boston would be 2, but I don't care about that).
I could use preceding to check if the arrival of the previous one is the same as the departure of the current one, but i don't know tripnumber of the preceding one without re-calculating .

the template is being called within:

Code:
 <xsl:template match="/Trip">
  <TripXML>
   <xsl:call-template name="AirSegments" />
  </TripXML>
 </xsl:template>
 <xsl:template name="AirSegments">
  <TripSection>
   <xsl:for-each select="FlightSection/Flight">
     <Detail>
      <xsl:attribute name="SegNum">
       <xsl:value-of select="number(@SegNbr)"/>
      </xsl:attribute>
      <xsl:attribute name="From">
       <xsl:value-of select="@OrigAir"/>
      </xsl:attribute>
      <xsl:attribute name="To">
       <xsl:value-of select="@DestAir"/>
      </xsl:attribute>
      <xsl:attribute name="TripItem">
       <xsl:call-template name="GetTripItem">
        <xsl:with-param name="thisSeg" select="number(@SegNbr)"/>
        <xsl:with-param name="lastSeg"  select="0"/>
        <xsl:with-param name="previousDest" select="***"/>
        <xsl:with-param name="previousCoupon" select="0"/>
       </xsl:call-template>
      </xsl:attribute>
     </Detail>
   </xsl:for-each>
  </TripSection>
 </xsl:template>
Currently using XSLT 1.0 - no chance of using 2.0

Nigel
 
Old June 7th, 2011, 10:04 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

It looks to me as you could walk the "Flight" elements sibling by sibling and pass on the current trip number. That way you don't need any recursion and no named templates:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">
  
  <xsl:output indent="yes"/>
  
  <xsl:template match="Trip">
    <TripXML>
      <xsl:apply-templates/>
    </TripXML>
  </xsl:template>
  
  <xsl:template match="FlightSection">
    <TripSection>
      <xsl:apply-templates select="Flight[1]"/>
    </TripSection>
  </xsl:template>
  
  <xsl:template match="Flight">
    <xsl:param name="trip-item" select="1"/>
    <Detail SegNum="{number(@SegNbr)}" From="{@OrigAir}" To="{@DestAir}" TripItem="{$trip-item}"/>
    <xsl:variable name="next" select="following-sibling::Flight[1]"/>
    <xsl:choose>
      <xsl:when test="@DestAir = $next/@OrigAir">
        <xsl:apply-templates select="$next">
          <xsl:with-param name="trip-item" select="$trip-item + 1"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="$next">
          <xsl:with-param name="trip-item" select="$trip-item + 2"/>
        </xsl:apply-templates>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
</xsl:stylesheet>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old June 7th, 2011, 10:11 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

Like Martin I am also confused how your input relates to your output and why you think you need recursive templates.

The following produce the required output from the specified input:

Code:
<xsl:template match="Trip">
<TripXML>
  <TripSection>
    <xsl:apply-templates select="FlightSection/Flight">
    <xsl:sort select="@SegNbr" data-type="number"/>
    </xsl:apply-templates>
  </TripSection>
</TripXML>
</xsl:template>
 
<xsl:template match="Flight">
  <Detail SegNum="{number(@SegNbr)}" From="{@OrigAir}" To="{@DestAir}"/> 
</xsl:template>
As there are 'missing' elements in the input, and you also want these elements to be missing in the output there is a simple one to one mapping - which doesn't appear to require anything complicated at all.
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?

Last edited by samjudson; June 7th, 2011 at 10:15 AM..
 
Old June 7th, 2011, 10:17 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

Sorry, scrap that - It was the fact your put your output before your input was getting me confused. I see why you might need recursion, and I'll look at a better solution.
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?





Similar Threads
Thread Thread Starter Forum Replies Last Post
how to use recursive apply vs call template FXYLDY XSLT 2 June 15th, 2010 01:57 PM
Help with a recursive Query!!! dbayona SQL Server 2005 1 December 20th, 2007 07:40 AM
Problem in recursive call chennaiguy XSLT 3 March 22nd, 2007 11:18 AM
recursive XSLT Help boates XSLT 2 January 11th, 2006 03:50 PM
Recursive Transform chuck.boyer XSLT 0 December 5th, 2005 05:51 PM





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