Re: [xsl] with XPath 1.0, select all following sibling elements of name "foo" up to the first non-"foo" element

Subject: Re: [xsl] with XPath 1.0, select all following sibling elements of name "foo" up to the first non-"foo" element
From: "Dimitre Novatchev dnovatchev@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 19 Feb 2021 01:29:09 -0000
Here is a short and efficient XSLT 1.0 solution using keys:

<xsl:stylesheet version="1.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform";>
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:key name="kPrecedingFoo" match="foo"
use="generate-id(following-sibling::*[not(self::foo)])"/>

  <xsl:template match="/*/*[1]">
    <xsl:copy-of select="key('kPrecedingFoo',
generate-id(../*[not(self::foo)][1]))"/>
  </xsl:template>
</xsl:stylesheet>

Applying this transformation on variations of the following XML document
(try uncommenting different subsets of the commented elements) produces
always the wanted result:

<t>
  <!-- <bar/> -->
  <foo ind="1"/>
  <foo ind="2"/>
  <!-- <bar/> -->
  <foo ind="3"/>
</t>

Cheers,
Dimitre

On Wed, Feb 17, 2021 at 5:32 PM Wolfhart Totschnig
wolfhart.totschnig@xxxxxxxxxxx <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
wrote:

> Dear list,
>
> I am facing an XPath problem for which I cannot find the solution. I
> want to select all following sibling elements of name "foo" up to the
> first non-"foo" element. So, in the following case, the first two <foo>
> elements should be selected:
>
> <foo/>
> <foo/>
> <bar/>
> <foo/>
>
> In the following case, all three <foo> elements should be selected:
>
> <foo/>
> <foo/>
> <foo/>
>
> And in the following case, nothing should be selected:
>
> <bar/>
> <foo/>
> <foo/>
>
> I came up with the following non-working approach:
>
>              <xsl:choose>
>                  <xsl:when
> test="not(following-sibling::*[not(self::foo)])">
>                      <xsl:value-of select="following-sibling::*"/>
>                  </xsl:when>
>                  <xsl:otherwise>
>                      <xsl:value-of
>
> select="following-sibling::*[not(self::source)][1]/preceding-sibling::*[self::source][preceding-sibling::current()]"/>
>                  </xsl:otherwise>
>              </xsl:choose>
>
> That is, test whether there are non-"foo" following siblings. If there
> are none, take all following siblings. If there are, go forward to the
> first non-"foo" sibling, and from there go backwards, taking all the
> "foo" siblings up to the current node.
>
> But this does not work. Apparently, the expression
> "preceding-sibling::current()" is not a valid construct. So what is the
> correct way to do what I have in mind (or a simpler solution, if there
> is one). Please note that this stylesheet needs to be executed by a web
> browser, and so the solution has to remain within XPath 1.0.
>
> Thanks in advance for your help!
> Wolfhart
> 
>
>

-- 
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.

Current Thread