Re: [xsl] Creating Footnote Ids

Subject: Re: [xsl] Creating Footnote Ids
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Thu, 05 Jul 2007 12:15:28 -0400
Hi Jeff,

At 02:15 AM 7/5/2007, you wrote:
I have an XML document that has footnote mark-up, this can appear in any level within the document. I want to create an id attribute that will have a value depending on the ancestors of the footnote element.

for example:

<book>
   <preface>
      <footnote/>
      <footnote/>
      <footnote/>
      <footnote/>
   </preface>
   <part>
       <chapter>
          <footnote/>
          <footnote/>
           <footnote/>
       </chapter>
       <chapter>
          <footnote/>
          <footnote/>
           <footnote/>
       </chapter>
      <footnote/>
      <footnote/>
      <footnote/>
   </part>
   <chapter>
      <footnote/>
      <footnote/>
      <footnote/>
   </chapter>
</book>

would turn to:

<book>
   <preface>
      <footnote id="PRE1FN1"/>
      <footnote id="PRE1FN2"/>
      <footnote id="PRE1FN3"/>
      <footnote id="PRE1FN4"/>
   </preface>
   <part>
       <chapter>
          <footnote id="P1C1FN1"/>
          <footnote id="P1C1FN2"/>
          <footnote id="P1C1FN3"/>
       </chapter>
       <chapter>
          <footnote id="P1C2FN1"/>
          <footnote id="P1C2FN2"/>
          <footnote id="P1C2FN3"/>
       </chapter>
      <footnote id="P1FN1"/>
      <footnote id="P1FN2"/>
      <footnote id="P1FN3"/>
   </part>
   <chapter>
      <footnote id="C1FN1"/>
      <footnote id="C1FN2"/>
      <footnote id="C1FN3"/>
   </chapter>
</book>

How can i do this in XSLT 2.0? I tried doing it by creating a variable for the count of each ancestor but I can get it correct.

It'd be simpler, I think, to use an XSLT 1.0 technique: simply iterate over the ancestors to generate your id string:


<xsl:template match="footnote">
  <xsl:attribute name="id">
    <xsl:apply-templates select="ancestor-or-self::*" mode="id-generate"/>
  </xsl:attribute>
  ...
</xsl:template>

<xsl:template match="part" mode="id-generate">
  <xsl:text>P</xsl:text>
  <xsl:number/>
</xsl:template>

<xsl:template match="chapter" mode="id-generate">
  <xsl:text>C</xsl:text>
  <xsl:number/>
</xsl:template>

<xsl:template match="footnote" mode="id-generate">
  <xsl:text>FN</xsl:text>
  <xsl:number/>
</xsl:template>

etc. for other ancestors you want represented in your string

<xsl:template match="*" mode="id-generate"/>
<!-- avoids default template traversal from ancestors not otherwise matched -->

I hope that helps.

Using 2.0 you could make this more concise:

<xsl:template match="preface | part | chapter | footnote" mode="id-generate">
  <xsl:variable name="code"
    select="('PRE','P','C','FN')[index-of(('preface','part','chapter','footnote'),local-name())]"/>
  <xsl:value-of select="$code"/>
  <xsl:number/>
</xsl:template>

(untested)

Note: apply-templates always works in document order, even when the nodes are selected on a reverse axis, as in this case. So the nodes will be matched in the mode from top down, not bottom up.

Cheers,
Wendell



======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================

Current Thread