munish
munish

Reputation: 485

XSLT condition not working to check if node is present or not

Whenever I am trying to transform an xml to json, few conditions are not working as expected.

e.g.

XML is

<ns1:OTA_AirSeatMapRS 
    xmlns:ns1="http://www.opentravel.org/OTA/2003/05" 
    xmlns="http://www.opentravel.org/OTA/2003/05" 
    xmlns:fo="http://xml.amadeus.com/SMPRES_97_1_IA" 
    xmlns:helper="com.openjaw.rules.XSLHelper" Version="1.0" >

   <ns1:Success />
   <ns1:SeatMapResponses>
      <ns1:SeatMapResponse>
         <ns1:SeatMapDetails MaxRow="A|C|D|E|F|G|H|K" OverwingEnd="28" OverwingStart="11" SpaceAfter="C|G">
            <ns1:CabinClass CabinType="N" EndingRow="44" Name="F" StartingRow="11" cabinLocation="M">
               <ns1:AirRows>
                  <ns1:AirRow MaxNumberOfSeats="6" RowNumber="11">
                     <ns1:AirSeats>
                        <ns1:AirSeat SeatAvailability="" SeatCharacteristics="I" SeatNumber="C" />
                        <ns1:AirSeat SeatAvailability="" SeatCharacteristics="8" SeatNumber="D" />
                        <ns1:AirSeat SeatAvailability="" SeatCharacteristics="8" SeatNumber="E" />
                        <ns1:AirSeat SeatAvailability="" SeatCharacteristics="8" SeatNumber="F" />
                        <ns1:AirSeat SeatAvailability="" SeatCharacteristics="8" SeatNumber="G" />
                        <ns1:AirSeat SeatAvailability="" SeatCharacteristics="I" SeatNumber="H" />
                     </ns1:AirSeats>
                     <ns1:AirRowCharacteristics />
                  </ns1:AirRow>
                  <ns1:AirRow MaxNumberOfSeats="1" RowNumber="12">
                     <ns1:AirSeats>
                        <ns1:AirSeat SeatAvailability="" SeatCharacteristics="I" SeatNumber="F" />
                     </ns1:AirSeats>
                     <ns1:AirRowCharacteristics />
                  </ns1:AirRow>
                  <ns1:AirRow MaxNumberOfSeats="0" RowNumber="13">
                     <ns1:AirSeats />
                     <ns1:AirRowCharacteristics>Z</ns1:AirRowCharacteristics>
                  </ns1:AirRow>
                  <ns1:AirRow MaxNumberOfSeats="0" RowNumber="14">
                     <ns1:AirSeats />
                     <ns1:AirRowCharacteristics />
                  </ns1:AirRow>
                  <ns1:AirRow MaxNumberOfSeats="3" RowNumber="15">
                     <ns1:AirSeats>
                        <ns1:AirSeat SeatAvailability="O" SeatCharacteristics="" SeatNumber="A" />
                        <ns1:AirSeat SeatAvailability="O" SeatCharacteristics="" SeatNumber="C" />
                        <ns1:AirSeat SeatAvailability="O" SeatCharacteristics="" SeatNumber="D" />
                     </ns1:AirSeats>
                     <ns1:AirRowCharacteristics />


                  </ns1:AirRow>
               </ns1:AirRows>
            </ns1:CabinClass>
         <

    /ns1:SeatMapDetails>
          </ns1:SeatMapResponse>
       </ns1:SeatMapResponses>
    <ns1:cabinLocations>
          <ns1:cabinLocation Characteristic="L" Description="Lowerdeck" />
          <ns1:cabinLocation Characteristic="M" Description="Maindeck" />
          <ns1:cabinLocation Characteristic="U" Description="Upperdeck" />
       </ns1:cabinLocations>
    </ns1:OTA_AirSeatMapRS>

And XSL is :

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ns1="http://www.opentravel.org/OTA/2003/05"
    xmlns:ota="http://www.opentravel.org/OTA/2003/05"   
    xmlns="http://www.opentravel.org/OTA/2003/05" xmlns:math="http://exslt.org/math"
    xmlns:str="http://exslt.org/strings" extension-element-prefixes="str">

<xsl:template match="/">

