[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

[xsl] is there a more elegant way to change page references?


Subject: [xsl] is there a more elegant way to change page references?
From: Terry Ofner <tdofner@xxxxxxxxx>
Date: Mon, 28 May 2012 11:42:07 -0400

I have an xml document with multiple page references inside <ref> elements. I
have to add 2 to each page reference that follows the text TG:

<ref><b>TG: </b>pp. 19, 20, 21, 29, 32, 40, 43, 44, 46, 56, 57, 58, 60, 61,
66, 67&#8211;68</ref>

As you can see above, the list can contain one or more series, as in 67-68
(with an en-dash).

Here is my series of templates, one that captures the page numbers using
tokenize(); the other that adds 2 to each number and that reassembles the list
of references. The templates work. However, I am wondering if there is a more
direct way to accomplish the same thing. Perhaps using analyze string or some
other approach.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">

    <xsl:output method="xml" indent="yes"></xsl:output>

    <!-- identity template-->

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

    <!--Capture the page numbers as attributes to page element-->
    <!-- and save TGpages varible -->

    <xsl:template match="ref[b/text()='TG: ']">
        <xsl:variable name="TGpages">
            <pages>
            <xsl:for-each select="tokenize(., '\. ')">

            <xsl:if test="position()=1">
                <prefix><xsl:value-of select="."/></prefix>
            </xsl:if>

            <xsl:if test="position()=2">
                <xsl:for-each select="tokenize(.,', ')">
                    <xsl:choose>
                        <xsl:when test="matches(.,'&#8211;')">
                            <page><xsl:for-each
select="tokenize(.,'&#8211;')">
                                <xsl:if test="position()=1">
                                    <xsl:attribute name="firstpage"
select="."/>
                                </xsl:if>
                                <xsl:if test="position()=2">
                                    <xsl:attribute name="lastpage"
select="."/>
                                </xsl:if>
                            </xsl:for-each></page>
                        </xsl:when>
                        <xsl:otherwise>
                            <page>
                        <xsl:attribute name="page">
                            <xsl:value-of select="."/>
                        </xsl:attribute>
                    </page>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each>
            </xsl:if>

            </xsl:for-each></pages></xsl:variable>

        <xsl:apply-templates select="$TGpages"/>

    </xsl:template>

    <!-- Add 2 to each page number and  put it all -->
    <!-- back together again. -->

    <xsl:template match="pages">
        <xsl:variable name="numPage" select="count(page)"/>
        <ref>
            <xsl:choose>
                <xsl:when test="$numPage > 1">
                   <b>TG: </b><xsl:text>pp. </xsl:text>
                </xsl:when>
                <xsl:when test="$numPage = 1 and .[@firstpage|@lastpage]">
                    <b>TG: </b> <xsl:text>pp. </xsl:text>
                </xsl:when>
                <xsl:otherwise>
                    <b>TG: </b><xsl:text>p. </xsl:text>
                </xsl:otherwise>
            </xsl:choose>

         <!-- put comma back in -->
            <xsl:for-each select="page">
                <xsl:if test="position()>1">
                    <xsl:text>, </xsl:text>
                    <xsl:apply-templates/>
                </xsl:if>
                <xsl:if test="position()=1">
                    <xsl:apply-templates/>
                </xsl:if>

          <!-- add 2 to each attribute -->
               <xsl:for-each select="@firstpage">
                <xsl:value-of select=".+2"/><xsl:text>&#8211;</xsl:text>
            </xsl:for-each>

            <xsl:for-each select="@lastpage">
                <xsl:value-of select=".+2"/>
            </xsl:for-each>

            <xsl:for-each select="@page">
                <xsl:value-of select=".+2"/>
            </xsl:for-each>
            </xsl:for-each>
        </ref>
    </xsl:template>
</xsl:stylesheet>


Current Thread
Keywords
xml