xsl-list
[Top] [All Lists]

Re: [xsl] Using node-set variables in predicates (another node comparison question)

2022-01-04 14:52:42
Note that this function:

<xsl:function name="mine:is-trim-element" as="xs:boolean">
    <xsl:param name="elt" as="node()"/>
    <xsl:value-of select="exists($elt[self::desc or self::dt or self::endnote 
or self::entry or self::example-title or self::glossterm or self::li or 
self::msg-severity or self::p or self::shortdesc or self::title or 
self::value-allowed or self::value-default or self::value-type])"/>
  </xsl:function>

Should use xsl:sequence instead of value-of as you want to return a Boolean 
value.

By using value-of you are effectively constructing a Boolean (result of 
exists()) then converting that to a text node (result of value-of) and then 
XSLT implicitly converts that back to a Boolean using the string value of the 
text node.

In general, you almost always want xsl:sequence unless what you really want is 
a text node (for example, because you’re contributing to the content of a 
result element).

[Wendell beat me to this suggestion but I’d already written it:]

As for the question of determining the type: I think I would follow Dimitre’s 
advice and use templates :

<xsl:function name=”mine:is-trim-element” as=”xs:boolean”>
    <xsl:param name="elt" as="node()"/>
  <xsl:apply-templates select=”$elt” mode=” mine:is-trim-element”/>
</xsl:function>

<xsl:template mode=” mine:is-trim-element” as=”xs:Boolean”
  match=”desc | endnote | dt”

  <xsl:sequence select=”true()”/>
</xsl:template>

<xsl:template mode=” mine:is-trim-element” as=”xs:Boolean” priority=”-1” 
match=”*”>
  <xsl:sequence select=”false()”
</xsl:template>

This makes the logic for determining type extensible using normal extension 
mechanisms.

Cheers,

E.

_____________________________________________
Eliot Kimber
Sr Staff Content Engineer
O: 512 554 9368
M: 512 554 9368
servicenow.com<https://www.servicenow.com>
LinkedIn<https://www.linkedin.com/company/servicenow> | 
Twitter<https://twitter.com/servicenow> | 
YouTube<https://www.youtube.com/user/servicenowinc> | 
Facebook<https://www.facebook.com/servicenow>

From: Chris Papademetrious 
christopher(_dot_)papademetrious(_at_)synopsys(_dot_)com 
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com>
Date: Tuesday, January 4, 2022 at 2:37 PM
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com 
<xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
Subject: Re: [xsl] Using node-set variables in predicates (another node 
comparison question)
[External Email]

Hi Dimitre,

That is good advice about functions – I will keep it in mind!


Hi everyone,

So I ran into a limitation of using document node-set variables in template 
match expressions:

  <!-- put document nodes in $trim-elements -->
  <xsl:variable name="trim-elements" 
select="//(desc|dt|entry|glossterm|li|p|shortdesc|title)"/>

  <!-- reference elements in $trim-elements -->
  <xsl:template match="text()
                       [matches(., '^\s+')]
                       [ancestor::*[. intersect 
$trim-elements][not(descendant::*[. intersect $trim-elements])]]
                       [not(ancestor-or-self::node()
                         [ancestor::*[. intersect 
$trim-elements][not(descendant::*[. intersect $trim-elements])]]
                         [preceding-sibling::node()])]">

When I constructed a temporary <p> node in a variable:

xsl:variable name="temporary-p">
   <p><xsl:copy-of select=”…blah blah…”></p>
</xsl:variable>

then called <xsl:apply-templates> to apply the template:

<xsl:apply-templates select="$temporary-p"/>

the template did not get applied. This makes perfect sense – my temporary <p> 
variable does not contain any document nodes at all, so the template match 
expression would never match!

But with Dimitre’s advice about functions fresh in my mind, I converted my 
document-node variable into a node-type function:

  <xsl:function name="mine:is-trim-element" as="xs:boolean">
    <xsl:param name="elt" as="node()"/>
    <xsl:value-of select="exists($elt[self::desc or self::dt or self::endnote 
or self::entry or self::example-title or self::glossterm or self::li or 
self::msg-severity or self::p or self::shortdesc or self::title or 
self::value-allowed or self::value-default or self::value-type])"/>
  </xsl:function>

Now I can use the function instead of the variable in the match expression:

  <xsl:template match="text()
                       [matches(., '^\s+')]
                       
[ancestor::*[mine:is-trim-element(.)][not(descendant::*[mine:is-trim-element(.)])]]
                       [not(ancestor-or-self::node()
                         
[ancestor::*[mine:is-trim-element(.)][not(descendant::*[mine:is-trim-element(.)])]]
                         
[preceding-sibling::node()[not(mine:is-invisible(.))]])]">

and the template applies as expected to my temporary variable!

Follow-up question – is there some syntactic sugar that would allow me to write

self::(a|b|c)

instead of

(self::a or self::b or self::c)

or some other way of testing the element type in $elt altogether? I have 
another function that matches several dozen element types, and a more compact 
representation would be nice. I thought about matching local-name() against a 
list of tag names using “intersect”, but that is not much shorter and it seems 
operationally clunkier.

Thanks, this has been an enjoyable exercise for learning!


  *   Chris


XSL-List info and 
archive<https://urldefense.com/v3/__http:/www.mulberrytech.com/xsl/xsl-list__;!!N4vogdjhuJM!QoTfzk5BnM0e2UXvfQdi8oQSTETaMkscgawE6XS1ls6pK21OytP7rdlPobZYmhyWkmh8Ow$>
EasyUnsubscribe<https://urldefense.com/v3/__http:/lists.mulberrytech.com/unsub/xsl-list/3453418__;!!N4vogdjhuJM!QoTfzk5BnM0e2UXvfQdi8oQSTETaMkscgawE6XS1ls6pK21OytP7rdlPobZYmhxv1pEexw$>
 (by email<>)
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--
<Prev in Thread] Current Thread [Next in Thread>