如何使用previous-sibling检查以前的xpath元素

时间:2013-08-08 20:59:03

标签: xml xslt xpath axes

我正在使用营销平台来展示一个人为航班订购的行李。一名乘客可以将多个细分作为整体旅程的一部分。因此,如果我们有如下所示的记录(每个记录都有一个唯一的值,因为它在被拉出之前都被插入到数据库中,这里的xml是我正在使用的模型)。

编辑8/9 - 下面的实际XML和修订的XSLT。另外,如果您在Bag部分查看此链接(http://f.spiritairlines.com/ats/msg.aspx?sg1=2e4a4d00cb00be84c598b618d6556e3e)。我希望它看起来像第二线(佩德罗史密斯)而不是第一线(桑德拉史密斯)。顺便说一下,这是所有测试数据,所以没有隐私问题显示你,也没有关于他们的私人信息。

<bookingcontact_to_booking>
    <passenger_to_bookings> 
        <passenger_to_booking>
            <Prop pk_id="4147" entity_id="126" val="SMITH" type_id="20" prop_name="lastname" prop_id="10208"/>
            <Prop pk_id="4147" entity_id="126" val="PEDRO" type_id="20" prop_name="firstname" prop_id="10206"/>
            <passseg_to_passengers>
                <passseg_to_passenger>
                    <Prop pk_id="9432" entity_id="122" val="2013-08-27 17:45:00.000" type_id="30" prop_name="arrivaltime" prop_id="10216"/>
                    <Prop pk_id="9432" entity_id="122" val="188" type_id="20" prop_name="flightnumber" prop_id="10217"/>
                    <Prop pk_id="9432" entity_id="122" val="5" type_id="10" prop_name="checkedbagcount" prop_id="10220"/>
                    <Prop pk_id="9432" entity_id="122" val="1" type_id="10" prop_name="carryonbagcount" prop_id="10221"/>
                    <Prop pk_id="9432" entity_id="122" val="1" type_id="10" prop_name="journeynumber" prop_id="10222"/>
                    <Prop pk_id="9432" entity_id="122" val="0" type_id="10" prop_name="segmentnumber" prop_id="10223"/>
                    <Prop pk_id="9432" entity_id="122" val="2013-08-27 08:12:00.000" type_id="30" prop_name="departuretime" prop_id="10296"/>
                    <Prop pk_id="9432" entity_id="122" val="Las Vegas, NV" type_id="20" prop_name="departureairport" prop_id="10297"/>
                    <Prop pk_id="9432" entity_id="122" val="New York, NY - LaGuardia " type_id="20" prop_name="arrivalairport" prop_id="10298"/>
                    <Prop pk_id="9432" entity_id="122" val="10B,20B" type_id="20" prop_name="seatassignment" prop_id="10299"/>
                </passseg_to_passenger>
                <passseg_to_passenger>
                    <Prop pk_id="9433" entity_id="122" val="10B,20B" type_id="20" prop_name="seatassignment" prop_id="10299"/>
                    <Prop pk_id="9433" entity_id="122" val="Fort Lauderdale, FL" type_id="20" prop_name="arrivalairport" prop_id="10298"/>
                    <Prop pk_id="9433" entity_id="122" val="New York, NY - LaGuardia " type_id="20" prop_name="departureairport" prop_id="10297"/>
                    <Prop pk_id="9433" entity_id="122" val="2013-08-27 19:45:00.000" type_id="30" prop_name="departuretime" prop_id="10296"/>
                    <Prop pk_id="9433" entity_id="122" val="1" type_id="10" prop_name="segmentnumber" prop_id="10223"/>
                    <Prop pk_id="9433" entity_id="122" val="1" type_id="10" prop_name="journeynumber" prop_id="10222"/>
                    <Prop pk_id="9433" entity_id="122" val="1" type_id="10" prop_name="carryonbagcount" prop_id="10221"/>
                    <Prop pk_id="9433" entity_id="122" val="5" type_id="10" prop_name="checkedbagcount" prop_id="10220"/>
                    <Prop pk_id="9433" entity_id="122" val="779" type_id="20" prop_name="flightnumber" prop_id="10217"/>
                    <Prop pk_id="9433" entity_id="122" val="2013-08-27 22:45:00.000" type_id="30" prop_name="arrivaltime" prop_id="10216"/>
                </passseg_to_passenger>
            </passseg_to_passengers>
        </passenger_to_booking>
    </passenger_to_bookings>
</bookingcontact_to_booking>

我想每次只显示一次CarryOnBagCount和CheckedBagCount。我尝试了几种不同的方法,但我认为我从解决方案中得到了进一步的发展。目前,无论旅程和航段如何,输出都是行李数量。 XSLT在下面。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />

    <xsl:key name="journey" match="passengersegment" use="Prop[@prop_name = 'journeynumber']/@val"/>

    <xsl:template match="/">
        <xsl:for-each select="/Msg/Props/bookingcontact_to_booking/passenger_to_bookings/passenger_to_booking">
            <tr>
                <td colspan="3">
                    <table style="text-align: left; line-height: 18px; font-family: Arial, Helvetica, sans-serif; font-size: 12px; color:#333333;"
                    border="0" cellspacing="0" cellpadding="0" width="542" align="left">
                        <tbody>
                            <tr>
                                <td height="22" width="200">
                                    <xsl:value-of select="Prop[@prop_name = 'firstname']/@val" /><xsl:text> </xsl:text><xsl:value-of select="Prop[@prop_name = 'lastname']/@val" />
                                </td>
                                <xsl:apply-templates select="passengersegment[generate-id() = generate-id(key('journey', journeynumber)[1])]"/>
                            </tr>
                        </tbody>
                    </table>
                </td>
            </tr>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="passengersegment">
        <td style="text-align: left;" width="100">
            <table style="text-align: left; line-height: 18px; font-family: Arial, Helvetica, sans-serif; font-size: 12px; color:#333333;" width="100">
                <tr>
                    <xsl:for-each select="passseg_to_passengers/passseg_to_passenger">
                        <td width="50">
                            <xsl:value-of select="Prop[@prop_name = 'carryonbagcount']/@val" />
                        </td>
                    </xsl:for-each>
                </tr>
            </table>                            
        </td>
        <td style="text-align: left;" width="100">
            <table style="text-align: left; line-height: 18px; font-family: Arial, Helvetica, sans-serif; font-size: 12px; color:#333333;" width="100">
                <tr>
                    <xsl:for-each select="passseg_to_passengers/passseg_to_passenger">
                        <td width="50">
                            <xsl:value-of select="Prop[@prop_name = 'checkedbagcount']/@val" />
                        </td>
                    </xsl:for-each>
                </tr>
            </table>                            
        </td>
    </xsl:template>

</xsl:stylesheet>

2 个答案:

答案 0 :(得分:1)

在没有看到预期HTML的样本的情况下提供精确答案并且因为XSLT中的元素名称似乎与输入XML样本不匹配,这有点棘手。但是,您需要阅读和使用的技术是Muenchian Grouping。这是在XSLT 1.0中对元素进行分组的最有效方法。

在您的情况下,您希望获得乘客的独特旅程,然后获得每个旅程的第一段。您可以通过定义一个键来 journeynumber

来查找 passengersegment 元素。
<xsl:key name="journey" match="passengersegment" use="journeynumber"/>

然后,要获得不同的旅程编号,您需要查看所有 passengersegment ,但只选择键中首先出现的 journeynumber 值。

<xsl:apply-templates 
     select="passengersegment
             [generate-id() = generate-id(key('journey', journeynumber)[1])]"/>

在匹配 passengersegment 的模板中,您可以输出该细分受众群的第一个 carryonbagcount checkednbagcount (旅程中的第一个)。

尝试使用此XSLT作为开头,并在此基础上构建:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:key name="journey" match="passengersegment" use="journeynumber"/>

  <xsl:template match="/passenger">
    <table border="1">
      <tr>
        <th>Journey</th>
        <th>Carry on</th>
        <th>Checked</th>
      </tr>
      <xsl:apply-templates select="passengersegment[generate-id() = generate-id(key('journey', journeynumber)[1])]"/>
    </table>
  </xsl:template>

  <xsl:template match="passengersegment">
    <tr>
      <td>
        <xsl:value-of select="journeynumber"/>
      </td>
      <td>
        <xsl:value-of select="carryonbagcount"/>
      </td>
      <td>
        <xsl:value-of select="checkedbagcount"/>
      </td>
    </tr>
  </xsl:template>
</xsl:stylesheet>

请注意,如果想要获得旅程中所有细分的总 carryonbagcount ,那么在 passengersegment 中您可以执行以下操作:

<xsl:value-of select="sum(key('journey', journeynumber)/carryonbagcount)" />

答案 1 :(得分:1)

假设输出的carryonbagcount应该是每条腿的最大值,这里只是对Tim回答的一个小调整。

此输入文档......

<passenger>
  <passengersegment>
      <journeynumber>0</journeynumber>
      <segmentnumber>0</segmentnumber>
      <carryonbagcount>1</carryonbagcount>
      <checkedbagcount>1</checkedbagcount>
  </passengersegment>
  <passengersegment>
       <journeynumber>0</journeynumber>
       <segmentnumber>1</segmentnumber>
       <carryonbagcount>1</carryonbagcount>
       <checkedbagcount>1</checkedbagcount>
   </passengersegment>
   <passengersegment>
       <journeynumber>1</journeynumber>
       <segmentnumber>0</segmentnumber>
       <carryonbagcount>1</carryonbagcount>
       <checkedbagcount>1</checkedbagcount>
   </passengersegment>
   <passengersegment>
       <journeynumber>1</journeynumber>
       <segmentnumber>1</segmentnumber>
       <carryonbagcount>1</carryonbagcount>
       <checkedbagcount>1</checkedbagcount>
   </passengersegment>

...当这个XSLT 1.0样式表应用于它时......

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />

<xsl:key name="kJourney" match="passengersegment" use="journeynumber" />  

<xsl:template match="/*">
<table>
 <thead>
  <tr>
   <th><strong>Journey</strong></th> <th><strong>CARRY-ON</strong></th> <th><strong>CHECKED</strong></th>
  </tr>
 </thead>
 <tbody>
    <xsl:apply-templates select="passengersegment[generate-id() =
                                                  generate-id(key('kJourney',journeynumber)[1])]"
                         mode="group" /> 
 </tbody>
