xsl-list
[Top] [All Lists]

Re: [xsl] Add element at the end of a variable group of elements

2021-03-02 23:25:42
On Wed, 2021-03-03 at 00:01 +0000, Charles O'Connor
coconnor(_at_)ariessys(_dot_)com wrote:
Hi all,

Using XSLT 2.0, I'd like to add an element at the end of a group of
elements that may vary whether they exist. 

First, some XSLT 3 approaches...

The following works fine:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="3.0" expand-text="yes"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:xs="http://www.w3.org/2001/XMLSchema";
  exclude-result-prefixes="#all"
  >

  <xsl:output indent="yes" />

  <!--* enable  identity transform: *-->
  <xsl:mode on-no-match="shallow-copy" />

  <xsl:template match="(foo|bar|mercury|venus)[last()]">
    <xsl:next-match/> <!--* built-in template copies the element *-->
    <moon>Now with more craters!</moon>
  </xsl:template>

</xsl:stylesheet>



So maybe that's a reason to upgrade :)

You could also define two substitution groups and use predicate
patterns to match them. You could even put (foo|bar|mergcury|venus)" in
a variable, as Wendell did, and use that in a predicate pattern, e.g.:

 <xsl:variable name="first-group" as="xs:string*"
    select='("foo", "bar", "mercury", "venus")' />

 <xsl:template match=".[
    name() = $first-group
  ][
    not(following-sibling::*[1]/name() = $first-group)
  ]">
    <xsl:next-match/> <!--* built-in template copies the element *-->
    <moon>Now with more craters!</moon>
  </xsl:template>

However, this is getting obscure, may be slow, and is not the XSLT 2
you asked for.

You may find this works:
  <xsl:template match="*[name() = ('foo', 'bar', 'mercury',
'venus')][last()]">

So here is a working XSLT 2 version:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:xs="http://www.w3.org/2001/XMLSchema";
  exclude-result-prefixes="#all"
  >

  <xsl:output indent="yes" />

  <xsl:template  match="*">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:variable name="first-group" as="xs:string*"
    select="('foo', 'bar', 'mercury', 'venus')" />

  <xsl:template match="*[name() = $first-group][last()]" priority="10">
    <xsl:next-match/> <!--* built-in template copies the element *-->
    <moon>Now with more craters!</moon>
  </xsl:template>

</xsl:stylesheet>

Liam

-- 
Liam Quin, https://www.delightfulcomputing.com/
Available for XML/Document/Information Architecture/XSLT/
XSL/XQuery/Web/Text Processing/A11Y training, work & consulting.
Barefoot Web-slave, antique illustrations:  http://www.fromoldbooks.org
--~----------------------------------------------------------------
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>