C# 在XSLT中组合相同的子元素

C# 在XSLT中组合相同的子元素,c#,asp.net,xslt,C#,Asp.net,Xslt,大家好,首先我正在学习复杂的XSLT迭代,现在我写了一个查询,在这个查询中,我在标记信息下有相同的信息,唯一不同的标记是BookingClassAvail,它具有不同的属性值,我想合并成一个,保持信息标记是分开的 XML: 2012-10-27 2012-11-05 希望输出如下所示: <Availability> <Success/> <Information xmlns="http://www.opentravel.org/O

大家好,首先我正在学习复杂的XSLT迭代,现在我写了一个查询,在这个查询中,我在标记信息下有相同的信息,唯一不同的标记是BookingClassAvail,它具有不同的属性值,我想合并成一个,保持信息标记是分开的

XML:


2012-10-27
2012-11-05
希望输出如下所示:

    <Availability>
      <Success/>
      <Information xmlns="http://www.opentravel.org/OTA/2003/05">
        <DepDateTime>2012-10-27</DepDateTime>
        <OrigLocation LocationCode="DEL" />
        <DestLocation LocationCode="BOM" />
        <OrigDestinationOptions>
          <OrigDestinationOption>
            <FlightSegment DepDateTime="2012-10-27A12:35:00" ArrDateTime="2012-10-27A14:05:00" StopQuantity="0" FlightNumber="152" JourneyDuration="90" Ticket="eTicket">
              <DepAirport LocationCode="DEL" Terminal="" />
              <ArrAirport LocationCode="BOM" Terminal="" />
              <OperatingAirline CompanyShortName="A1" />
              <Equipment AirEquipType="A320" />
              <MarketingAirline CompanyShortName="A1" />
              <BookingClassAvail ResBookDesigCode="T" ResBookDesigQuantity="180" />
              <BookingClassAvail ResBookDesigCode="B" ResBookDesigQuantity="80" />
            </FlightSegment>
          </OrigDestinationOption>

         <!-- since the DepDateTime has different date hence not combined in the above flightsegment -->

            <OrigDestinationOption>
              <FlightSegment DepDateTime="2012-10-28A10:35:00" ArrDateTime="2012-10-27A14:05:00" StopQuantity="0" FlightNumber="152" JourneyDuration="90" Ticket="eTicket">
                <DepAirport LocationCode="DEL" Terminal="" />
                <ArrAirport LocationCode="BOM" Terminal="" />
                <OperatingAirline CompanyShortName="A1" />
                <Equipment AirEquipType="A320" />
                <MarketingAirline CompanyShortName="A1" />
                <BookingClassAvail ResBookDesigCode="B" ResBookDesigQuantity="80" />
              </FlightSegment>
            </OrigDestinationOption>
        </OrigDestinationOptions>
      </Information>
      <Information xmlns="http://www.opentravel.org/OTA/2003/05">
        <DepDateTime>2012-11-05</DepDateTime>
        <OrigLocation LocationCode="BOM" />
        <DestinationLocation LocationCode="DEL" />
        <OrigDestinationOptions>
          <OrigDestinationOption>
            <FlightSegment DepDateTime="2012-11-05T08:35:00" ArrDateTime="2012-11-05T09:40:00" StopQuantity="0" FlightNumber="993" JourneyDuration="65" Ticket="eTicket">
              <DepAirport LocationCode="BOM" Terminal="" />
              <ArrAirport LocationCode="DEL" Terminal="" />
              <OperatingAirline CompanyShortName="GR" />
              <Equipment AirEquipType="A320" />
              <MarketingAirline CompanyShortName="GR" />
              <BookingClassAvail ResBookDesigCode="T" ResBookDesigQuantity="180" />
              <BookingClassAvail ResBookDesigCode="Y" ResBookDesigQuantity="180" />
            </FlightSegment>
          </OrigDestinationOption>
        </OrigDestinationOptions>
      </Information>
    </Availability>

2012-10-27
2012-11-05
如果您看到上面的标签BookingClassAvail具有不同的ResBookDesigCode和ResBookDesigQuantity信息,因此需要按行堆叠

<BookingClassAvail ResBookDesigCode="T" ResBookDesigQuantity="180" />
<BookingClassAvail ResBookDesigCode="B" ResBookDesigQuantity="80" />

此外,如果任何信息以不同于单独航班段的形式提供

另外请注意,上述一个标签用于出境航班,其他信息用于入境航班,需要分开保存,只需要合并

万分感谢


Sean我使用了您建议的解决方案,但我遇到了一个错误,即“无法从已加载的输入文档中删除空白。请改为将输入文档作为XmlReader提供。”