</table>
</xsl:template>

<xsl:template match="passengersegment" mode="group">
  <tr>
    <td><xsl:value-of select="journeynumber" /></td>

    <xsl:apply-templates select="." mode="max"> 
      <xsl:with-param name="col-name" select="'carryonbagcount'" />
    </xsl:apply-templates>

    <xsl:apply-templates select="." mode="max"> 
      <xsl:with-param name="col-name" select="'checkedbagcount'" />
    </xsl:apply-templates>
  </tr>  
</xsl:template>

<xsl:template match="passengersegment" mode="max"> 
  <xsl:param name="col-name" /> 
  <xsl:for-each select="key('kJourney',journeynumber)/*[name()=$col-name]">
    <xsl:sort select="." data-type="number" order="descending" />
    <xsl:if test="position()=1">
      <td><xsl:value-of select="." /></td>
    </xsl:if>
  </xsl:for-each>  
</xsl:template>  

</xsl:stylesheet>

...产生此HTML输出......

<!DOCTYPE html SYSTEM "about:legacy-compat">
<table>
  <thead>
    <tr>
      <th><strong>Journey</strong></th>
      <th><strong>CARRY-ON</strong></th>
      <th><strong>CHECKED</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>1</td>
      <td>1</td>
    </tr>
    <tr>
      <td>1</td>
      <td>1</td>
      <td>1</td>
    </tr>
  </tbody>
