Search

http://getsymphony.com/learn/articles/view/html-ninja-technique/

In the article, the author shows how to select the body element, and transform its contents. I've only had any success in selecting items from the input XML, "/", "data", "data/navigation", and so on.

Is the Ninja Technique only applicable when dealing with HTML in the XML input, such as when returning HTML from the database?

Or is it possible to use it to transform HTML elements that I define in my xslt stylesheets?

I think the principle of the Ninja Technique is derived from a common approach with XSLT: the identity template or the identity transform. The technique is not restricted to HTML elements.

    <xsl:template match="/">
<html lang="en" class="no-js">
    <head>
        <title><xsl:apply-templates select="data" mode="page-title"/></title>
        <meta name="description" content=""/>       
        <xsl:call-template name="scripts"/>
    </head>
    <body>test</body>
    </html>
    </xsl:template>

    <xsl:template match="body">
        !!<xsl:value-of select="."/>??
    </xsl:template>

Is the above code possible? I can't even get close to getting it to work. I can only match elements shown in ?debug, such as /data, and /data/navigation.

It appears you're trying to match a node in your output document not in your input document.

So I take it then, that it's not designed to be used that way?

That's a shame. Would be a useful feature.

So I take it then, that it's not designed to be used that way?

Not using that technique. What are you trying to do exactly? Why don't you alter that template?

There's many different things I'd like to do with this kind of technique, but here's one example:

<xsl:template match="/">
<html lang="en" class="no-js">
    <body>      
        <div id="top" class="foo bar">
            <xsl:apply-templates select="data" mode="top"/>
        </div>
    </body>         
</html>
</xsl:template>

<xsl:template match="/data" mode="top"> 
    <xsl:attribute name="class">
        <!--<xsl:value-of select="." />-->
        purple
    </xsl:attribute>
    <xsl:text>the parent div is now purple!</xsl:text>
</xsl:template>

As it is, this replaces the class of 'foo bar' with 'purple'. What I would like to do, is to have a technique where I can add 'purple' to the class rather than replace it.

I know there are ways to do that, but what I'm looking for is one where the children can transform the parent, without the parent specifically calling any templates or functions to perform that task.

ie, I'd like to transform elements in the output document, rather than replace them.

You could probably figure something out by throwing the code into a variable creating a tree fragment and utilize exsl:note-set to get what you want:

http://www.exslt.org/exsl/functions/node-set/index.html

What I would like to do, is to have a technique where I can add 'purple' to the class rather than replace it.

I don't fully understand this... You have complete control over the output. The class names are hard-coded in your xslt. Why not just add purple? Or add the other class names in your xsl:attribute if you want a conditional statement to determine if purple needs to be added?

It seems to me your looking for a solution for something that isn't really a problem.

Also you could make use of template overloading:

In your master.xsl:

<xsl:template match="/">
<html lang="en" class="no-js">
    <body>
        <div id="top" class="foo bar">
            <xsl:attribute name="class">foo bar <xsl:call-template name="class" /></xsl:attribute>
            <xsl:apply-templates />
        </div>
    </body>
</html>
</xsl:template>

<xsl:template name="class" /> <!-- this template is an empty stub -->

and in your blog.xsl:

<xsl:template match="data">
    something, you know... your templates
</xsl:template>

<xsl:template name="class">purple</xsl:template> <!-- this template overloads the empty stub from master.xsl -->

That way your pages, like blog.xsl can override the default (empty) template and inject their own classname into the master template.

removed

Remie, the purpose is more modular code. Repeating the words "foo bar" because its in the master.xsl isn't a good solution. Requiring a template that processes the logic for all the colors of the rainbow isn't a good solution either. Template overrides don't quite accomplish it either, because what if I need to add 'purple' to #top in one template, and 'grid_12' to #top from another template? I'd rather be able to add and remove arbitrary values while keeping the rest of the attribute intact. It is well-formatted XML after all - should be able to do that!

Lewis, thank you.. that could work. I'll have to play with that some.

<xsl:variable name="html">
<template>
    <html lang="en" class="no-js">
        <head>
            <title><xsl:apply-templates select="data" mode="page-title"/></title>
            <meta name="description" content=""/>       
            <xsl:call-template name="scripts"/>
        </head>
        <body>      
            <div id="top" class="foo bar">
                test
            </div>
        </body>         
    </html>
</template>
</xsl:variable> 

<xsl:template match="/">    
    <xsl:apply-templates select="exsl:node-set($html)/*" />
</xsl:template>

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

<xsl:template match="template//@*">
    <xsl:attribute name="{name(.)}">
        <xsl:value-of select="."/>
    </xsl:attribute>
</xsl:template>

<xsl:template match="template//div[@id='top']/@class">
    <xsl:attribute name="class"><xsl:value-of select="." /> purple</xsl:attribute>
</xsl:template>

Thanks for the tip lewis! :)

Cool, that's what I was thinking. Glad you worked it out!

Please don't read the above solution unless you dare to become a Super-Ninja! :-)

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