XSL numbering at different levels

2019-08-18 20:06发布

问题:

I have an XML text document that looks like this:

<corpus>
 <deposition>
  <deposition-title>Praesent vitae</deposition-title>
  <text>
   <seg type="not_foo">Lorem ipsum dolor sit amet, consectetur 
     adipiscing elit. Vivamus ultrices consequat facilisis. 
     Suspendisse a odio<note>foo note</note> in lobortis. Aenean 
     non dui scelerisque, rutrum est at, cursus sem.</seg>
   <seg type="foo">Ut pharetra bibendum ipsum, portitor 
     velit pharetra quis. Aeneano<note>foo note</note> purus. Praesent 
     aliquam viverra tellus in condimentum.</seg>
   </text>
 </deposition>
 <deposition>
  <deposition-title>Elementum arcu non</deposition-title>
  <text>
    <seg type="foo">Curabitur pulvinar leo eget. Orci varius 
     natoque penatibus et magnis dis<note>foo note</note> montes, 
     nascetur ridiculus mus.</seg>
    <seg type="not_foo">Morbi vehicula dolor bibendum enim mollis lobortis. 
     Nulla rutrum vel diam vel posuere. Aliquam pellentesque 
     malesuada elit sed tempor.</seg>
   </text>
 </deposition>
</corpus>

I am adding footnote numbers to it in preparation to print, doing some preprocess using XSL 3.0 on Saxon. The target output adds <footnote/> plus increment number on two conditions, seg[@type='foo'] | note. The numbers reset to zero for each deposition. The result should look like this:

<corpus>
 <deposition>
  <deposition-title>Praesent vitae</deposition-title>
  <text>
   <seg type="not_foo">Lorem ipsum dolor sit amet, consectetur 
     adipiscing elit. Vivamus ultrices consequat facilisis. 
     Suspendisse a odio<note>some note</note><footnote>1</footnote> in lobortis. Aenean 
     non dui scelerisque, rutrum est at, cursus sem.</seg>
   <seg type="foo">Ut pharetra bibendum ipsum, portitor 
     velit pharetra quis. Aeneano<note>some note</note><footnote>2</footnote> purus. Praesent 
     aliquam viverra tellus in condimentum.</seg><footnote>3</footnote>
   </text>
 </deposition>
 <deposition>
  <deposition-title>Elementum arcu non</deposition-title>
  <text>
    <seg type="foo">Curabitur pulvinar leo eget. Orci varius 
     natoque penatibus et magnis dis<note>some note</note><footnote>1</footnote> montes, 
     nascetur ridiculus mus.</seg><footnote>2</footnote>
    <seg type="not_foo">Morbi vehicula dolor bibendum enim mollis lobortis. 
     Nulla rutrum vel diam vel posuere. Aliquam pellentesque 
     malesuada elit sed tempor.</seg></seg><footnote>3</footnote>
   </text>
 </deposition>
</corpus>

I am using the following to copy and insert the <footnote>with number:

<xsl:template match="seg[@type='foo'] | note">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy><footnote><xsl:number count="seg[@type='foo'] | note" from="deposition" format="1" level="any"/></footnote>
</xsl:template>

However, the result is not what I expected. It seems this template, in terms of assigning numbers, is treating the seg element first, and then anything inside the seg second? Like layers? In the case of the first deposition it results in this new XML:

<deposition>
  <deposition-title>Praesent vitae</deposition-title>
  <text>
   <seg>Lorem ipsum dolor sit amet, consectetur 
     adipiscing elit. Vivamus ultrices consequat facilisis. 
     Suspendisse a odio<note>some note</note><footnote>2</footnote> in lobortis. Aenean 
     non dui scelerisque, rutrum est at, cursus sem.</seg>
   <seg type="foo">Ut pharetra bibendum ipsum, portitor 
     velit pharetra quis. Aeneano<note>some note</note><footnote>3</footnote> purus. Praesent 
     aliquam viverra tellus in condimentum.</seg><footnote>1</footnote>
   </text>
 </deposition>

This means the footnotes are not in 'real' (or 'printable') order.

Not sure what is causing this. Thanks for any assistance.

回答1:

I have taken a different approach, it uses a first transformation step to add empty footnote elements and a second transformation step to number these using xsl:number:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:array="http://www.w3.org/2005/xpath-functions/array"
    exclude-result-prefixes="xs math map array"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:mode name="add-footnotes" on-no-match="shallow-copy"/>

  <xsl:variable name="footnotes">
      <!-- populating variable by pushing the global context item's child node through the mode named 'add-footnotes' -->
      <xsl:apply-templates mode="add-footnotes"/>
  </xsl:variable>

  <xsl:template match="seg[@type = 'foo'] | note" mode="add-footnotes">
      <!-- delegating copying of the element to the identity transformation -->
      <xsl:next-match/>
      <footnote/>
  </xsl:template>

  <xsl:template match="/">
      <xsl:apply-templates select="$footnotes/node()"/>
  </xsl:template>

  <xsl:template match="footnote">
      <xsl:copy>
          <xsl:number level="any" from="deposition"/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Sample at http://xsltfiddle.liberty-development.net/eiQZDbe/1



回答2:

I don't think you'll be able to do this with xsl:number.

The only way I can think of really is to count the preceding seg/note, add 1 (for self), and add any descendant note.

Preceding is not very efficient though so hopefully I'm overlooking something and you'll get a better answer.

Example...

XML Input (added an additional note for testing)

<corpus>
    <deposition>
        <deposition-title>Praesent vitae</deposition-title>
        <text>
            <seg type="not_foo">Lorem ipsum dolor sit amet, consectetur 
                adipiscing elit. Vivamus ultrices consequat facilisis. 
                Suspendisse a odio<note>foo note</note> in lobortis. Aenean 
                non dui scelerisque, rutrum est at, cursus sem.</seg>
            <seg type="foo">Ut pharetra bibendum ipsum, portitor 
                velit pharetra quis. Aeneano<note>foo note</note> purus. Praesent 
                aliquam viverra tellus<note>another note</note> in condimentum.</seg>
        </text>
    </deposition>
    <deposition>
        <deposition-title>Elementum arcu non</deposition-title>
        <text>
            <seg type="foo">Curabitur pulvinar leo eget. Orci varius 
                natoque penatibus et magnis dis<note>foo note</note> montes, 
                nascetur ridiculus mus.</seg>
            <seg type="not_foo">Morbi vehicula dolor bibendum enim mollis lobortis. 
                Nulla rutrum vel diam vel posuere. Aliquam pellentesque 
                malesuada elit sed tempor.</seg>
        </text>
    </deposition>
</corpus>

XSLT 2.0 (this is also valid 1.0)

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

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

  <xsl:template match="seg[@type='foo']|note">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    <xsl:variable name="dep" select="generate-id(ancestor::deposition)"/>
    <footnote>
      <xsl:value-of 
        select="count((preceding::seg[@type='foo']|preceding::note)[generate-id(ancestor::deposition)=$dep]) + 1 + count(.//note)"/>
    </footnote>
  </xsl:template>

</xsl:stylesheet>

Output

<corpus>
   <deposition>
      <deposition-title>Praesent vitae</deposition-title>
      <text>
         <seg type="not_foo">Lorem ipsum dolor sit amet, consectetur 
                adipiscing elit. Vivamus ultrices consequat facilisis. 
                Suspendisse a odio<note>foo note</note>
            <footnote>1</footnote> in lobortis. Aenean 
                non dui scelerisque, rutrum est at, cursus sem.</seg>
         <seg type="foo">Ut pharetra bibendum ipsum, portitor 
                velit pharetra quis. Aeneano<note>foo note</note>
            <footnote>2</footnote> purus. Praesent 
                aliquam viverra tellus<note>another note</note>
            <footnote>3</footnote> in condimentum.</seg>
         <footnote>4</footnote>
      </text>
   </deposition>
   <deposition>
      <deposition-title>Elementum arcu non</deposition-title>
      <text>
         <seg type="foo">Curabitur pulvinar leo eget. Orci varius 
                natoque penatibus et magnis dis<note>foo note</note>
            <footnote>1</footnote> montes, 
                nascetur ridiculus mus.</seg>
         <footnote>2</footnote>
         <seg type="not_foo">Morbi vehicula dolor bibendum enim mollis lobortis. 
                Nulla rutrum vel diam vel posuere. Aliquam pellentesque 
                malesuada elit sed tempor.</seg>
      </text>
   </deposition>
</corpus>


标签: xml xslt