</table>

更新

到目前为止,OP已经改变了问题和样本数据,这确实是一个新问题。假设@entity_id唯一标识一名乘客。如果没有,OP应该正确解释输入数据结构和转换规则。所以这是新问题的解决方案..

此XSLT 1.0样式表...

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />

<xsl:key name="kJourney" match="passseg_to_passenger"
  use="concat( ../../Prop/@entity_id, '|', Prop[@prop_name='journeynumber']/@val)" /> 
  <!-- Assume that @entity_id is an identifier for the passenger. -->

<xsl:template match="bookingcontact_to_booking">
<table>
 <thead>
  <tr>
   <th><strong>PASSENGER</strong></th> <th><strong>CARRY-ON</strong></th> <th><strong>CHECKED</strong></th>
  </tr>
 </thead>
 <tbody>
   <xsl:apply-templates select="passenger_to_bookings/passenger_to_booking" /> 
 </tbody>
</table>
</xsl:template>

<xsl:template match="passenger_to_booking">
  <xsl:variable name="passenger-id" select="(Prop/@entity_id)[1]" />
  <xsl:variable name="passenger-name" select="
   concat( Prop[@prop_name='firstname']/@val, ' ', Prop[@prop_name='lastname']/@val)" />
  <tr>
   <xsl:apply-templates select="passseg_to_passengers/passseg_to_passenger
       [generate-id() = generate-id(key('kJourney',
            concat( $passenger-id, '|', Prop[@prop_name='journeynumber']/@val))[1])]"
     mode="group"> 
    <xsl:with-param name="passenger-id"   select="$passenger-id" />
    <xsl:with-param name="passenger-name" select="$passenger-name" />
  </xsl:apply-templates>   
  </tr>
</xsl:template>

