[xsl] template matching with modes, not seeing what I expect

Subject: [xsl] template matching with modes, not seeing what I expect
From: "Trevor Nicholls trevor@xxxxxxxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 15 Mar 2020 10:04:40 -0000
In these difficult times I hope everybody reading this is safe and well and
stays that way.


I'm testing a simple stylesheet which implements a suggestion made in reply
to my previous approach, i.e. that I could process the output of a document
into a variable to test. When the stylesheet is just reporting the results,
it works just fine, but when I combine it with templates which copy the
input document and replace one attribute based on those tests, the input
document is not being copied.


Sorry that the question comes at the bottom of quite a long message.


Here's the stylesheet


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
<xsl:output method="xml" encoding="UTF-8" />

<!-- standard identity template -->

<xsl:template match="*">


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

    <xsl:apply-templates />




<xsl:template match="@*">

  <xsl:copy-of select="." />


<!-- special case for sections -->
<xsl:template match="section">
    <xsl:attribute name="subsects">
      <xsl:call-template name="checkchildren" />
    <xsl:apply-templates select="@*[name() != 'subsects']" />
    <xsl:apply-templates />

<!-- check what sort of section it is: has only a title and sections, has no
sections, or is mixed -->
<!-- build a cut down copy of the structure in a variable and test that-->
<xsl:template name="checkchildren">
  <xsl:variable name="tempstruct">
    <xsl:element name="section">
     <xsl:apply-templates mode="check" />
  <xsl:call-template name="testsections">
    <xsl:with-param name="top" select="$tempstruct" />

<xsl:template match="section" mode="check">


    <xsl:apply-templates mode="check" />




<xsl:template match="title" mode="check">


    <xsl:value-of select="." />




<xsl:template match="included" mode="check">

  <xsl:apply-templates mode="check" />



<xsl:template match="*" mode="check">

  <xsl:element name="{local-name()}">
<!-- <xsl:apply-templates /> -->

<xsl:template name="testsections">

  <xsl:param name="top" />

  <xsl:for-each select="$top/*">
      <xsl:when test="not(child::section)">
      <xsl:when test="child::*[not(self::title)][not(self::section)]">




As I understand it, the above stylesheet should copy its input XML exactly,
adding or adjusting the subsects attribute on every section element to
reflect whether (apart from a title) it contains only sections, no sections,
or a mixture.


But if I run this stylesheet and give it an input file (with no subsects
attributes) which contains a parent with multiple sections and mixed
content, only the first section is output with the attribute (incorrectly
set to "none"), and the rest of the output XML is the result of the
mode="check" versions of the templates, i.e. the only output is the initial
XML header followed by a copy of the $tempstruct variable built when the
context node is the top level element of the input document.. The default
templates simply aren't executed.


If I remove the identity template, and instead of copying the document and
filling in the new attribute, change checkchildren to output the values for
each section as text nodes, it behaves as I'd expect.


By putting a message into the <xsl:template match="*"> template (the one
without a mode) I have verified that this particular template is executed
exactly once: for the path /document/title. 


Have I misunderstood how modes work? Is there a coding error that I haven't
noticed? The XSL processor is Saxon and the stylesheet is XSL 2.0.


Take care out there




Current Thread