user3872094
user3872094

Reputation: 3351

Template declared to match element, but never triggered

I've the following XML.

<?xml version="1.0" encoding="UTF-8"?>
<docs>
    <biblos>
        <texto xmlns="http://www.aranzadi.es/namespace/contenido/biblos/texto" idioma="spa">
            <parrafo>
                <en-origen estilo-fuente="cursiva">This is cursive text.</en-origen>
            </parrafo>
        </texto>
    </biblos>
</docs>

and the following XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <html>
            <body>
                <section class="chapter">
                    <xsl:apply-templates select="docs"/>
                </section>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="docs">
        <div class="chapter">
        <xsl:text>Docs Block</xsl:text>
            <xsl:apply-templates select="biblos"/>
        </div>
    </xsl:template>
    <xsl:template match="biblos">
      <xsl:text>biblos block</xsl:text>
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="texto">
        <xsl:text>Text To Block</xsl:text>
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="parrafo">
        <div class="para">
            <xsl:apply-templates/>
        </div>
    </xsl:template>
    <xsl:template match="parrafo">
        <span class="format-smallcaps">
            <xsl:apply-templates/>
        </span>
    </xsl:template>
    <xsl:template match="en-origen">
        <xsl:variable name="fontStyle">
            <xsl:choose>
                <xsl:when test="./@estilo-fuente">
                    <xsl:value-of select="concat('font-style-',@estilo-fuente)"/>
                </xsl:when>
                <xsl:when test="./@format">
                    <xsl:value-of select="concat('format-',@format)"/>
                </xsl:when>
            </xsl:choose>
        </xsl:variable>
        <span class="{$fontStyle}">
            <xsl:value-of select="."/>
            <xsl:apply-templates select="para"/>
        </span>
    </xsl:template>
</xsl:transform>

when i run this, I'm getting the below output.

<!DOCTYPE html
  PUBLIC "XSLT-compat">
<html>
   <body>
      <section class="chapter">
         <div class="chapter">Docs Blockbiblos block


                            This is cursive text.
         </div>
      </section>
   </body>
</html>

Here the problem is, though I've declared texto and child nodes of it in my XSLT, it is not getting called, but the text is directly getting printed.

Please let me know where I'm going wrong and how I can fix it.

Upvotes: 2

Views: 417

Answers (1)

Abel
Abel

Reputation: 57217

Good question (thanks for providing a complete, working example!). Often, if elements are not matched, the cause lies in missing namespaces:

You have the following in your input XML:

 <texto xmlns="http://www.aranzadi.es/namespace/contenido/biblos/texto" idioma="spa">

In other words, the texto element is in a namespace. In your XSLT you have the following:

<xsl:template match="texto">

Since no namespace is declared for XPath (xpath-default-namespace on the containing xsl:template or xsl:stylesheet), this will operate on elements texto in no namespace, meaning, as written, it will not match texto from your source.

You can solve this by:

<xsl:transform 
    xmlns:tto="http://www.aranzadi.es/namespace/contenido/biblos/texto"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

and:

<xsl:template match="tto:texto">

Now your template will be matched.

Remember that element names can be in a namespace if the namespace is declared on that element, but the attributes, unless prefixes, are in no nammespace, so this solution is only required (given your example input) on matching or selecting elements.

Also, it is important to realize that prefixes do not matter, they do not need to match the prefix (or absence thereof) from the source document. What matters, is that the namespace bound to the prefix matches.

If there are child elements, in this case parrafo and en-origen, these inherit the namespace given on their parent element. So if you want to match these elements as well, you should adjust their names to tto:paraffo and tto:en-origin in patterns and XPath expressions.

Upvotes: 4

Related Questions