<xsl:template match="passseg_to_passenger" mode="group">
  <xsl:param name="passenger-id" />
  <xsl:param name="passenger-name" />
  <td><xsl:value-of select="$passenger-name" /></td>

  <xsl:apply-templates select="." mode="max"> 
    <xsl:with-param name="passenger-id" select="$passenger-id" />
    <xsl:with-param name="col-name" select="'carryonbagcount'" />
  </xsl:apply-templates>

  <xsl:apply-templates select="." mode="max"> 
    <xsl:with-param name="passenger-id" select="$passenger-id" />
    <xsl:with-param name="col-name" select="'checkedbagcount'" />
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="passseg_to_passenger" mode="max"> 
  <xsl:param name="passenger-id" />
  <xsl:param name="col-name" /> 
  <xsl:for-each select="key('kJourney',
      concat( $passenger-id, '|', Prop[@prop_name='journeynumber']/@val)
  )/Prop[@prop_name=$col-name]/@val">
    <xsl:sort select="." data-type="number" order="descending" />
    <xsl:if test="position()=1">
      <td><xsl:value-of select="." /></td>
    </xsl:if>
  </xsl:for-each>  
</xsl:template>  

</xsl:stylesheet>

...应用于此输入文档时...

<bookingcontact_to_booking>
    <passenger_to_bookings> 
        <passenger_to_booking>
            <Prop pk_id="4147" entity_id="126" val="SMITH" type_id="20" prop_name="lastname" prop_id="10208"/>
            <Prop pk_id="4147" entity_id="126" val="PEDRO" type_id="20" prop_name="firstname" prop_id="10206"/>
            <passseg_to_passengers>
                <passseg_to_passenger>
                    <Prop pk_id="9432" entity_id="122" val="2013-08-27 17:45:00.000" type_id="30" prop_name="arrivaltime" prop_id="10216"/>
                    <Prop pk_id="9432" entity_id="122" val="188" type_id="20" prop_name="flightnumber" prop_id="10217"/>
                    <Prop pk_id="9432" entity_id="122" val="5" type_id="10" prop_name="checkedbagcount" prop_id="10220"/>
                    <Prop pk_id="9432" entity_id="122" val="1" type_id="10" prop_name="carryonbagcount" prop_id="10221"/>
                    <Prop pk_id="9432" entity_id="122" val="1" type_id="10" prop_name="journeynumber" prop_id="10222"/>
                    <Prop pk_id="9432" entity_id="122" val="0" type_id="10" prop_name="segmentnumber" prop_id="10223"/>
                    <Prop pk_id="9432" entity_id="122" val="2013-08-27 08:12:00.000" type_id="30" prop_name="departuretime" prop_id="10296"/>
                    <Prop pk_id="9432" entity_id="122" val="Las Vegas, NV" type_id="20" prop_name="departureairport" prop_id="10297"/>
                    <Prop pk_id="9432" entity_id="122" val="New York, NY - LaGuardia " type_id="20" prop_name="arrivalairport" prop_id="10298"/>
                    <Prop pk_id="9432" entity_id="122" val="10B,20B" type_id="20" prop_name="seatassignment" prop_id="10299"/>
                </passseg_to_passenger>
                <passseg_to_passenger>
                    <Prop pk_id="9433" entity_id="122" val="10B,20B" type_id="20" prop_name="seatassignment" prop_id="10299"/>
                    <Prop pk_id="9433" entity_id="122" val="Fort Lauderdale, FL" type_id="20" prop_name="arrivalairport" prop_id="10298"/>
                    <Prop pk_id="9433" entity_id="122" val="New York, NY - LaGuardia " type_id="20" prop_name="departureairport" prop_id="10297"/>
                    <Prop pk_id="9433" entity_id="122" val="2013-08-27 19:45:00.000" type_id="30" prop_name="departuretime" prop_id="10296"/>
                    <Prop pk_id="9433" entity_id="122" val="1" type_id="10" prop_name="segmentnumber" prop_id="10223"/>
                    <Prop pk_id="9433" entity_id="122" val="1" type_id="10" prop_name="journeynumber" prop_id="10222"/>
                    <Prop pk_id="9433" entity_id="122" val="1" type_id="10" prop_name="carryonbagcount" prop_id="10221"/>
                    <Prop pk_id="9433" entity_id="122" val="5" type_id="10" prop_name="checkedbagcount" prop_id="10220"/>
                    <Prop pk_id="9433" entity_id="122" val="779" type_id="20" prop_name="flightnumber" prop_id="10217"/>
                    <Prop pk_id="9433" entity_id="122" val="2013-08-27 22:45:00.000" type_id="30" prop_name="arrivaltime" prop_id="10216"/>
                </passseg_to_passenger>
            </passseg_to_passengers>
        </passenger_to_booking>
    </passenger_to_bookings>
</bookingcontact_to_booking>

...产生这个html输出文档......

<!DOCTYPE html SYSTEM "about:legacy-compat">
<table>
  <thead>
    <tr>
      <th><strong>PASSENGER</strong></th>
      <th><strong>CARRY-ON</strong></th>
      <th><strong>CHECKED</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>PEDRO SMITH</td>
      <td>1</td>
      <td>5</td>
    </tr>
  </tbody>
</table>