Question

This is about page numbering across multiple, grouped XML files, by using an index file to access the individual XML files. The numbering must start anew for each group, and span all files within the group. This is my index.xml file, that defines the groups and individual files:

<list>
  <numberGroup>
    <entry>
      <file>n1.xml</file>
    </entry>
    <entry>
      <file>n2.xml</file>
    </entry>
    <entry>
      <file>n3.xml</file>
    </entry>
  </numberGroup>
  <numberGroup>
    <entry>
      <file>p1.xml</file>
    </entry>
    <entry>
      <file>p2.xml</file>
    </entry>
    <entry>
      <file>p3.xml</file>
    </entry>
  </numberGroup>
  <numberGroup>
    <entry>
      <file>a1.xml</file>
    </entry>
    <entry>
      <file>a3.xml</file>
    </entry>
  </numberGroup>
</list>

All <file>s n1.xml, n2.xml etc. have numerous tags <page/>, that are transformed into page numbers during the transformation. (<span class="r" id="pg12">...</span>)

This is the template I have so far:

<xsl:template match="page">
<xsl:variable name="vRoot" select="generate-id(/)"/>
<xsl:variable name="vPage" select="$vFiles[$vRoot = generate-id(document(.))]"/>
<span class="r">
  <xsl:attribute name="id">pg<xsl:value-of select="count(document( (.|$vPage)/preceding::file)//page | (.|$vPage)/preceding::page) + 1">
  </xsl:value-of></xsl:attribute>
       ...
</span>
</xsl:template>

The problem is, the numbering does not restart at 1 for each new numberGroup.

Any suggestions?.

Was it helpful?

Solution

You are counting the elements considering the full node-set of all page elements. If you want to restart the numbering in each numberGroup you have to select them in this context.

I'm assuming your n1.xml, p1.xml files have this format:

<pages>
    <page/>
    <page/>
    <page/>
</pages>

You can restrict the context of your selection to the files that are in each numberGroup by creating a template for numberGroup and selecting the page elements within that context:

<xsl:template match="numberGroup">
    <xsl:apply-templates select="document(entry/file)//page"/>
</xsl:template>

Now, for each page you just have to get its position():

<xsl:template match="page">
    <span class="r" id="pg{position()}"/>
</xsl:template>

This would produce this result:

<div>
   <span class="r" id="pg1"/>
   <span class="r" id="pg2"/>
   ...
   <span class="r" id="pg99"/> <!-- total pages of all files in the first group -->
</div>
<div>
   <span class="r" id="pg1"/>
   <span class="r" id="pg2"/>
   ...
   <span class="r" id="pg19"/> <!-- total pages in second group -->
</div>
<div>...</div>

So the solution should be much simpler than the one you were trying. You don't need any variables or complex XPath expressions. Here is a full stylesheet that should produce a result similar to what you expect:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="numberGroup">
        <div>
            <xsl:apply-templates select="document(entry/file)//page"/>
        </div>
    </xsl:template>

    <xsl:template match="page">
        <span class="r" id="pg{position()}"/>
    </xsl:template>
</xsl:stylesheet>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top