|
Subject: Re: [xsl] An XPath expression that avoids writing special casecode? From: "Roger L Costello costello@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> Date: Fri, 18 Jun 2021 16:23:43 -0000 |
Wendell wrote:
> 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.
Ah!
Fantastic explanation!
Thank you Wendell.
/Roger
From: Wendell Piez wapiez@xxxxxxxxxxxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Sent: Friday, June 18, 2021 12:02 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: [EXT] Re: [xsl] An XPath expression that avoids writing special
casecode?
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
emptyB 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 itB 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 mailto:costello@xxxxxxxxx
<mailto:xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
Hi Mukul,
I tried your suggestion. For this XML document:
<Document>
B B <Row>
B B B B <Cell>
B B B B B B <Data>aviation</Data>
B B B B </Cell>
B B B B <Cell/>
B B </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:
B B <Row>
B B B B <Cell>
B B B B B B <Data>aviation</Data>
B B B B </Cell>
B B B B <Cell/>
B B </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 mailto:mukulg@xxxxxxxxxxxxxxxxx
<mailto:xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Sent: Friday, June 18, 2021 3:28 AM
To: mailto: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:mailto:costello@xxxxxxxxx
<mailto:mailto:xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
B
My XML document contains a bunch of <Row> elements, like so:
<Document>
B B ...
B B <Row>
B B B B <Cell>
B B B B B B <Data>airport</Data>
B B B B </Cell>
B B B B <Cell>
B B B B B B <Data>airports</Data>
B B B B </Cell>
B B </Row>
B B ...
</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">
B B <xsl:param name="element"/>
B B <xsl:param name="parent"/>
B B <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:
B B <Row>
B B B B <Cell>
B B B B B B <Data>aviation</Data>
B B B B </Cell>
B B B B <Cell/>
B B </Row>
Then this call to f:getRow fails:
<xsl:sequence select="f:getRow('aviation', '')" />B B B B <!-- 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>
B B <Row>
B B B B <Cell>
B B B B B <Data>airport</Data>
B B B B </Cell>
B B B B <Cell>
B B B B B <Data>airports</Data>
B B B B </Cell>
B B </Row>
B B <Row>
B B B B <Cell>
B B B B B <Data>airport</Data>
B B B B </Cell>
B B B B <Cell>
B B B B B <Data>ABC</Data>
B B B B </Cell>
B B </Row>
B B <Row>
B B B <Cell>
B B B B B <Data>aviation</Data>
B B B </Cell>
B B B <Cell/>
B B </Row>
</Document>B
XSLT stylesheet,
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
B B B B B B B B B B B B B xmlns:f="http://test_fn"
B B B B B B B B B B B B B exclude-result-prefixes="f"
B B B B B B B B B B B B B version="2.0">
B B <xsl:output method="xml" indent="yes"/>
B B
B B <xsl:variable name="document" select="/Document"/>
B B <xsl:template match="/">
B B B <result>
B B B B B <xsl:copy-of select="f:getRow('airport', 'airports')"/>
B B B B B <xsl:copy-of select="f:getRow('aviation', '')"/>
B B B </result>
B B </xsl:template>
B B
B B <xsl:function name="f:getRow">
B B B <xsl:param name="element"/>
B B B <xsl:param name="parent"/>
B B B <xsl:sequence select="$document/Row[Cell[1]/Data eq
$element][Cell[2]/string(Data) eq $parent]" />
B B </xsl:function>
</xsl:stylesheet>
The output of above XSLT transformation is following,
<?xml version="1.0" encoding="UTF-8"?>
<result>
B B <Row>
B B B B <Cell>
B B B B B <Data>airport</Data>
B B B B </Cell>
B B B B <Cell>
B B B B B <Data>airports</Data>
B B B B </Cell>
B B </Row>
B B <Row>
B B B <Cell>
B B B B B <Data>aviation</Data>
B B B </Cell>
B B B <Cell/>
B B </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...
...http://github.com/wendellpiez... ...gitlab.coko.foundation/wendell...
http://www.mulberrytech.com/xsl/xsl-list
http://lists.mulberrytech.com/unsub/xsl-list/673357 ()
| Current Thread |
|---|
|
| <- Previous | Index | Next -> |
|---|---|---|
| Re: [xsl] An XPath expression that , Wendell Piez wapiez@ | Thread | [xsl] user-defined XSLT functions a, David Birnbaum djbpi |
| Re: [xsl] An XPath expression that , Wendell Piez wapiez@ | Date | [xsl] user-defined XSLT functions a, David Birnbaum djbpi |
| Month |