XSLT条件无法检查节点是否存在

时间:2015-08-08 04:09:07

标签: xml xslt

每当我尝试将xml转换为json时,几乎没有条件按预期工作。

e.g。

XML

<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>

XSL是:

<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>

此处如果对于一系列deck-&gt; rowNumber-&gt; seatNumber存在,那么它应该打印可用的其他不可用。 但条件是每次都是假的。

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" :
{

}

}

请在这里建议我缺少的东西。我被困在这里两天了。

1 个答案:

答案 0 :(得分:1)

为了演示此问题,您可以将XSLT简化为此,使用一些硬编码值来保持简单。 (尽管请注意seatNumber的声明如何简化为<xsl:variable name="seatNumber" select="." />,而不是第二次重新标记相同的字符串)

<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>

问题是,检查可用性的xsl:if语句是在xsl:for-each语句的上下文中,该语句标记rowsDeck变量。这意味着xsl:for-each中的代码块位于原始文档的不同上下文中。您不是迭代源文档中的节点,而是迭代新创建的原子值。这意味着表达式//ns1:CabinClass将不起作用,因为您的上下文不再是原始XML。

我有点惊讶你没有得到以下几行的错误:

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

无论如何,要解决,您可以通过变量(在xsl:for-each之前声明)

创建对原始文档的引用
<xsl:variable name="root" select="/" />

然后,您可以将xsl:if语句更改为:

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

实际上,在这里使用xsl:choose可能更好,同样指定表达式两次。此处也不必使用boolean运算符。当表达式返回一个节点时,如果它存在,if语句将把它评估为真,如果不存在则将其评估为假。

尝试使用此XSLT作为初学者

<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>