Reputation: 3351
I've below XMLs.
<emphasis type="italic">
varying from ti,e to time<star.page>58</star.page>Starch
</emphasis>
and
<para indent="no">
<star.page>18</star.page> Further to same.
</para>
here i'm trying to apply-templates
on the star.page
, but the confusion is if i take <xsl:apply-templates select="./*[1][self::star.page]" mode="first"/>
, it is working fine for the first case, but for the second case, the star.page
is getting duplicated, if i use <xsl:apply-templates select="./node()[1][self::star.page]" mode="first"/>
, in case 2
the star.page that is supposed to appear before div
is coming inside div
and for case 1
, the value is getting duplicated.
Here are the DEmos
Case1-enter link description here Case2- enter link description here
Expected output are as below.
Case 1:
<span class="font-style-italic">
varying from ti,e to time<?pb label='58'?><a name="pg_58"></a></span>2<span class="font-style-italic">Starch
</span>
Case 2:
<?pb label='18'?><a name="pg_18"></a>
<div class="para">
Further to same.
</div>
Here the condition is as below.
star.page
is immediate child of parent node(though it is para
or emphasis
), the pb label
has to be created first followed by the tag(Case 2 output).star.page
, then the content should come with pb label inside it.(Case 1 output).please let me know a common solution on how i can fix theses issues.
Upvotes: 0
Views: 46
Reputation: 70648
I am not clear what the bulk of your XSLT is doing, but I would first make use of a named template to avoid repeated code. There is no issue with giving a matched template a name too.
<xsl:template match="star.page" name="page">
<xsl:processing-instruction name="pb">
<xsl:text>label='</xsl:text>
<xsl:value-of select="."/>
<xsl:text>'</xsl:text>
<xsl:text>?</xsl:text>
</xsl:processing-instruction>
<a name="{concat('pg_',.)}"/>
</xsl:template>
Then the template with the mode "first" becomes this
<xsl:template match="star.page" mode="first">
<xsl:call-template name="page" />
</xsl:template>
You can still call this in the same way, or maybe a slightly different condition will also work
<xsl:apply-templates select="star.page[not(preceding-sibling::node())]" mode="first"/>
Then, all you need is a template to ignore "star.page" that are the first child (because they have already been explicitly selected)
<xsl:template match="star.page[not(preceding-sibling::node())]" />
As a simplified example, try this for starers
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="para|emphasis">
<xsl:apply-templates select="star.page[not(preceding-sibling::node())]" mode="first"/>
<div>
<xsl:choose>
<xsl:when test="./@align">
<xsl:attribute name="class"><xsl:text>para align-</xsl:text><xsl:value-of select="./@align"/></xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="class"><xsl:text>para</xsl:text></xsl:attribute>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="star.page[not(preceding-sibling::node())]" />
<xsl:template match="star.page" name="page">
<xsl:processing-instruction name="pb">
<xsl:text>label='</xsl:text>
<xsl:value-of select="."/>
<xsl:text>'</xsl:text>
<xsl:text>?</xsl:text>
</xsl:processing-instruction>
<a name="{concat('pg_',.)}"/>
</xsl:template>
<xsl:template match="star.page" mode="first">
<xsl:call-template name="page" />
</xsl:template>
</xsl:stylesheet>
Do note the use of strip-space
here because strictly speaking, the star.page
is not the first node in each example, there is a white-space node before it.
When applied to this XML
<root>
<emphasis type="italic">
varying from ti,e to time<star.page>58</star.page>Starch
</emphasis>
<para indent="no">
<star.page>18</star.page> Further to same.
</para>
</root>
The following is output
<div class="para">
varying from time to time<?pb label='58'??><a name="pg_58"/>Starch
</div>
<?pb label='18'??>
<a name="pg_18"/>
<div class="para"> Further to same.
</div>
Upvotes: 1