tags:

views:

77

answers:

1

As I have understood the match atribute of a template tag, it defines what part of the xml tree that will be enclosed in the template.

However ther seem to be some exceptions, I have a working peace of code, lite this:

<xsl:template match="/root/content">
    <xsl:for-each select="/root/meta/errors/error">
        <p>
            <strong>Error:</strong> <xsl:value-of select="message" /> (<xsl:value-of select="data/param" />)<br />
            <xsl:for-each select="data/option">
                <xsl:value-of select="." /><br />
            </xsl:for-each>
        </p>
        <br /><br />
    </xsl:for-each>
</xsl:template>

But when I try to add a conditional like this:

<xsl:template match="/root/content">
    <xsl:if test="not(/root/meta/error/errors/data/param)"-->
        <xsl:for-each select="/root/meta/errors/error">
            <p>
                <strong>Error:</strong> <xsl:value-of select="message" /> (<xsl:value-of select="data/param" />)<br />
                <xsl:for-each select="data/option">
                    <xsl:value-of select="." /><br />
                </xsl:for-each>
            </p>
            <br /><br />
        </xsl:for-each>
        <xsl:call-template name="trip_form">
            <xsl:with-param name="type" select="'driver'" />
                <xsl:with-param name="size" select="'savetrip'" />
            </xsl:call-template>
    </xsl:if>
</xsl:template>

It doesn't work any more, why, and how can I make it work again?

+3  A: 

Attribute matches are applied when you ask for it (you are pulling with complex and unneeded for-each resulting in no attribute matching at all), otherwise they are ignored. That's why the copy idiom is used with specific attribute apply-templates:

<xsl:template match="node() | @*">
   <xsl:copy>
      <xsl:apply-templates select="* | @*" />
   </xsl:copy>
</xsl:template>

When it comes to the order in which they are applied, the order is the document order, which means: after the element is applied, its attributes will be applied (in undetermined order) and then the element's children are applied. Attributes never have children and their parent is the containing element.

"it defines what part of the xml tree that will be enclosed in the template."

No. It is called when the processor encounters input that matches the specification, or when you specifically apply this input by using xsl:apply-templates. Your code should not use xsl:for-each, that's rarely needed. Instead, use xsl:apply-templates. This will also give you the possibility to match the attributes when you like.

Normally, you don't (need to) specify the parent in the match-attribute of apply-templates. And you surely don't write down the whole path inside the templates each time, that will wreak havoc on usability of your stylesheet... Try something like this instead and have a look at some XSL tutorials on the net (w3schools provides some basic information and Tennison's book is next to invaluable to learn about this variant of functional programming):

<xsl:template match="/">
   <xsl:apply-templates select="/root/content" />
</xsl:template>

<xsl:template match="content">
   <xsl:apply-templates select="errors/error" />
</xsl:template>

<xsl:template match="error">
    <p>
        <strong>Error:</strong> 
        <xsl:value-of select="message" /> 
        (<xsl:value-of select="data/param" />)
        <br />
        <xsl:apply-templates select="data/option" />
    </p>
    <br /><br />
</xsl:template>

<xsl:template match="option">
   <xsl:value-of select="." /><br />
</xsl:template>

"It doesn't work any more, why, and how can I make it work again?"

Because your if-statement is probably always true (or always false). Reason: if anywhere in your document the XPath is correct, it will always be false, if it is never correct, it will always be true. Using xsl:if with an XPath that starts in the root will, for the live of the transformation, always yield the same result. Not sure what you are after, so I cannot really help you further here. Normally, instead of xsl:if, we tend to use a matching template (again, yes, I know it gets boring ;).

Note: you ask something about attributes in your question, this I tried to answer in the opening paragraph (before this edit). However, there's nothing about attributes inside your code, so I don't know how to really help you.

Note on the note: LarsH suggests that you perhaps mean to ask about the match-attribute inside xsl:template. If so, the answer lies in the text above anywhere, where I talk about apply-templates and the sort. In short: the input document is processed, node by node, possibly directed by xsl:apply-templates, and it tries to find a matching template for each node it's currently at. That's all there is to it.

Abel
@Abel, the call-template is outside the for-each, so he's only calling it once per /root/content node. Not over and over again.About attributes: I had the same misunderstanding of his title at first, but then I realized he was talking about the "match" attribute of the xsl:template element. Not about matching attributes. :-)
LarsH
@Abel: You may be interested to visit this chat: http://chat.meta.stackoverflow.com and the room XSLT and XPath.
Dimitre Novatchev
@LarsH: good point, my bad. Hmm, about attributes, thanks, you seem right. I added a little section to my answer (and removed my call-template remark). @Dimitre: tx, I'll have a look!
Abel