"seatLayout" : {
<xsl:for-each select="//ns1:cabinLocations/ns1:cabinLocation">
"<xsl:value-of select="@Description"/>" :
{
<xsl:variable name="deck" select="@Characteristic"/>
<xsl:if test="//ns1:CabinClass[@cabinLocation=$deck]">
<xsl:variable name="rowsInDeck" select="//ns1:CabinClass[@cabinLocation=$deck]/../@MaxRow"/>
"equipmentInfo":{
"columns":"<xsl:value-of select="$rowsInDeck"/>",
"columnSpaceAfter":"<xsl:value-of select="//ns1:CabinClass[@cabinLocation=$deck]/../@SpaceAfter"/>",
"wingsStart":"<xsl:value-of select="math:lowest(//ns1:SeatMapDetails[@OverwingStart!='']/ns1:CabinClass[@cabinLocation=$deck]/../@OverwingStart)"/>",
"wingsEnd":"<xsl:value-of select="math:highest(//ns1:SeatMapDetails[@OverwingEnd!='']/ns1:CabinClass[@cabinLocation=$deck]/../@OverwingEnd)"/>",
"cabinName":"<xsl:value-of select="//ns1:CabinClass[@cabinLocation=$deck]/@Name"/>",
"cabinType":"<xsl:value-of select="//ns1:CabinClass[@cabinLocation=$deck]/@CabinType"/>",
"cabinStart":"<xsl:value-of select="math:lowest(//ns1:CabinClass[@cabinLocation=$deck]/@StartingRow)"/>",
"cabinEnd":"<xsl:value-of select="math:highest(//ns1:CabinClass[@cabinLocation=$deck]/@EndingRow)"/>"
}
"rowInfo":{
<xsl:for-each select="//ns1:CabinClass[@cabinLocation=$deck]/ns1:AirRows/ns1:AirRow">
<xsl:variable name="rowNumber" select="@RowNumber"/>
<xsl:variable name="rowCharacteristic" select="//ns1:CabinClass[@cabinLocation=$deck]/ns1:AirRows/ns1:AirRow[@RowNumber=$rowNumber]/ns1:AirRowCharacteristics"/>

"<xsl:value-of select="$rowNumber"/>:{
"rchar":"<xsl:value-of select="$rowCharacteristic" />
"rseats":[
<xsl:for-each select="str:tokenize($rowsInDeck, '|')">
<xsl:variable name="pos" select="position()"/>
<xsl:variable name="seatNumber" select="str:tokenize($rowsInDeck, '|')[position()=$pos]"/>
{
<xsl:value-of select="$deck"/>##<xsl:value-of select="$rowNumber"/>##<xsl:value-of select="$seatNumber"/>
<xsl:if test="boolean(//ns1:CabinClass[@cabinLocation=$deck]/ns1:AirRows/ns1:AirRow[@RowNumber=$rowNumber]/ns1:AirSeats/ns1:AirSeat[@SeatNumber=$seatNumber])">
"available"
</xsl:if>
<xsl:if test="not(boolean(//ns1:CabinClass[@cabinLocation=$deck]/ns1:AirRows/ns1:AirRow[@RowNumber=$rowNumber]/ns1:AirSeats/ns1:AirSeat[@SeatNumber=$seatNumber]))">
"NOT available"
</xsl:if>

}
</xsl:for-each>
]
}
<xsl:if test="position()!=last()">,</xsl:if>
</xsl:for-each>
}
</xsl:if>
}
<xsl:if test="position()!=last()">,</xsl:if>
</xsl:for-each> 
}


</xsl:template>

</xsl:stylesheet>

Here if for a sequence of deck->rowNumber->seatNumber is present then it should print available else not available. But the condition is giving false everytime.

Output : 

<?xml version="1.0" encoding="UTF-8"?>

"seatLayout" : {

"Lowerdeck" :
{

}
,
"Maindeck" :
{

"equipmentInfo":{
"columns":"A|C|D|E|F|G|H|K",
"columnSpaceAfter":"C|G",
"wingsStart":"11",
"wingsEnd":"28",
"cabinName":"F",
"cabinType":"N",
"cabinStart":"11",
"cabinEnd":"44"
}
"rowInfo":{


"11:{
"rchar":"
"rseats":[

{
M##11##A
"NOT available"


}

{
M##11##C
"NOT available"


}

{
M##11##D
"NOT available"


}

{
M##11##E
"NOT available"


}

{
M##11##F
"NOT available"


}

{
M##11##G
"NOT available"


}

{
M##11##H
"NOT available"


}

{
M##11##K
"NOT available"


}

]
}
,

"12:{
"rchar":"
"rseats":[

{
M##12##A
"NOT available"


}

{
M##12##C
"NOT available"


}

{
M##12##D
"NOT available"


}

{
M##12##E
"NOT available"


}

{
M##12##F
"NOT available"


}

{
M##12##G
"NOT available"


}

{
M##12##H
"NOT available"


}

{
M##12##K
"NOT available"


}

]
}
,

"13:{
"rchar":"Z
"rseats":[

{
M##13##A
"NOT available"


}

{
M##13##C
"NOT available"


}

{
M##13##D
"NOT available"


}

{
M##13##E
"NOT available"


}

{
M##13##F
"NOT available"


}

{
M##13##G
"NOT available"


}

{
M##13##H
"NOT available"


}

{
M##13##K
"NOT available"


}

]
}
,

"14:{
"rchar":"
"rseats":[

{
M##14##A
"NOT available"


}

{
M##14##C
"NOT available"


}

{
M##14##D
"NOT available"


}

{
M##14##E
"NOT available"


}

{
M##14##F
"NOT available"


}

{
M##14##G
"NOT available"


}

{
M##14##H
"NOT available"


}

{
M##14##K
"NOT available"


}

]
}
,

"15:{
"rchar":"
"rseats":[

{
M##15##A
"NOT available"


}

{
M##15##C
"NOT available"


}

{
M##15##D
"NOT available"


}

{
M##15##E
"NOT available"


}

{
M##15##F
"NOT available"


}

{
M##15##G
"NOT available"


}

{
M##15##H
"NOT available"


}

{
M##15##K
"NOT available"


}

]
}

}

}
,
"Upperdeck" :
{

}

}

