使用XSLT数组过滤XSLT结果

4

我是XSLT的初学者。

以下是我收到的源XML。 Request 标签包含用于过滤 Result 标签的 FlightId

源XML:

<Response>
    <Request>
        <RequestedFlights>
            <FlightId>2121</FlightId>
            <FlightId>2584</FlightId>
        </RequestedFlights>
    </Request>
    <Result>
        <Flights>
            <Flight>
                <Segments>
                    <Segment>
                        <Id>1</Id>
                        <FlightNumber>2121</FlightNumber>
                    </Segment>
                    <Segment>
                        <Id>2</Id>
                        <FlightNumber>1121</FlightNumber>
                    </Segment>
                </Segments>
            </Flight>
            <Flight>
                <Segments>
                    <Segment>
                        <Id>3</Id>
                        <FlightNumber>2121</FlightNumber>
                    </Segment>
                    <Segment>
                        <Id>4</Id>
                        <FlightNumber>2584</FlightNumber>
                    </Segment>
                </Segments>
            </Flight>
            <Flight>
                <Segments>
                    <Segment>
                        <Id>5</Id>
                        <FlightNumber>2121</FlightNumber>
                    </Segment>
                    <Segment>
                        <Id>6</Id>
                        <FlightNumber>2584</FlightNumber>
                    </Segment>
                    <Segment>
                        <Id>7</Id>
                        <FlightNumber>2023</FlightNumber>
                    </Segment>
                </Segments>
            </Flight>
        </Flights>
    </Result>
</Response>

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

    <xsl:output method="xml" indent="yes" />
    <xsl:variable name="ReqFlights" select="//Request/RequestedFlights/FlightId" />
    <xsl:variable name="FilterFlights" select="//Result/Flights/Flight[Segments/Segment/FlightNumber=$ReqFlights]"/>

    <xsl:template match="Response">
        <FilterResult>
            <ResultCount>
                <xsl:value-of select="count($FilterFlights)"/>
            </ResultCount>
            <xsl:copy>
                <xsl:copy-of select="$FilterFlights"/>
            </xsl:copy>
        </FilterResult>
    </xsl:template>
</xsl:stylesheet>

我使用上述XSLT收到以下输出。

输出:

<FilterResult>
    <ResultCount>3</ResultCount>
    <Response>
        <Flight>
            <Segments>
                <Segment>
                    <Id>1</Id>
                    <FlightNumber>2121</FlightNumber>
                </Segment>
                <Segment>
                    <Id>2</Id>
                    <FlightNumber>1121</FlightNumber>
                </Segment>
            </Segments>
        </Flight>
            <Flight>
            <Segments>
                <Segment>
                    <Id>3</Id>
                    <FlightNumber>2121</FlightNumber>
                </Segment>
                <Segment>
                    <Id>4</Id>
                    <FlightNumber>2584</FlightNumber>
                </Segment>
            </Segments>
        </Flight>
            <Flight>
            <Segments>
                <Segment>
                    <Id>5</Id>
                    <FlightNumber>2121</FlightNumber>
                </Segment>
                <Segment>
                    <Id>6</Id>
                    <FlightNumber>2584</FlightNumber>
                </Segment>
                <Segment>
                    <Id>7</Id>
                    <FlightNumber>2023</FlightNumber>
                </Segment>
            </Segments>
        </Flight>
    </Response>
</FilterResult>

我希望得到以下输出。
预期输出:
<FilterResult>
    <ResultCount>1</ResultCount>
    <Response>
        <Flight>
            <Segments>
                <Segment>
                    <Id>3</Id>
                    <FlightNumber>2121</FlightNumber>
                </Segment>
                <Segment>
                    <Id>4</Id>
                    <FlightNumber>2584</FlightNumber>
                </Segment>
            </Segments>
        </Flight>
    </Response>
</FilterResult>

请帮助我。我应该如何使用数组来过滤响应并获得期望的输出。 谢谢。

精心构建的问题。+1。 - Sean B. Durkin
为什么有两个航班号,但ResultCount却是1? - Sean B. Durkin
@SeanB.Durkin的ResultCount为1,因为"FilterFlights"变量应该只有一个Flight节点。 - Ankur Raiyani
不,它应该将那些 FlightId 作为 FlightNumber - Ankur Raiyani
如果一个航班的航班号与请求的航班ID完全相同,它们是否保证按照相同的顺序排列?(将航班与请求的航班进行比较)还是说它们之间没有任何排序关系? - Sean B. Durkin
显示剩余7条评论
2个回答

2

用途:

