Something I did not realise about xsl and apply-templates
I love xsl. And I used to love apply-templates. Until today.
I always thought that apply when you have and xml that looks like this:
Then you could use apply templates to select all the children of a -
<xsl:apply-templates select="a/*">
</xsl:apply-templates >
And have the templates you need to process all the nodes -
<xsl:template match="b">
<B_Processed/>
</xsl:template>
<xsl:template match="c">
<C_Processed/>
</xsl:template>
<xsl:template match="d">
<D_Processed/>
</xsl:template>
Running this would on the provided example will generate, as expected -
<B_Processed/>
<C_Processed/>
<D_Processed/>
The behaviour I did not expect is what happens when the match encounters an unfamiliar node, so if your xml looks like this -
Notice the added <e> tag to which there isn't a template.
The output of the xsl with this input is:
<B_Processed />
<C_Processed />
<D_Processed />
<B_Processed />
Noticed that last B_Processed?
Apparently the xsl match process behaviour is that if it encounters an element in the select (the one you've specifically specified in the apply-templates) that does not have a match it will drill into that node recursively until it does find a match.
In my example <e> is unknown, but it's child <b> has a template which then gets executed.
In my world of using xsl to process xml messages this is a big disadvantage, as it means that in a way I might get unexpected results if I don't cover absolutely every option in the tempales.
For instance - if I need to filter out irrelevant elements from a message, I can't just specify the ones I need, I have to specify all the ones that might occur and I don't need as well, because otherwise they might include, internally, an element to which I have a template, although I never planned to apply it in that level.
I can pretty much state now that I will not be using apply-templates any more! Not unless I know exactly what I'm getting (and that it will never change) - which is pretty much never.
I always thought that apply when you have and xml that looks like this:
<a>
<b>
<b/>
</b>
<c>
<b/>
</c>
<d>
<b/>
</d>
</a>
Then you could use apply templates to select all the children of a -
<xsl:apply-templates select="a/*">
</xsl:apply-templates >
And have the templates you need to process all the nodes -
<xsl:template match="b">
<B_Processed/>
</xsl:template>
<xsl:template match="c">
<C_Processed/>
</xsl:template>
<xsl:template match="d">
<D_Processed/>
</xsl:template>
Running this would on the provided example will generate, as expected -
<B_Processed/>
<C_Processed/>
<D_Processed/>
The behaviour I did not expect is what happens when the match encounters an unfamiliar node, so if your xml looks like this -
<a>
<b>
<b/>
</b>
<c>
<b/>
</c>
<d>
<b/>
</d>
<e>
<b/>
</e>
</a>
Notice the added <e> tag to which there isn't a template.
The output of the xsl with this input is:
<B_Processed />
<C_Processed />
<D_Processed />
<B_Processed />
Noticed that last B_Processed?
Apparently the xsl match process behaviour is that if it encounters an element in the select (the one you've specifically specified in the apply-templates) that does not have a match it will drill into that node recursively until it does find a match.
In my example <e> is unknown, but it's child <b> has a template which then gets executed.
In my world of using xsl to process xml messages this is a big disadvantage, as it means that in a way I might get unexpected results if I don't cover absolutely every option in the tempales.
For instance - if I need to filter out irrelevant elements from a message, I can't just specify the ones I need, I have to specify all the ones that might occur and I don't need as well, because otherwise they might include, internally, an element to which I have a template, although I never planned to apply it in that level.
I can pretty much state now that I will not be using apply-templates any more! Not unless I know exactly what I'm getting (and that it will never change) - which is pretty much never.
0 Comments:
Post a Comment
<< Home