XSL numbering using two different sets simultaneou

2019-03-06 10:22发布

Following on from my previous question and the given solution XSL numbering at different levels ....

The previous question dealt with inserting 'footnote' numbers into an XML text using XSL 3.0/Saxon. The provided solution worked well, if well above my ability to understand. As these things go, I actually need to insert 2 types of footnotes, some using numbers (1, 2, 3), some using letters (a,b,c), depending on the element receiving the footnote number/letter. The revised sandbox with updated files including incorrect output is found here: http://xsltfiddle.liberty-development.net/948Fn5a/6

I assumed that one could 'double up' the given solution, using separate modes, however the second mode appnotes doesn't do anything, except, it seems, to double the original text! (see xsltfiddle sandbox for results)

Sample XML:

<?xml version="1.0" encoding="utf-8" ?>
<corpus>
<deposition>
    <deposition-title>Praesent vitae</deposition-title>
    <text>
        <seg type="not_foo">Lorem ipsum dolor sit amet, consectetur 
            adipiscing elit. Vivamus<note2>another note 2</note2> 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="foo">Curabitur pulvinar leo eget. Orci varius 
            natoque penatibus<note2>another note 2</note2> 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>
<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<note2>another note 2</note2> pellentesque 
            malesuada elit sed tempor.</seg>
    </text>
</deposition>

XSL 3.0:

<?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"
    exclude-result-prefixes="xs"
    version="3.0">

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

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

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

<xsl:variable name="footnotes">
  <xsl:apply-templates mode="add-footnotes"/>
</xsl:variable>

<xsl:variable name="appnotes">
  <xsl:apply-templates mode="add-appnotes"/>
</xsl:variable>

<xsl:template match="seg[@type = 'foo'] | note" mode="add-footnotes">
  <xsl:next-match/>
  <footnote/>
</xsl:template>

<xsl:template match="note2" mode="add-appnotes">
  <xsl:next-match/>
  <appnote/>
</xsl:template>

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

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

<xsl:template match="appnote">
  <xsl:copy>
      <xsl:number level="any" format="a" from="deposition"/>
  </xsl:copy>
</xsl:template>

My expected result would be that elements seg[@type = 'foo'] | note would now be followed by <footnote> with 1, 2, 3, etc, and element note2 now followed by <appnote> with a, b, c. But only the former happens....while doubling the entire XML document. Again see the sandbox linked above.

Thanks in advance.

标签: xml xslt
1条回答
姐就是有狂的资本
2楼-- · 2019-03-06 10:40

If you want to solve that with three different steps then you need to make sure the second step uses the result of the first step as the input and not the original input, that is, you have to make sure you use the variables a bit differently:

<?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:mode name="add-appnotes" on-no-match="shallow-copy"/>

  <xsl:variable name="footnotes">
      <xsl:apply-templates mode="add-footnotes"/>
  </xsl:variable>

  <xsl:variable name="appnotes">
      <xsl:apply-templates select="$footnotes/node()" mode="add-appnotes"/>
  </xsl:variable>

  <xsl:template match="seg[@type = 'foo'] | note" mode="add-footnotes">
      <xsl:next-match/>
      <footnote/>
  </xsl:template>

    <xsl:template match="note2" mode="add-appnotes">
      <xsl:next-match/>
      <appnote/>
  </xsl:template>

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

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

  <xsl:template match="appnote">
      <xsl:copy>
          <xsl:number level="any" format="a" from="deposition"/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

http://xsltfiddle.liberty-development.net/948Fn5a/7

I would think however that you don't need three modes respectively three steps, you could simply add your template creating the appnotes to the first step/mode:

<?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"
    exclude-result-prefixes="xs"
    version="3.0">

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

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

  <xsl:variable name="notes">
      <xsl:apply-templates mode="add-notes"/>
  </xsl:variable>

  <xsl:template match="seg[@type = 'foo'] | note" mode="add-notes">
      <xsl:next-match/>
      <footnote/>
  </xsl:template>

  <xsl:template match="note2" mode="add-notes">
      <xsl:next-match/>
      <appnote/>
  </xsl:template>

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

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

  <xsl:template match="appnote">
      <xsl:copy>
          <xsl:number level="any" format="a" from="deposition"/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

http://xsltfiddle.liberty-development.net/948Fn5a/8

As a variation on that approach, as you only want to transform the deposition elements and only need to number the other elements in that subtree, it might be easier and more efficient to not use global variables with the whole tree transformed but to only transform the deposition contents:

<?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"
    exclude-result-prefixes="xs"
    version="3.0">

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

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

    <xsl:template match="deposition">
        <xsl:variable name="notes-added">
            <xsl:apply-templates mode="add-notes"/>
        </xsl:variable>
        <xsl:copy>
            <xsl:apply-templates select="$notes-added/node()"/>           
        </xsl:copy>     
    </xsl:template>

    <xsl:template match="seg[@type = 'foo'] | note" mode="add-notes">
        <xsl:next-match/>
        <footnote/>
    </xsl:template>

    <xsl:template match="note2" mode="add-notes">
        <xsl:next-match/>
        <appnote/>
    </xsl:template>

    <xsl:template match="footnote">
        <xsl:copy>
            <xsl:number level="any" format="1"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="appnote">
        <xsl:copy>
            <xsl:number level="any" format="a"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

http://xsltfiddle.liberty-development.net/948Fn5a/9

查看更多
登录 后发表回答