xsl-list
[Top] [All Lists]

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

2022-01-02 20:42:36
On Sun, Jan 2, 2022 at 5:58 PM Chris Papademetrious
christopher(_dot_)papademetrious(_at_)synopsys(_dot_)com <
xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com> wrote:

Hi Dimitre,

Just some feedback from a novice... For me, this would be difficult to
remember to determine if a node is in a sequence:

        exists(index-of($seq, $n, id-equal#2))

A one-word operator for this would be easier for me to remember:

        $n in $seq
        $n is $seq




Hi Chris,
An advice for every novice:

(a) If you have a pressing need and want to spend the next 6 - 10 years
waiting, then ask for a new operator... Be ready to hear numerous
explanations why your proposal is a bad idea :)

(b) If you have a pressing need and want to have it resolved today, then
write your own function (and many more useful things while you are waiting
for (a)  above)


Cheers,
Dimitre





Hi everyone (again),

I was able to use the [$n intersect $seq] trick again today! And I'm proud
of how it turned out, so I wanted to share it with you.

I want to remove leading/trailing whitespace from certain DITA block
elements. For example, I want to turn this:

        <p>   This is some text.</p>

into this:

        <p>This is some text.</p>

But there are two tricky aspects:

1. The leading/trailing whitespace could be buried in a lower-level inline
element:

        <p>   Here is some text.</p>
        <p><b>   Here</b> is some text.</p>
        <p><b><i>   Here</i></b> is some text.</p>

so I need to match the first effectively rendered descendant text() node
of these block elements.

2. Some DITA block elements allow other DITA block elements in them:

        <p>   This is a paragraph element.</p>
        <li>   This is a list element.</li>

        <li>
          <p>   This is a paragraph element in a list element.</p>
        </li>

so I need the sibling-adjacency check to stop at the lowest-level
enclosing block element.

Here are the templates I came up with:


  <!-- look for leading/trailing text() nodes in these block elements -->
  <xsl:variable name="elements"
select="//(desc|dt|entry|glossterm|li|p|pre|shortdesc|title)"/>

  <!-- remove leading whitespace from leading text() nodes in block
elements -->
  <xsl:template match="text()
                       [matches(., '^\s+')]
                       [ancestor::*[. intersect
$elements][not(descendant::*[. intersect $elements])]]
                       [not(ancestor-or-self::node()
                         [ancestor::*[. intersect
$elements][not(descendant::*[. intersect $elements])]]
                         [preceding-sibling::node()]
                        )]">
    <xsl:variable name="results">
      <xsl:next-match/>  <!-- apply other templates, if needed -->
    </xsl:variable>
    <xsl:value-of select="replace($results, '^\s+', '')"/>
  </xsl:template>

  <!-- remove trailing whitespace from trailing text() nodes in block
elements -->
  <xsl:template match="text()
                       [matches(., '\s+$')]
                       [ancestor::*[. intersect
$elements][not(descendant::*[. intersect $elements])]]
                       [not(ancestor-or-self::node()
                         [ancestor::*[. intersect
$elements][not(descendant::*[. intersect $elements])]]
                         [following-sibling::node()]
                        )]">
    <xsl:variable name="results">
      <xsl:next-match/>  <!-- apply other templates, if needed -->
    </xsl:variable>
    <xsl:value-of select="replace($results, '\s+$', '')"/>
  </xsl:template>


Basically, it goes something like:

Find the text() node:

* That has leading/trailing whitespace
* That is within a block element that does not contain some other
lower-level block element
* That is not itself, or has no ancestor up to (but not including) that
block element, with a preceding/following sibling

The hardest part was figuring out how to get all ancestors up to the first
block element, but not past that. The nesting of [descendant::*[...]]
within [ancestor::*] is probably not the most performant way to do this,
but it gets the job done.

And by using <xsl:next-match/>, the templates can work together to remove
both leading and trailing whitespace from the same text() node, if needed.

 - Chris






-- 
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
Never fight an inanimate object
-------------------------------------
To avoid situations in which you might make mistakes may be the
biggest mistake of all
------------------------------------
Quality means doing it right when no one is looking.
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play
-------------------------------------
To achieve the impossible dream, try going to sleep.
-------------------------------------
Facts do not cease to exist because they are ignored.
-------------------------------------
Typing monkeys will write all Shakespeare's works in 200yrs.Will they write
all patents, too? :)
-------------------------------------
Sanity is madness put to good use.
-------------------------------------
I finally figured out the only reason to be alive is to enjoy it.
--~----------------------------------------------------------------
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>