xsltpositionxslt-2.0xslt-grouping

Add position numbers if rule from another node applies, but in the order of current node


Input:

<ROOT>
  <TEMPLATE style="test">
      <ATTRIBUTE name="Color"><VALUE><UNIT>B</UNIT><UNIT>lack</UNIT></VALUE></ATTRIBUTE>
  </TEMPLATE>
  <TEMPLATE style="test">
      <ATTRIBUTE name="Something"><VALUE>1235</VALUE></ATTRIBUTE>
      <ATTRIBUTE name="Name"><VALUE><UNIT>Hello</UNIT></VALUE></ATTRIBUTE>
      <ATTRIBUTE name="Height"><VALUE>12</VALUE></ATTRIBUTE>
  </TEMPLATE>
  <TEMPLATE style="something-else">
      <ATTRIBUTE name="Test"><VALUE>Hey</VALUE></ATTRIBUTE>
  </TEMPLATE>
  <TEMPLATE style="footnotes">
      <ATTRIBUTE name="FOOTNOTE_Test"><VALUE>not-relevant</VALUE></ATTRIBUTE>
      <ATTRIBUTE name="FOOTNOTE_Name"><VALUE>whatever</VALUE></ATTRIBUTE>
      <ATTRIBUTE name="FOOTNOTE_Color"><VALUE>Some value</VALUE></ATTRIBUTE>
  </TEMPLATE>
<ROOT>

Desired Output:

<ROOT>
  <TEMPLATE style="test">
      <ATTRIBUTE name="Color"><VALUE><UNIT>B</UNIT><UNIT>lack</UNIT> *1</VALUE></ATTRIBUTE>
  </TEMPLATE>
  <TEMPLATE style="test">
      <ATTRIBUTE name="Something"><VALUE>1235</VALUE></ATTRIBUTE>
      <ATTRIBUTE name="Name"><VALUE><UNIT>Hello</UNIT> *2</VALUE></ATTRIBUTE>
      <ATTRIBUTE name="Height"><VALUE>12</VALUE></ATTRIBUTE>
  </TEMPLATE>
  <TEMPLATE style="something-else">
      <ATTRIBUTE name="Test"><VALUE>Hey</VALUE></ATTRIBUTE>
  </TEMPLATE>
  <TEMPLATE style="footnotes">
      <ATTRIBUTE name="FOOTNOTE_Test"><VALUE>not-relevant</VALUE></ATTRIBUTE>
      <ATTRIBUTE name="FOOTNOTE_Name"><VALUE>whatever</VALUE></ATTRIBUTE>
      <ATTRIBUTE name="FOOTNOTE_Color"><VALUE>Some value</VALUE></ATTRIBUTE>
  </TEMPLATE>
<ROOT>

In my templates with the style "test" there are attributes whose name + prefix "FOOTNOTE_" can match the names of the attributes from the template "footnotes". If the name matches, a " * {position}" should be added to the attribute value. The position counts up how many footnotes have already been set, but the order is based on the test-style attributes and not on the footnotes.

I have already tried various grouping attempts and for-each loops, but they never led to the desired result.

I am using XSLT 2.0


Solution

  • Here's a slightly simpler approach:

    XSLT 2.0

    <xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:key name="fn" match="TEMPLATE[@style='footnotes']/ATTRIBUTE" use="substring-after(@name, 'FOOTNOTE_')" />
    <xsl:variable name="numbered-attributes" select="/ROOT/TEMPLATE[@style='test']/ATTRIBUTE[key('fn', @name)]" />
    <xsl:variable name="index" select="$numbered-attributes/generate-id()" />
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="ATTRIBUTE[. intersect $numbered-attributes]/VALUE"> 
        <xsl:copy>
            <xsl:apply-templates select="*"/>
            <xsl:text> *</xsl:text>
            <xsl:value-of select="index-of($index, generate-id(..))" />
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>