Re: [xsl] How to do macro substitution in XPath?

Subject: Re: [xsl] How to do macro substitution in XPath?
From: "Martin Honnen martin.honnen@xxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 2 Dec 2023 15:49:28 -0000
On 02/12/2023 16:36, Roger L Costello costello@xxxxxxxxx wrote:
Hi Folks,

I am converting prose like this:

If the title = "Path to Power" and the author = "Robert A. Caro" (Lyndon
Baines Johnson (LBJ)), then
process LBJ as follows
     action 1
If the title = "Power Broker" and the author = "Robert A. Caro" (Robert
Moses (RM)), then
process RM as follows
     action 2
Neither LBJ nor RM
     action 3

I need the XPath to be as like the prose as possible.

Suppose the XPath will operate on XML documents like this:

<Book>
   <Title>Path to Power</Title>
   <Author>Robert A. Caro</Author>
</Book>

Below is one approach to writing the XPath. See the XPath in the
xsl:value-of element. Notice the use of XML ENTITIES.

The advantage of that approach is the XPath looks like the prose.


The disadvantage with that approach is that ENTITIES are not XPath. I need
to stick with pure XPath. What XPath do you recommend?

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xsl:stylesheet[ <!ENTITY LBJ "((/Book/Title eq 'Path to Power') and (/Book/Author eq
'Robert A. Caro'))">
<!ENTITY RM "((/Book/Title eq 'Power Broker') and (/Book/Author eq
'Robert A. Caro'))">
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="3.0">
     <xsl:template match="/">
         <xsl:value-of select="
             if &LBJ; then
                 'action 1'
             else if &RM; then
                 'action 2'
             else if (not((&LBJ;) or (&RM;))) then
                 'action 3'
             else
                 'Error'
             "/>
     </xsl:template>
</xsl:stylesheet>


You ca do the following using static parameters and shadow attributes:


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="3.0" B B B xmlns:xs="http://www.w3.org/2001/XMLSchema"; B B B exclude-result-prefixes="#all">

B B B  <xsl:param name="LBJ" as="xs:string" static="yes"
select="'((/Book/Title eq ''Path to Power'') and (/Book/Author eq
''Robert A. Caro''))'"/>
B B B  <xsl:param name="RM" as="xs:string" static="yes"
select="'((/Book/Title eq ''Power Broker'') and (/Book/Author eq
''Robert A. Caro''))'"/>

B B B  <xsl:template match="/">
B B B B B B B  <xsl:value-of _select="
B B B B B B B B B B B  if {$LBJ} then
B B B B B B B B B B B B B B B  'action 1'
B B B B B B B B B B B  else if {$RM} then
B B B B B B B B B B B B B B B  'action 2'
B B B B B B B B B B B  else if (not(({$LBJ}) or ({$RM}))) then
B B B B B B B B B B B B B B B  'action 3'
B B B B B B B B B B B  else
B B B B B B B B B B B B B B B  'Error'
B B B B B B B B B B B  "/>
B B B  </xsl:template>


Whether that is helpful or readable/maintainable in the end, I am not sure, but you asked for a way without entities, so I am trying to show one.

Current Thread