XML:


2012-10-27
2012-11-05
使用的XSLT:

     <xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:ot="http://www.opentravel.org/OTA/2003/05"
  exclude-result-prefixes="xsl ot">
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*" />

  <xsl:key name="kSegment" match="ot:OrigDestinationOption"
                           use="concat( ot:FlightSegment[1]/@DepDateTime,
                                          '|', generate-id(..))" />

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="ot:OrigDestinationOptions">
    <xsl:variable name="options" select="generate-id()" />
    <xsl:copy>
      <xsl:apply-templates select="
     ot:OrigDestinationOption[
       generate-id()=generate-id(key('kSegment',
        concat( ot:FlightSegment[1]/@DepDateTime,
                '|', $options))[1])]" mode="group" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="ot:OrigDestinationOption" mode="group">
    <xsl:variable name="group" select="key('kSegment',
        concat( ot:FlightSegment[1]/@DepDateTime,'|', generate-id(..)))" />
    <xsl:copy>
      <xsl:apply-templates select="*[not(self::ot:FlightSegment)]"/>
      <FlightSegment xmlns="http://www.opentravel.org/OTA/2003/05">
        <xsl:apply-templates
          select="ot:FlightSegment[1]/@*  |
               ot:FlightSegment[1]/*[not(self::ot:BookingClassAvail)] |
               $group/ot:FlightSegment/ot:BookingClassAvail" />
      </FlightSegment>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

面临的错误:


“无法从已加载的输入文档中删除空白。请改为将输入文档作为XmlReader提供。”

此XSLT 1.0样式表…

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:ot="http://www.opentravel.org/OTA/2003/05"
  exclude-result-prefixes="xsl ot">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />

    <xsl:key name="kSegment" match="ot:OrigDestinationOption"
                             use="concat( ot:FlightSegment[1]/@DepDateTime,
                                          '|', generate-id(..))" />

<xsl:template match="@*|node()">
 <xsl:copy>
   <xsl:apply-templates select="@*|node()"/>
 </xsl:copy>
</xsl:template>

<xsl:template match="ot:OrigDestinationOptions">
 <xsl:variable name="options" select="generate-id()" />
 <xsl:copy>
   <xsl:apply-templates select="
     ot:OrigDestinationOption[
       generate-id()=generate-id(key('kSegment',
        concat( ot:FlightSegment[1]/@DepDateTime,
                '|', $options))[1])]" mode="group" />
 </xsl:copy>
</xsl:template>

<xsl:template match="ot:OrigDestinationOption" mode="group">
  <xsl:variable name="group" select="key('kSegment',
        concat( ot:FlightSegment[1]/@DepDateTime,'|', generate-id(..)))" /> 
 <xsl:copy>
   <xsl:apply-templates select="*[not(self::ot:FlightSegment)]"/>
   <FlightSegment xmlns="http://www.opentravel.org/OTA/2003/05">
     <xsl:apply-templates
       select="ot:FlightSegment[1]/@*  |
               ot:FlightSegment[1]/*[not(self::ot:BookingClassAvail)] |
               $group/ot:FlightSegment/ot:BookingClassAvail" />
   </FlightSegment>  
 </xsl:copy>
</xsl:template>

</xsl:stylesheet>
<Availability>
  <Information xmlns="http://www.opentravel.org/OTA/2003/05">
    <OrigDestinationOptions>
      <OrigDestinationOption>
        <FlightSegment DepDateTime="2012-10-27A12:35:00" Ticket="eTicket">
          <DepAirport LocationCode="DEL" Terminal="" />
          <BookingClassAvail ResBookDesigCode="T" ResBookDesigQuantity="180" />
          <BookingClassAvail ResBookDesigCode="B" ResBookDesigQuantity="80" />
        </FlightSegment>
      </OrigDestinationOption>
    </OrigDestinationOptions>
  </Information>
  <Information xmlns="http://www.opentravel.org/OTA/2003/05">
    <OrigDestinationOptions>
      <OrigDestinationOption>
        <FlightSegment DepDateTime="2012-10-28A10:35:00" Ticket="eTicket">
          <DepAirport LocationCode="DEL" Terminal="" />
          <BookingClassAvail ResBookDesigCode="B" ResBookDesigQuantity="80" />
        </FlightSegment>
      </OrigDestinationOption>
    </OrigDestinationOptions>
  </Information>
</Availability>

…应用于此输入时(OP提供文档的精简版本)


…产生…

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:ot="http://www.opentravel.org/OTA/2003/05"
  exclude-result-prefixes="xsl ot">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />

    <xsl:key name="kSegment" match="ot:OrigDestinationOption"
                             use="concat( ot:FlightSegment[1]/@DepDateTime,
                                          '|', generate-id(..))" />

<xsl:template match="@*|node()">
 <xsl:copy>
   <xsl:apply-templates select="@*|node()"/>
 </xsl:copy>
</xsl:template>

<xsl:template match="ot:OrigDestinationOptions">
 <xsl:variable name="options" select="generate-id()" />
 <xsl:copy>
   <xsl:apply-templates select="
     ot:OrigDestinationOption[
       generate-id()=generate-id(key('kSegment',
        concat( ot:FlightSegment[1]/@DepDateTime,
                '|', $options))[1])]" mode="group" />
 </xsl:copy>
</xsl:template>

<xsl:template match="ot:OrigDestinationOption" mode="group">
  <xsl:variable name="group" select="key('kSegment',
        concat( ot:FlightSegment[1]/@DepDateTime,'|', generate-id(..)))" /> 
 <xsl:copy>
   <xsl:apply-templates select="*[not(self::ot:FlightSegment)]"/>
   <FlightSegment xmlns="http://www.opentravel.org/OTA/2003/05">
     <xsl:apply-templates
       select="ot:FlightSegment[1]/@*  |
               ot:FlightSegment[1]/*[not(self::ot:BookingClassAvail)] |
               $group/ot:FlightSegment/ot:BookingClassAvail" />
   </FlightSegment>  
 </xsl:copy>
</xsl:template>

</xsl:stylesheet>
<Availability>
  <Information xmlns="http://www.opentravel.org/OTA/2003/05">
    <OrigDestinationOptions>
      <OrigDestinationOption>
        <FlightSegment DepDateTime="2012-10-27A12:35:00" Ticket="eTicket">
          <DepAirport LocationCode="DEL" Terminal="" />
          <BookingClassAvail ResBookDesigCode="T" ResBookDesigQuantity="180" />
          <BookingClassAvail ResBookDesigCode="B" ResBookDesigQuantity="80" />
        </FlightSegment>
      </OrigDestinationOption>
    </OrigDestinationOptions>
  </Information>
  <Information xmlns="http://www.opentravel.org/OTA/2003/05">
    <OrigDestinationOptions>
      <OrigDestinationOption>
        <FlightSegment DepDateTime="2012-10-28A10:35:00" Ticket="eTicket">
          <DepAirport LocationCode="DEL" Terminal="" />
          <BookingClassAvail ResBookDesigCode="B" ResBookDesigQuantity="80" />
        </FlightSegment>
      </OrigDestinationOption>
    </OrigDestinationOptions>
  </Information>
</Availability>

笔记
  • 分组键是父OrigDestinationOptions节点和航班起飞时间的乘积
  • 假设每个OrigDestinationOption恰好包含一个FlightSegment
  • 假设合并同一组中的FlightSegments时,需要保留的组中所有成员的唯一不同信息是BookingClassAvail元素
  • 这不是一个超级通用的解决方案,但考虑到问题表达中缺乏定义,这是合理的。如果需要更一般的解决方案,则需要更精确地了解输入结构和转换规则

  • 此XSLT 1.0样式表…

    <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:ot="http://www.opentravel.org/OTA/2003/05"
      exclude-result-prefixes="xsl ot">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*" />
    
        <xsl:key name="kSegment" match="ot:OrigDestinationOption"
                                 use="concat( ot:FlightSegment[1]/@DepDateTime,
                                              '|', generate-id(..))" />
    
    <xsl:template match="@*|node()">
     <xsl:copy>
       <xsl:apply-templates select="@*|node()"/>
     </xsl:copy>
    </xsl:template>
    
    <xsl:template match="ot:OrigDestinationOptions">
     <xsl:variable name="options" select="generate-id()" />
     <xsl:copy>
       <xsl:apply-templates select="
         ot:OrigDestinationOption[
           generate-id()=generate-id(key('kSegment',
            concat( ot:FlightSegment[1]/@DepDateTime,
                    '|', $options))[1])]" mode="group" />
     </xsl:copy>
    </xsl:template>
    
    <xsl:template match="ot:OrigDestinationOption" mode="group">
      <xsl:variable name="group" select="key('kSegment',
            concat( ot:FlightSegment[1]/@DepDateTime,'|', generate-id(..)))" /> 
     <xsl:copy>
       <xsl:apply-templates select="*[not(self::ot:FlightSegment)]"/>
       <FlightSegment xmlns="http://www.opentravel.org/OTA/2003/05">
         <xsl:apply-templates
           select="ot:FlightSegment[1]/@*  |
                   ot:FlightSegment[1]/*[not(self::ot:BookingClassAvail)] |
                   $group/ot:FlightSegment/ot:BookingClassAvail" />
       </FlightSegment>  
     </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    
    <Availability>
      <Information xmlns="http://www.opentravel.org/OTA/2003/05">
        <OrigDestinationOptions>
          <OrigDestinationOption>
            <FlightSegment DepDateTime="2012-10-27A12:35:00" Ticket="eTicket">
              <DepAirport LocationCode="DEL" Terminal="" />
              <BookingClassAvail ResBookDesigCode="T" ResBookDesigQuantity="180" />
              <BookingClassAvail ResBookDesigCode="B" ResBookDesigQuantity="80" />
            </FlightSegment>
          </OrigDestinationOption>
        </OrigDestinationOptions>
      </Information>
      <Information xmlns="http://www.opentravel.org/OTA/2003/05">
        <OrigDestinationOptions>
          <OrigDestinationOption>
            <FlightSegment DepDateTime="2012-10-28A10:35:00" Ticket="eTicket">
              <DepAirport LocationCode="DEL" Terminal="" />
              <BookingClassAvail ResBookDesigCode="B" ResBookDesigQuantity="80" />
            </FlightSegment>
          </OrigDestinationOption>
        </OrigDestinationOptions>
      </Information>
    </Availability>
    
    
    
    …应用于此输入时(OP提供文档的精简版本)

    
    
    …产生…

    <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:ot="http://www.opentravel.org/OTA/2003/05"
      exclude-result-prefixes="xsl ot">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*" />
    
        <xsl:key name="kSegment" match="ot:OrigDestinationOption"
                                 use="concat( ot:FlightSegment[1]/@DepDateTime,
                                              '|', generate-id(..))" />
    
    <xsl:template match="@*|node()">
     <xsl:copy>
       <xsl:apply-templates select="@*|node()"/>
     </xsl:copy>
    </xsl:template>
    
    <xsl:template match="ot:OrigDestinationOptions">
     <xsl:variable name="options" select="generate-id()" />
     <xsl:copy>
       <xsl:apply-templates select="
         ot:OrigDestinationOption[
           generate-id()=generate-id(key('kSegment',
            concat( ot:FlightSegment[1]/@DepDateTime,
                    '|', $options))[1])]" mode="group" />
     </xsl:copy>
    </xsl:template>
    
    <xsl:template match="ot:OrigDestinationOption" mode="group">
      <xsl:variable name="group" select="key('kSegment',
            concat( ot:FlightSegment[1]/@DepDateTime,'|', generate-id(..)))" /> 
     <xsl:copy>
       <xsl:apply-templates select="*[not(self::ot:FlightSegment)]"/>
       <FlightSegment xmlns="http://www.opentravel.org/OTA/2003/05">
         <xsl:apply-templates
           select="ot:FlightSegment[1]/@*  |
                   ot:FlightSegment[1]/*[not(self::ot:BookingClassAvail)] |
                   $group/ot:FlightSegment/ot:BookingClassAvail" />
       </FlightSegment>  
     </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    
    <Availability>
      <Information xmlns="http://www.opentravel.org/OTA/2003/05">
        <OrigDestinationOptions>
          <OrigDestinationOption>
            <FlightSegment DepDateTime="2012-10-27A12:35:00" Ticket="eTicket">
              <DepAirport LocationCode="DEL" Terminal="" />
              <BookingClassAvail ResBookDesigCode="T" ResBookDesigQuantity="180" />
              <BookingClassAvail ResBookDesigCode="B" ResBookDesigQuantity="80" />
            </FlightSegment>
          </OrigDestinationOption>
        </OrigDestinationOptions>
      </Information>
      <Information xmlns="http://www.opentravel.org/OTA/2003/05">
        <OrigDestinationOptions>
          <OrigDestinationOption>
            <FlightSegment DepDateTime="2012-10-28A10:35:00" Ticket="eTicket">
              <DepAirport LocationCode="DEL" Terminal="" />
              <BookingClassAvail ResBookDesigCode="B" ResBookDesigQuantity="80" />
            </FlightSegment>
          </OrigDestinationOption>
        </OrigDestinationOptions>
      </Information>
    </Availability>
    
    
    
    笔记
  • 分组键是父OrigDestinationOptions节点和航班起飞时间的乘积
  • 假设每个OrigDestinationOption恰好包含一个FlightSegment
  • 假设在合并同一组中的FlightSegments时,只有不同的信息