tags:

views:

85

answers:

3

I'm sure that this is an extremely basic question but here goes anyway! I have read that the built in template rule for text and attribute nodes in XSLT is

<xsl:template match="text()|@*">
  <xsl:value-of select="."/>
</xsl:template>

However for the source document

<?xml version="1.0"?>
<booker>
 <award>
  <author blah="test">Aravind Adiga</author>
  <title>The White Tiger</title>
  <year>2008</year>
 </award>
</booker>

And XSLT

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="text"/>
</xsl:stylesheet>

I get the following output applying the transform in Visual Studio. Can someone please explain why I don't see "test" in the output?

Aravind Adiga

The White Tiger

2008

+3  A: 

Because the built-in rule for elements does not apply templates to an element's own attributes, only to it's child elements. If you want to traverse the attributes in the same way you traverse the child elements (which is probably an artificial task) you need to define your own default:

<xsl:template match="*">
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates/>
</xsl:template>
Vincent Marchetti
I agree, just to add for completeness - the default `<apply-templates/>` selects all child nodes, not only elements (otherwise, nothing would be output by the code from the question).
Krab
Thanks, I don't need to actually do it, I'm just trying to understand the rules. So basically the `@*` part of the built in rule will never get invoked unless it is called explicitly?
Martin Smith
+2  A: 

To address this question from a comment:

Thanks, I don't need to actually do it, I'm just trying to understand the rules. So basically the @* part of the built in rule will never get invoked unless it is called explicitly?

In this case, there are two default rules which interest us:

<xsl:template match="text()|@*">
  <xsl:value-of select="."/>
</xsl:template>

<xsl:template match="/|*">
  <xsl:apply-templates/>
</xsl:template>

When the document is processed, the second template matches the root and applies-templates. The default for apply-templates is to select all child nodes (attributes, confusingly, aren't child nodes). You never select any attribute to be processed, as the only apply-templates appears in it's default form.

So if you selected somewhere any attribute (like Vincent Marchetti did), it would be processed by the first mentioned default template.

Krab
+1 I see! Thanks it all makes sense now.
Martin Smith
+1  A: 

Principal rule is - attributes don't have identity at all - they are accessible only as sideways bits attached to a node. It's good to think of them as non-existent until you have a node first. You can also think of them as totally second class citizens in XPath and XSLT world. Every time you use them in selection conditions it's like you switched from a join to a cursor in SQL and every time you use "for" instead of "apply" the same happens as well.

Another way to put it - the only real, efficient "index" you have is the one with all XPaths in a document (.Net actually builds Hashtable of XPaths => constant time match). The reason for "apply" being privileged is that it guarantees pure functional processing - you could run everything matched by apply on separate threads with no synchronization and no memory sharing - you just concat their results.

Third way to look at it, which is a stretch, imagine that your tags are SQL tables and that you have only surrogate PK-s and FK-s - nothing else you can really select except "all from T1 and all related to them from T2". For any decent SQL engine it's like a 0-cost effort to do it - it just reads one good index item by item since the very structure of it is 1-1 with your query. Everything else costs much more.

Once you have tags selected and templates matched and running, then it's cheap to just grab values of attributes - as long as you just transform/render them. Attrib tests at the end of XPath are reasonably cheap as well - again since the final tag/node is selected and now it's just a little filter on top of it.

So, XSLT engine and XPath selection in general have very good reason to totally ignore attributes - perf.

ZXX