Re: [xsl] Add id to next element

Subject: Re: [xsl] Add id to next element
From: "Eliot Kimber eliot.kimber@xxxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 19 May 2022 17:53:52 -0000
The typical way to do it is to have the processing of the section element get
the value from the preceding target element:


  <xsl:template match="section">
    <xsl:variable name="id" as="xs:string?"
      select="preceding-sibling::target[1]/@refid"
    />
    <xsl:copy>
        <xsl:attribute name="id"
          select="if ($id) then $id else generate-id(.)"
        />
        <xsl:apply-templates mode="#current"/>
    </xsl:copy>
  </xsl:template>

This assumes that every <section> is preceded by a <target> element. If thats
not the case then youd have to do a little more work to only select a target
that follows any preceding sections:

    <xsl:variable name="precedingSection" as="element()?"
select="preceding-sibling::section[1]"/>
    <xsl:variable name="id" as="xs:string?"
      select="(preceding-sibling::target[. &gt;&gt;
$precedingSection])[last()]/@refid"
    />

Or something close to thatthis is (or intends to be) selecting the nearest
<target> that follows the nearest preceding <section>, which should be the
<target> that applies to the current <section>.

For the <target> element you have a template that does nothing.

Instead of constructing the $id variable as I am here, you could instead do
apply-templates to the preceding <target> in a distinct mode and have it
generate the attributethats probably cleaner but a little more work to set
up, but its an easy refactor to apply to my original code:

  <xsl:template match="section">
    <xsl:copy>
        <xsl:attribute name="id" select="generate-id(.)"/>
        <xsl:apply-templates mode="set-section-id"
          select="(preceding-sibling::target[. &gt;&gt;
$precedingSection])[last()]"
        />
        <xsl:apply-templates mode="#current"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="target" mode="set-section-id">
      <xsl:attribute name="id"
        select="@refid"
      />
  </xsl:template>

Note that the first xsl:attribute name=id will be overridden by one
generated by the target element if there is one (by the last attribute
declaration wins rule for element construction).

Alternatively you could have the processing for the <target> element call
templates on its following <section> and pass the refid value as a parameter.
But that would not be typical XSLT practice and would make it hard to find the
processing for <section>, which is obviously the primary component being
processed.

There are other ways to do it, of course, but I think this approach would be
normal best practice.

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: Raghavendra Nyshadham nyraghu27132@xxxxxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Thursday, May 19, 2022 at 12:18 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
Subject: [xsl] Add id to next element
[External Email]


I am trying to write an XSLT stylesheet to transform an XML document
(that was generated by Python Docutils) to HTML5. Here is a fragment
from the source document:

<target refid="foo"/>
<section>

The <target> element specifies an identifier for the next element,
i.e., <section>. So I want something like

<section id="foo">

in the HTML output. I am unable to figure out an XSLT way to attach an
attribute to the next element while processing <target>. Would
appreciate any help.

Thanks and regards,
Raghavendra.

Current Thread