Home > Software design >  Can I number child elements consecutively, even across parent elements?
Can I number child elements consecutively, even across parent elements?

Time:10-20

I have XML that looks basically like this:

<course>
 <class>
  <person>
    <name>bob</name>
    <age>19</age>
  </person>
  <person>
     <name>john</name>
     <age>18</age>
  <person>
 </class>
 <class>
  <person>
    <name>jane</name>
    <age>19</age>
  </person>
  <person>
    <name>greg</name>
    <age>20</age>
  </person>
 </class>
</course>

I also have all their grades, and because of the way my original data is set up, the easiest way for me to add all their grades is actually to add them via XSLT. So, I have XSLT that looks like this:

  <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="course/class/person[1]">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:copy-of select="node()"/>
            <grade>A</grade>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="course/class/person[2]">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:copy-of select="node()"/>
            <grade>B</grade>
        </xsl:copy>
    </xsl:template>

This code works great to add all of the grades for class[1], but I would like to use it to add class[2] (and 3 and 4 and so on) while keeping the person numbering consecutive, even across class elements. So, while Jane is actually class[2]/person[1], I just want her to be person[3]. Is that possible at all?

CodePudding user response:

In XSLT 3 (and perhaps 2, would need to check in the spec) I think you can express e.g. <xsl:template match="(//person)[3]"> to match the third person in the document or e.g. <xsl:template match="(class/person)[3]"> to match the third person in the document that is a child of a class. It should also be possible in XSLT 3 to set up an accumulator counting persons.

CodePudding user response:

It seems to me that you want

<xsl:template match="course/class/person">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:copy-of select="node()"/>
        <grade>
          <xsl:number level="any" from="course" format="A"/>
        </grade>
    </xsl:copy>
</xsl:template>

See https://xsltfiddle.liberty-development.net/93YNgWu

  • Related