xsltapply-templates

apply-templates outputs content more times than expected


I'm new to XSLT and I can't understand why the root get processed twice (at least this is my interpretation of this output).

EDIT: (I'm using Saxon-HE with XSLT 2.0) but also tested with several online processes, getting always the same result.

XSLT file

<?xml version="1.0" encoding="UTF-8"?>
<!-- XResume.xsl: resume.xml ==> resume.xhtml -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="https://github.com/IME-SE8/XResume">

<xsl:output method="html"/>

<xsl:template match="/">

<html>
<head>
  <meta charset="utf-8" />
  <meta lang="en" />
  <meta name="description" content="Personal Resume and Portfolio" />
  <title><xsl:value-of select="resume/personalInformation/name/attribute::shortForm" /> Website</title>
</head>
<body>
  <xsl:apply-templates select="resume"/>
</body>
</html>

</xsl:template>

<xsl:template match="resume">
  <div class="resume">

    <div class="header">
      <div class="name"><xsl:value-of select="personalInformation/name" /></div>
      <div class="contacts">
        <xsl:for-each select="personalInformation/contact">
          <div class="contactInformation">
            <p><xsl:value-of select="organization" /></p>
            <p><xsl:value-of select="address" /></p>
            <p><xsl:value-of select="phoneNumber" /></p>
            <p><xsl:value-of select="email" /></p>
          </div>
        </xsl:for-each>
      </div>
    </div>

    <div class="sections">
      <xsl:apply-templates />
    </div>
  </div>
</xsl:template>


<xsl:template match="interests"></xsl:template>
<xsl:template match="education"></xsl:template>
<xsl:template match="skills"></xsl:template>
<xsl:template match="experiences"></xsl:template>
<xsl:template match="projects"></xsl:template>
<xsl:template match="awards"></xsl:template>

</xsl:stylesheet>

XML file

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl"
href="https://github.com/IME-SE8/XResume/master/XResume.xsl"?>
<resume 
xmlns="https://github.com/IME-SE8/XResume" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://github.com/IME-SE8/XResume XResume.xsd">

    <personalInformation>
        <name first="John" last="Doe" shortForm="JD">John Doe</name>
        <contact type="institutional">
            <organization>StackOverflow Institute of Technology</organization>
            <address>Internet</address>
            <phoneNumber>+1 (666) 666-9999</phoneNumber>
            <email>john@d.oe</email>
        </contact>
    </personalInformation>


    <interests>
        <interest>Q and A</interest>
        <interest>XSLT</interest>
    </interests>

    <education></education>

    <skills></skills>

    <experiences></experiences>

    <projects></projects>

    <awards></awards>

</resume>

HTML output

<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <meta charset="utf-8">
      <meta lang="en">
      <meta name="description" content="Personal Resume and Portfolio">
      <title>JD Website</title>
   </head>
   <body>
      <div class="resume">
         <div class="header">
            <div class="name">John Doe</div>
            <div class="contacts">
               <div class="contactInformation">
                  <p>StackOverflow Institute of Technology</p>
                  <p>Internet</p>
                  <p>+1 (666) 666-9999</p>
                  <p>john@d.oe</p>
               </div>
            </div>
         </div>
         <div class="sections">


                    John Doe

                        StackOverflow Institute of Technology
                        Internet
                        +1 (666) 666-9999
                        john@d.oe

















         </div>
      </div>
   </body>
</html>

(yes, with that amount of blank lines)

The output header div is perfectly fine, but inside the sections div that apply-templates renders all the information in the div header again but without the HTML tags.

Is there any XSLT processing detail am I missing? Does the template match sets the context in a way that the matched element is now considered a root or something like that?


Solution

  • The problem is here:

    <div class="sections">
      <xsl:apply-templates />
    </div>
    

    This applies templates to all child nodes of the current node (resume), including the personalInformation element.

    As there is no matching template specified for personalInformation, the builtin XSLT templates are used by the XSLT processor and applying them results in outputting the concatenation of all descendent text-nodes of the personalInformation element.

    Solution:

    Replace:

    <div class="sections">
      <xsl:apply-templates />
    </div>
    

    with:

    <div class="sections">
      <xsl:apply-templates select="*[not(self::personalInformation)]" />
    </div>
    

    The result of the transformation now doesn't contain the noted problematic output:

    <html>
       <head>
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
          <meta charset="utf-8">
          <meta lang="en">
          <meta name="description" content="Personal Resume and Portfolio">
          <title>JD Website</title>
       </head>
       <body>
          <div class="resume">
             <div class="header">
                <div class="name">John Doe</div>
                <div class="contacts">
                   <div class="contactInformation">
                      <p>StackOverflow Institute of Technology</p>
                      <p>Internet</p>
                      <p>+1 (666) 666-9999</p>
                      <p>john@d.oe</p>
                   </div>
                </div>
             </div>
             <div class="sections"></div>
          </div>
       </body>
    </html>