/*/Result/*/Flight
            [count(*/*)=count(/*/Request/*/FlightId)
           and
             not(*/*/FlightNumber[not(. = /*/Request/*/FlightId)])
            ]

以下是完整的转换过程:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
     <xsl:variable name="vHits" select=
     "/*/Result/*/Flight
                  [count(*/*)=count(/*/Request/*/FlightId)
                 and
                   not(*/*/FlightNumber[not(. = /*/Request/*/FlightId)])
                   ]"/>
    <FilterResult>
    <ResultCount><xsl:value-of select="count($vHits)"/></ResultCount>
    <Response>
     <xsl:copy-of select="$vHits"/>
    </Response>
  </FilterResult>
 </xsl:template>
</xsl:stylesheet>

当将此转换应用于提供的XML文档时:
<Response>
    <Request>
        <RequestedFlights>
            <FlightId>2121</FlightId>
            <FlightId>2584</FlightId>
        </RequestedFlights>
    </Request>
    <Result>
        <Flights>
            <Flight>
                <Segments>
                    <Segment>
                        <Id>1</Id>
                        <FlightNumber>2121</FlightNumber>
                    </Segment>
                    <Segment>
                        <Id>2</Id>
                        <FlightNumber>1121</FlightNumber>
                    </Segment>
                </Segments>
            </Flight>
            <Flight>
                <Segments>
                    <Segment>
                        <Id>3</Id>
                        <FlightNumber>2121</FlightNumber>
                    </Segment>
                    <Segment>
                        <Id>4</Id>
                        <FlightNumber>2584</FlightNumber>
                    </Segment>
                </Segments>
            </Flight>
            <Flight>
                <Segments>
                    <Segment>
                        <Id>5</Id>
                        <FlightNumber>2121</FlightNumber>
                    </Segment>
                    <Segment>
                        <Id>6</Id>
                        <FlightNumber>2584</FlightNumber>
                    </Segment>
                    <Segment>
                        <Id>7</Id>
                        <FlightNumber>2023</FlightNumber>
                    </Segment>
                </Segments>
            </Flight>
        </Flights>
    </Result>
</Response>

期望的、正确的结果已经生成:
<FilterResult>
   <ResultCount>1</ResultCount>
   <Response>
      <Flight>
         <Segments>
            <Segment>
               <Id>3</Id>
               <FlightNumber>2121</FlightNumber>
            </Segment>
            <Segment>
               <Id>4</Id>
               <FlightNumber>2584</FlightNumber>
            </Segment>
         </Segments>
      </Flight>
   </Response>
</FilterResult>

解释:

正确使用双重否定律


谢谢。对于给定的源XML,您的解决方案有效。但是当我需要将同样的规则应用于不同结构的XML时,我应该创建新问题还是编辑此问题? - Ankur Raiyani
@AnkurRaiyani,如果您创建一个新问题,对于每个人来说都会更好--否则您将破坏第一个问题或使其不易阅读。 - Dimitre Novatchev

1
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common"
  extension-element-prefixes="exsl">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*" />  

<xsl:variable name="requested"
  select="/Response/Request/RequestedFlights/FlightId/text()" />

<xsl:template name="flights-as-string">
  <xsl:param name="Id" />
  <xsl:for-each select="$Id">
    <xsl:sort select="." />
    <xsl:value-of select="concat('[',.,']')" />
  </xsl:for-each>  
</xsl:template>

<xsl:variable name="requested-str-nodeset">
  <xsl:call-template name="flights-as-string">
    <xsl:with-param name="Id" select="$requested" />
  </xsl:call-template>
</xsl:variable>  
<xsl:variable name="requested-str" select="exsl:node-set($requested-str-nodeset)/text()" />

<xsl:template match="/*">
  <xsl:variable name="flight-output">
    <xsl:apply-templates select="Result/Flights/Flight" />
  </xsl:variable>
  <FilterResult>
    <ResultCount><xsl:value-of select="
      count( exsl:node-set($flight-output)/Flight)" /></ResultCount>
    <Response>
      <xsl:copy-of select="$flight-output" />
    </Response>
  </FilterResult>
</xsl:template>

<xsl:template match="Flight">
  <xsl:variable name="actual-str">
    <xsl:call-template name="flights-as-string">
      <xsl:with-param name="Id" select="Segments/Segment/FlightNumber/text()" />
    </xsl:call-template>
  </xsl:variable>  
  <xsl:if test="$requested-str = exsl:node-set($actual-str)/text()">
      <xsl:copy-of select="." />
  </xsl:if>
</xsl:template>

</xsl:stylesheet>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接