user3872094
user3872094

Reputation: 3351

applying templates of same type but working on different type of declaration

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.

  1. If 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).
  2. If there is text and in between text there is 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

Answers (1)

Tim C
Tim C

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

Related Questions