Re: [xsl] An XPath expression that avoids writing special casecode?

Subject: Re: [xsl] An XPath expression that avoids writing special casecode?
From: "Wendell Piez wapiez@xxxxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 18 Jun 2021 16:02:12 -0000
Roger,

You ask

> Question: Below are two XPath expressions. The first is the one that
Mukul recommended and it returns the desired row. The second is the one
that I created and it fails. The only difference between the two XPath
expressions is string(Data) versus Data. Why does the former work whereas
the later fails?

> /Document/Row[Cell[1]/Data eq 'aviation'][Cell[2]/string(Data) eq '']
> /Document/Row[Cell[1]/Data eq 'aviation'][Cell[2]/Data eq '']

In the first case, the step 'string(Data)', in the absence of a Data node,
will return '', since string(()) (a string value of nothing) is an
empty string, i.e. a sequence of one member, ('').

In the second case, the failure of the path to reach any node at Data
results in the comparison () eq '' which should produce a runtime error,
since 'eq' requires two singleton operands.

It is useful to keep in mind the distinction between a test for the
existence of a node, and a test for a node's value. The operators such as
'=' have the nice feature of letting us collapse these things since
it permits many-to-many or many-to-none comparisons. The 'eq' operator has
the nice feature of not letting us collapse these things.

Cheers,
Wendell





On Fri, Jun 18, 2021 at 9:31 AM Roger L Costello costello@xxxxxxxxx <
xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:

> Hi Mukul,
>
> I tried your suggestion. For this XML document:
>
> <Document>
>     <Row>
>         <Cell>
>             <Data>aviation</Data>
>         </Cell>
>         <Cell/>
>     </Row>
> </Document>
>
> I evaluated the following XPath expression in Oxygen XML:
>
> /Document/Row[Cell[1]/Data eq 'aviation'][Cell[2]/string(Data) eq '']
>
> Oxygen XML returned the desired row:
>
>     <Row>
>         <Cell>
>             <Data>aviation</Data>
>         </Cell>
>         <Cell/>
>     </Row>
>
> Fantastic!
>
> Question: Below are two XPath expressions. The first is the one that Mukul
> recommended and it returns the desired row. The second is the one that I
> created and it fails. The only difference between the two XPath expressions
> is string(Data) versus Data. Why does the former work whereas the later
> fails?
>
> /Document/Row[Cell[1]/Data eq 'aviation'][Cell[2]/string(Data) eq '']
> /Document/Row[Cell[1]/Data eq 'aviation'][Cell[2]/Data eq '']
>
> /Roger
>
>
> From: Mukul Gandhi mukulg@xxxxxxxxxxxxxxxxx <
> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
> Sent: Friday, June 18, 2021 3:28 AM
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [EXT] Re: [xsl] An XPath expression that avoids writing special
> casecode?
>
> On Thu, Jun 17, 2021 at 7:36 PM Roger L Costello mailto:costello@xxxxxxxxx
> <mailto:xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>
> My XML document contains a bunch of <Row> elements, like so:
>
> <Document>
>     ...
>     <Row>
>         <Cell>
>             <Data>airport</Data>
>         </Cell>
>         <Cell>
>             <Data>airports</Data>
>         </Cell>
>     </Row>
>     ...
> </Document>
>
> I want to fetch the Row whose Cell[1]/Data is 'airport' and whose
> Cell[2]/Data is 'airports'. So I created this XPath expression:
>
> /Document/Row[Cell[1]/Data eq 'airport'][Cell[2]/Data eq 'airports']
>
> I do this kind of fetching operation often, so I created a function to
> fetch the desired Row:
>
> <xsl:function name="f:getRow">
>     <xsl:param name="element"/>
>     <xsl:param name="parent"/>
>     <xsl:sequence select="$document/Row[Cell[1]/Data eq
> $element][Cell[2]/Data eq $parent]" />
> </xsl:function>
>
> I call the function this way:
>
> <xsl:sequence select="f:getRow('airport', 'airports')" />
>
> Sometimes there is an element that doesn't have a parent. That is,
> sometimes I'd like to fetch a Row in which Cell[2] is empty, like this:
>
>     <Row>
>         <Cell>
>             <Data>aviation</Data>
>         </Cell>
>         <Cell/>
>     </Row>
>
> Then this call to f:getRow fails:
>
> <xsl:sequence select="f:getRow('aviation', '')" />        <!-- Those are
> two apostrophes within the parentheses -->
>
> Clearly I need to modify f:getRow. I could add special case code to test
> $parent to see if it is empty (the '' string) and do one thing, and if it's
> not empty do another thing. But I wonder if there is a more elegant
> solution that doesn't involve special case code? Is there a way to modify
> the XPath expression in f:getRow such that it fetches the correct Row
> regardless of whether $parent is empty or not?
>
> Testing with XSLT 2.0. Below is an example, for the solution you may be
> looking for,
>
> XML input document,
>
> <Document>
>     <Row>
>        <Cell>
>           <Data>airport</Data>
>        </Cell>
>        <Cell>
>           <Data>airports</Data>
>        </Cell>
>     </Row>
>     <Row>
>        <Cell>
>           <Data>airport</Data>
>        </Cell>
>        <Cell>
>           <Data>ABC</Data>
>        </Cell>
>     </Row>
>     <Row>
>       <Cell>
>          <Data>aviation</Data>
>       </Cell>
>       <Cell/>
>     </Row>
> </Document>
>
> XSLT stylesheet,
>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>                          xmlns:f="http://test_fn";
>                          exclude-result-prefixes="f"
>                          version="2.0">
>
>    <xsl:output method="xml" indent="yes"/>
>
>    <xsl:variable name="document" select="/Document"/>
>
>    <xsl:template match="/">
>       <result>
>          <xsl:copy-of select="f:getRow('airport', 'airports')"/>
>          <xsl:copy-of select="f:getRow('aviation', '')"/>
>       </result>
>    </xsl:template>
>
>    <xsl:function name="f:getRow">
>      <xsl:param name="element"/>
>      <xsl:param name="parent"/>
>      <xsl:sequence select="$document/Row[Cell[1]/Data eq
> $element][Cell[2]/string(Data) eq $parent]" />
>    </xsl:function>
>
> </xsl:stylesheet>
>
> The output of above XSLT transformation is following,
>
> <?xml version="1.0" encoding="UTF-8"?>
> <result>
>    <Row>
>        <Cell>
>           <Data>airport</Data>
>        </Cell>
>        <Cell>
>           <Data>airports</Data>
>        </Cell>
>     </Row>
>    <Row>
>       <Cell>
>          <Data>aviation</Data>
>       </Cell>
>       <Cell/>
>     </Row>
> </result>
>
>
>
> --
> Regards,
> Mukul Gandhi
> http://www.mulberrytech.com/xsl/xsl-list
> http://lists.mulberrytech.com/unsub/xsl-list/673357 ()
> 
>
>

-- 
...Wendell Piez... ...wendell -at- nist -dot- gov...
...wendellpiez.com... ...pellucidliterature.org... ...pausepress.org...
...github.com/wendellpiez... ...gitlab.coko.foundation/wendell...

Current Thread