Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSLT replace tag by generated one

Tags:

xslt

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

like image 772
Chris Avatar asked Apr 16 '26 01:04

Chris


1 Answers

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.

like image 153
Dimitre Novatchev Avatar answered Apr 21 '26 00:04

Dimitre Novatchev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!