Chris
Chris

Reputation: 1416

XSLT replace tag by generated one

I'm quite new to XSLT.

This is the problem I'm trying to solve for hours now:

I auto-generate a table of contents for a xml document which works great so far. However I'd like to replace a placeholder tag in my source xml with that just generated toc code. So the output should include the whole document with replaced placeholder-toc-tag with the auto-generated toc xml.

This is what I've tried:

Let's say I have my placeholderTag anywhere in the document and want to replace this/those. I thought that I could loop through all nodes by node() and check if the node name equals my placeholder tag:

<xsl:template match="node()">
    <xsl:choose>
        <xsl:when test="divGen">
            <!-- apply other template to generate toc-->
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="node()"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

However the if statement won't match like this.

edit: Ok, here's the source document (TEI coded - TEI namespace removed):

<TEI>
<teiHeader>
    <fileDesc>
        <titleStmt>
            <title>Title</title>
        </titleStmt>
        <publicationStmt>
            <p>Publication information</p>
        </publicationStmt>
        <sourceDesc>
            <p>Information about the source</p>
        </sourceDesc>
    </fileDesc>
</teiHeader>
<text>
    <front>
        <titlePage>
            <byline>title page details</byline>
        </titlePage>
    </front>

    <body>
        <divGen type="toc"/>

        <div type="part">
            <div type="section">
                <head>heading1</head>
            </div>
            <div type="section">
                <head>heading2</head>
            </div>
        </div>
        <div type="part">
            <div type="section">
                <head>heading3</head>
            </div>
            <div type="section">
                <head>heading4</head>
            </div>
            <div type="section">
                <head>heading5</head>
            </div>
        </div>
    </body>

    <back> </back>
</text>

I'd like to auto-generate the toc from the head values and replace the divGen tag by the auto-produced toc code. However please notice that the divGen tag can be anywhere in the document but not outside of body.

Any ideas?

Chris

Upvotes: 3

Views: 874

Answers (2)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

Good question, +1.

Here is a complete transformation (with mock TOC generation to be replaced by real one) that shows how to do this:

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

 <xsl:variable name="vTOC">
  <xsl:apply-templates mode="TOC"/>
  <mockTOC>
    <xsl:comment>The real TOC generated here</xsl:comment>
  </mockTOC>
 </xsl:variable>

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

 <xsl:template match="divGen[@type='toc']">
  <xsl:copy-of select="$vTOC"/>
 </xsl:template>

 <xsl:template match="text()" mode="TOC"/>
</xsl:stylesheet>

when this transformation is applied on the provided XML document:

<TEI>
    <teiHeader>
        <fileDesc>
            <titleStmt>
                <title>Title</title>
            </titleStmt>
            <publicationStmt>
                <p>Publication information</p>
            </publicationStmt>
            <sourceDesc>
                <p>Information about the source</p>
            </sourceDesc>
        </fileDesc>
    </teiHeader>
    <text>
        <front>
            <titlePage>
                <byline>title page details</byline>
            </titlePage>
        </front>
        <body>
            <divGen type="toc"/>
            <div type="part">
                <div type="section">
                    <head>heading1</head>
                </div>
                <div type="section">
                    <head>heading2</head>
                </div>
            </div>
            <div type="part">
                <div type="section">
                    <head>heading3</head>
                </div>
                <div type="section">
                    <head>heading4</head>
                </div>
                <div type="section">
                    <head>heading5</head>
                </div>
            </div>
        </body>
        <back>
        </back>
    </text>
</TEI>

the correct, wanted output is produced, in which any occurences of <divGen type="toc"/> are replaced by the generated TOC:

<TEI>
   <teiHeader>
      <fileDesc>
         <titleStmt>
            <title>Title</title>
         </titleStmt>
         <publicationStmt>
            <p>Publication information</p>
         </publicationStmt>
         <sourceDesc>
            <p>Information about the source</p>
         </sourceDesc>
      </fileDesc>
   </teiHeader>
   <text>
      <front>
         <titlePage>
            <byline>title page details</byline>
         </titlePage>
      </front>
      <body>
         <mockTOC><!--The real TOC generated here--></mockTOC>
         <div type="part">
            <div type="section">
               <head>heading1</head>
            </div>
            <div type="section">
               <head>heading2</head>
            </div>
         </div>
         <div type="part">
            <div type="section">
               <head>heading3</head>
            </div>
            <div type="section">
               <head>heading4</head>
            </div>
            <div type="section">
               <head>heading5</head>
            </div>
         </div>
      </body>
      <back/>
   </text>
</TEI>

Explanation: Use of modes to pre-generate the TOC in a variable, then overriding the identity rule for any TOC placeholder.

Upvotes: 2

Treemonkey
Treemonkey

Reputation: 2163

Im guessing somewhere u have a template like

<xsl:template match="/">
    <xsl:apply-templates select="*"/>
</xsl:template>

then u want the template to only match your placeholderTag

then the others will default to your other nodes!

<xsl:template match="placeholderTag">
    <!-- applying generate toc thing-->
</xsl:template>

<xsl:template match="node()">
    <xsl:copy-of select="node()"/>    
</xsl:template>

Upvotes: 0

Related Questions