Please suggest what I am missing here. I am stuck in this for two days.

Upvotes: 1

Views: 1565

Answers (1)

Tim C
Tim C

Reputation: 70648

To demonstrate the issue, your XSLT can be simplified to this, using some hard-coded values to keep it simple. (Although do note how the declaration of seatNumber can be simplified to <xsl:variable name="seatNumber" select="." /> rather than re-tokenizing the same string for a second time)

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ns1="http://www.opentravel.org/OTA/2003/05"
    xmlns:str="http://exslt.org/strings" extension-element-prefixes="str">

    <xsl:output method="text" />

    <xsl:template match="/">
        <xsl:variable name="deck" select="'M'" />
        <xsl:variable name="rowNumber" select="'11'" />
        <xsl:variable name="rowsInDeck" select="//ns1:CabinClass[@cabinLocation=$deck]/../@MaxRow"/>

        <xsl:for-each select="str:tokenize($rowsInDeck, '|')">
            <xsl:variable name="seatNumber" select="." />
            <xsl:value-of select="$deck"/>##<xsl:value-of select="$rowNumber"/>##<xsl:value-of select="$seatNumber"/>

            <xsl:if test="boolean(//ns1:CabinClass[@cabinLocation=$deck]/ns1:AirRows/ns1:AirRow[@RowNumber=$rowNumber]/ns1:AirSeats/ns1:AirSeat[@SeatNumber=$seatNumber])">
                "available"
            </xsl:if>
            <xsl:if test="not(boolean(//ns1:CabinClass[@cabinLocation=$deck]/ns1:AirRows/ns1:AirRow[@RowNumber=$rowNumber]/ns1:AirSeats/ns1:AirSeat[@SeatNumber=$seatNumber]))">
                "NOT available"
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

The problem is, your xsl:if statements that check for availability are within the context of an xsl:for-each statement which tokenizes the rowsDeck variable. This means the block of code within xsl:for-each is in a different context of the original document. You are not iterating over nodes in the source document, but newly created atomic values. This means the expression //ns1:CabinClass will not work, as your context is not the original XML any more.

I am partially surprised you did not get an error along the following lines:

Leading '/' cannot select the root node of the tree containing the context item:  the context item is not a node

Anyway, to solve, you can create a reference to the original document by means of a variable (declared before the xsl:for-each)

<xsl:variable name="root" select="/" />

Then, you can change your xsl:if statement to this:

<xsl:if test="boolean($root//ns1:CabinClass[@cabinLocation=$deck]/ns1:AirRows/ns1:AirRow[@RowNumber=$rowNumber]/ns1:AirSeats/ns1:AirSeat[@SeatNumber=$seatNumber])">

Actually, it might be better to use xsl:choose here, to same specifying the expression twice. It is also unnecessary to use the boolean operator here. As the expression returns a node, the if statement will evaluate it to true anyway if it exists, and false if not.

Try this XSLT for starters

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ns1="http://www.opentravel.org/OTA/2003/05"
    xmlns:str="http://exslt.org/strings" extension-element-prefixes="str">

    <xsl:output method="text" />

    <xsl:template match="/">
        <xsl:variable name="deck" select="'M'" />
        <xsl:variable name="rowNumber" select="'11'" />
        <xsl:variable name="rowsInDeck" select="//ns1:CabinClass[@cabinLocation=$deck]/../@MaxRow"/>

        <xsl:variable name="root" select="/" />
        <xsl:for-each select="str:tokenize($rowsInDeck, '|')">
            <xsl:variable name="seatNumber" select="." />
            <xsl:value-of select="$deck"/>##<xsl:value-of select="$rowNumber"/>##<xsl:value-of select="$seatNumber"/>
            <xsl:choose>
                <xsl:when test="$root//ns1:CabinClass[@cabinLocation=$deck]/ns1:AirRows/ns1:AirRow[@RowNumber=$rowNumber]/ns1:AirSeats/ns1:AirSeat[@SeatNumber=$seatNumber]">
                    "available"
                </xsl:when>
                <xsl:otherwise>
                    "NOT available"
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Related Questions