I'm trying to use the HTML Ninja Technique, but am finding that a nested em element is being repeated at the end of its parent tag.

My aim is to remove the opening and closing p tag (but not the text it's containing) from the text node:

        <section id="6" handle="how2-main-message">HOW2: Main message</section>
        <entry id="10">
            <heading handle="your-visual-guides-to-better-teaching">Your visual guides to better teaching</heading>
            <text mode="formatted"><p>With <em>100+</em> techniques visualised, learning new ways to teach has never been easier, faster or more compelling.</p>


<xsl:template match="/data" mode="page-heading">
        <h1><xsl:value-of select="/data/main-message/entry/heading"/></h1>
        <h2><xsl:apply-templates select="/data/main-message/entry/text//*"/></h2>

<xsl:template match="/data/main-message/entry/text//*">
    <xsl:element name="{name()}">
        <xsl:apply-templates select="* | text()"/>

<xsl:template match="/data/main-message/entry/text//p" priority="1">
    <xsl:apply-templates select="* | text()"/>

The output:

    <h1>Your visual guides to better teaching</h1>
    <h2>With <em>100+</em> techniques visualised, learning new ways to teach has never been easier, faster or more compelling.<em>100+</em></h2>

The p tag is gone as intended, but why is <em>100+</em> repeated at the end of the h2 tag?

I guess because you are selecting it with the //* expression in

<xsl:apply-templates select="/data/main-message/entry/text//*"/>

Try to be more specific by using

<xsl:apply-templates select="/data/main-message/entry/text/p/*"/>

when you know that the always is a p, or more general again direct grandchildren

<xsl:apply-templates select="/data/main-message/entry/text/*/*"/>

But why don't you just use

<xsl:copy-of select="/data/main-message/entry/text/*/*"/>

? And I think it's better to add a mode attribute to you ninja templates to avoid unwanted matches.

I need to keep the text that is directly inside the original p tag, and p/* selects only the child elements of p (such as em). I've edited my original post to make that clearer.

I think the ninja technique depends on the // to deal with all nested elements, and not just those of a certain depth?

Thanks for the reply.

Ah, I understand your comment on changing the apply-templates select parameter value properly now, @klaftertief. Sorted!

I changed:

<h2><xsl:apply-templates select="/data/main-message/entry/text//*"/></h2>


<h2><xsl:apply-templates select="/data/main-message/entry/text/p"/></h2>

Thanks again.

@DavidOliver: it is best practice to never use // for both performance reasons and the fact that you might match something you don't want to match (like you did in the above example).

Thanks. Yes, I usually stay away from //, but I mistakenly thought it was necessary to use it in the apply-templates select parameter value for the ninja technique.

I think I was confusing applying templates to a node with matching nodes via the ninja technique, and that I was applying the ninja technique multiple times. I think...

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details