开发者

Gobal counter in XSLT or alternative solution?

开发者 https://www.devze.com 2023-01-07 04:16 出处:网络
This is my Source-XML. It is originally a Word-ML which have been reduced to an own structure. Elements with name \"aaa\" can have any kind of name. The problem is the handling of footnotes:

This is my Source-XML. It is originally a Word-ML which have been reduced to an own structure. Elements with name "aaa" can have any kind of name. The problem is the handling of footnotes:

<root>
  <doc>
    <comment>text text text <footnote id="1" > text text text</comment>
    <aaa>text text text</aaa>
    <aaa>text text text<footnote id="2" /> text text text </aaa>
    <aaa>text text text<aaa/> text <footnote id="3" symbol="*"/></aaa>
    <aaa>text text text text</aaa>
    <aaa>text text te开发者_高级运维xt text<aaa>text text text<footnote id="4"  /></aaa></aaa>
 <aaa>text text text text<aaa>text text text<footnote id="4"  /></aaa></aaa>
 <aaa>text text text text<aaa>text text text<footnote id="5"  /></aaa></aaa>
    <aaa>text text text</aaa>
  </doc>
</root>

I have to transform this Source-XML in another XML. One thing i have to do is to replace the footnotes with the correspondig Number.

But it is not possible to only use the ID-Attribute. The ID is only an internal number. The footnotes should be progressive an there are following conditions:

  • Condition 1: "footnotes" that are a child of node "comment" should be ignored. the whole node "comment" is ignored.
  • Condition 2: "footnotes" that have a symbol-attribute do not count (i have to show the symbol and not the number)
  • Condition 3: it is possible that some notes have the same id (only a low percentage, but sometimes there are more links to the same footnote).

The Output should look like this (structure is not the same, only the handling of the footnotes is for interest now):

<root>
  <doc>
    <aaa>text text text</aaa>
    <aaa>text text text[1] text text text </aaa>
    <aaa>text text text<aaa/> text [*]</aaa>
    <aaa>text text text text</aaa>
    <aaa>text text text text<aaa>text text text[2]</aaa></aaa>
 <aaa>text text text text<aaa>text text text[2]</aaa></aaa>
 <aaa>text text text text<aaa>text text text[3]</aaa></aaa>
    <aaa>text text text</aaa>
  </doc>
</root>

My first thought was to have a global counter-variable which i increment according to the conditions. But since variables in XSLT are immutable it is not really an option.

I also tried to count the previous footnotes which occur before the current footnote.

        <xsl:template match="footnote">
         <xsl:call-template name="getFootnoteNumber">
          <xsl:with-param name="footNodeId" select="@id"/>
         </xsl:call-template>
        </xsl:template>

    <!-- simple template which only counts the footnotes
    that occur before the current footnode 
    the conditions 1, 2 and 3 are not yet included -->
        <xsl:template name="getFootnoteNumber">
           <xsl:param name="footNodeId"/>
           <xsl:value-of select="count(//footnote[position()&lt;=$footNodeId])"></xsl:value-of>     
    </xsl:template>
    <!-- i mostly get value "0", 
    or other strange numbers: for footNodeID=45 i get value 75, 
    doesn't really work-->

Is there a possibility to develop a global counter?

Or do i have to go on the other way with counting the previous footnotes? Although i don't really know how to implement condition 3.

Greetings and thx for any answer cpt.oneeye


This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="foot" match="footnote[not(ancestor::comment)][not(@symbol)]" use="@id"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="footnote[ancestor::comment]" priority="1" />
    <xsl:template match="footnote[@symbol]">
        <xsl:value-of select="concat('[',@symbol,']')"/>
    </xsl:template>
    <xsl:template match="footnote">
        <xsl:value-of select="concat('[',count(key('foot',@id)[1]/preceding::footnote[generate-id(.)=generate-id(key('foot',@id)[1])])+1,']')"/>
    </xsl:template>
</xsl:stylesheet>

With proper input:

<root>
    <doc>
        <comment>text text text <footnote id="1" /> text text text</comment>
        <aaa>text text text</aaa>
        <aaa>text text text <footnote id="2" /> text text text</aaa>
        <aaa>text text text <aaa/>text <footnote id="3" symbol="*"/></aaa>
        <aaa>text text text text</aaa>
        <aaa>text text text text <aaa>text text text <footnote id="4"  /></aaa></aaa>
        <aaa>text text text text <aaa>text text text <footnote id="4"  /></aaa></aaa>
        <aaa>text text text text <aaa>text text text <footnote id="5"  /></aaa></aaa>
        <aaa>text text text</aaa>
    </doc>
</root>

Result:

<root>
    <doc>
        <comment>text text text  text text text</comment>
        <aaa>text text text</aaa>
        <aaa>text text text [1] text text text</aaa>
        <aaa>text text text <aaa></aaa>text [*]</aaa>
        <aaa>text text text text</aaa>
        <aaa>text text text text <aaa>text text text [2]</aaa></aaa>
        <aaa>text text text text <aaa>text text text [2]</aaa></aaa>
        <aaa>text text text text <aaa>text text text [3]</aaa></aaa>
        <aaa>text text text</aaa>
    </doc>
</root>

Edit: Miss braquets. Next, I will post an answer without preceding axis.


XSLT 2.0 solution:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>

 <xsl:key name="kPosById" match="@pos" use="../@id"/>

 <xsl:variable name="vdistinctFootnotes">
  <xsl:for-each-group group-by="@id" select=
    "/*/*/*[not(self::comment)]//footnote[not(@symbol)]">

    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:attribute name="pos" select="position()"/>
    </xsl:copy>
  </xsl:for-each-group>
 </xsl:variable>

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

    <xsl:template match="footnote">
      <xsl:value-of select=
      "concat('[', key('kPosById', @id, $vdistinctFootnotes), ']')"/>
    </xsl:template>

    <xsl:template match="footnote[@symbol]">
     <xsl:value-of select="concat('[', @symbol, ']')"/>
    </xsl:template>

    <xsl:template match="footnote[ancestor::comment]"/>
</xsl:stylesheet>

when this transformation is applied on the provided document (corrected to be wellformed):

<root>
  <doc>
    <comment>text text text <footnote id="1" /> text text text</comment>
    <aaa>text text text</aaa>
    <aaa>text text text<footnote id="2" /> text text text </aaa>
    <aaa>text text text<aaa/> text <footnote id="3" symbol="*"/></aaa>
    <aaa>text text text text</aaa>
    <aaa>text text text text<aaa>text text text<footnote id="4"  /></aaa></aaa>
 <aaa>text text text text<aaa>text text text<footnote id="4"  /></aaa></aaa>
 <aaa>text text text text<aaa>text text text<footnote id="5"  /></aaa></aaa>
    <aaa>text text text</aaa>
  </doc>
</root>

the wanted result is produced:

<root>
  <doc>
    <comment>text text text  text text text</comment>
    <aaa>text text text</aaa>
    <aaa>text text text[1] text text text </aaa>
    <aaa>text text text<aaa/> text [*]</aaa>
    <aaa>text text text text</aaa>
    <aaa>text text text text<aaa>text text text[2]</aaa></aaa>
 <aaa>text text text text<aaa>text text text[2]</aaa></aaa>
 <aaa>text text text text<aaa>text text text[3]</aaa></aaa>
    <aaa>text text text</aaa>
  </doc>
</root>
0

精彩评论

暂无评论...
验证码 换一张
取 消