Reputation: 77
In my xsl there are already templates defined for elements like para, graphic etc. Example below:
<xsl:template match="para">
<fo:block>
<xsl:apply-templates />
</fo:block>
</xsl:template>
But I want to add an extra node at the innermost level in case of a particular attribute value. For example, if the element has the attribute value of changeStatus = new/changed, I need to add 'fo:change-bar-begin' element inside the other nodes. Example xml:
<para changeStatus="new">
This is a paragraph that has change bars applied to the whole paragraph. </para>
The output should be(here fo:block node is coming from the other templates in the xsl):
<fo:block>
<fo:change-bar-begin change-bar-style="solid"/>
This is a paragraph that has change bars applied to the whole paragraph.
<fo:change-bar-end/>
</fo:block>
I am using this code but it for some cases, it is adding the node at outer level, while in other cases it is removing the nodes(e.g. fo:block) defined in other templates.
<xsl:template match="*[@changeStatus='new' or @changeStatus='changed']">
<fo:change-bar-begin change-bar-style="solid"/>
<xsl:apply-templates select="node() | @*" />
<fo:change-bar-end/>
</xsl:template>
Here, para is just an example and I need this code to work for many elements, so using call-template is not an option. Please suggest the best way to do it.
Upvotes: 0
Views: 47
Reputation: 180276
Each time a node is selected for transformation, exactly one template is matched to it and applied, except inasmuch as that selected template may direct that others be applied to the same node. Thus, if you add a template that matches nodes that already have matching templates then you get the effect of one template or the other, not a combination of both.
Now, if you had wanted to put your change-bar
around the outermost elements generated by your existing templates then that would be one thing, but putting the change-bar
inside them is going to require either modifying or cloning all the existing templates that need such treatment. I highly recommend the "modifying" alternative, as maintaining it will be a lot easier.
For example, take your template matching para
elements. You might modify it like so:
<xsl:template match="para">
<fo:block>
<xsl:apply-templates select="." mode="cb-begin-choice"/>
<xsl:apply-templates />
<xsl:apply-templates select="." mode="cb-end-choice"/>
</fo:block>
</xsl:template>
You would support that, for all templates, with something like this:
<xsl:template match="*" mode="cb-begin-choice">
<xsl:if test="@changeStatus='new' or @changeStatus='changed'">
<fo:change-bar-begin change-bar-style="solid"/>
</xsl:if>
</xsl:template>
<xsl:template match="*" mode="cb-end-choice">
<xsl:if test="@changeStatus='new' or @changeStatus='changed'">
<fo:change-bar-end/>
</xsl:if>
</xsl:template>
Pulling out the change-bar details to those two additional templates makes putting in these changes easier, and leaves the modified templates clearer. It also gives you one place to control the change-bar details, so that if ever you want to change them, you can do it in just those two templates.
If you prefer, you can implement the same thing on top of named templates and xsl:call-template
instead of modes and xsl:apply-templates
.
Upvotes: 2