4

I am a beginner in XSLT.

Below is source XML which i receive. Request tag constains the FlightId which is being used to filter the Result tag.

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

I received below output using above XSLT.

Output:

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

I would like to receive below output.

Expected Output:

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

Please help me. How should i use the array to filter the response and get expected output. Thanks.

12
  • Nicely constructed question. +1. Commented Nov 21, 2012 at 11:00
  • Why is ResultCount 1 when there are two FlightNumbers? Commented Nov 21, 2012 at 11:44
  • @SeanB.Durkin ResultCount 1 because the "FilterFlights" variable should have only one Flight node. Commented Nov 21, 2012 at 11:50
  • So what is the rule here? Does a Flight have to contain all the FlightId's in order for it to be output? Commented Nov 21, 2012 at 11:50
  • What is the minimum and maximum number of FlightId s? Is it unbounded? Commented Nov 21, 2012 at 11:52

2 Answers 2

2

Use:

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

Here is the complete transformation:

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

When this transformation is applied on the provided XML document:

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

the wanted, correct result is produced:

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

Explanation:

Proper use of the double negation law.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. For the given source XML your solution works. But when i need to apply same law for different structured XML. Should i create new Question or edit this?
@AnkurRaiyani, It is better for everybody if you create a new question -- otherwise you'll destroy the first question, or make it less readable.
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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.