sanjay
sanjay

Reputation: 1020

XSLT - <xsl:number> element skip certain nodes

I have a xsl like follows,

<doc>
    <sec>
        <para>para</para>
        <para>para</para>
        <para>§ 9.02A spara</para>
        <para>para</para>
        <para>para</para>
    </sec>
    <sec>
        <para>para</para>
        <para>para</para>
        <para>para</para>
        <para>para</para>
        <para>para</para>
    </sec>
    <sec>
        <para>para</para>
        <para>para</para>
        <para>para</para>
        <para>para</para>
        <para>para</para>
    </sec>
</doc>

I need to add a attribute name type to <para> element by analyzing text() node of the <para> element.

if text() node starting with '§ 9.02A' the type attribute should be 'xxx' otherwise the type attribute should be sequential number value starting from number 1 for each level, so expected output should be,

<doc>
    <sec>
        <para type="1">para</para>
        <para type="2">para</para>
        <para type="XXX">§ 9.02A spara</para>
        <para type="3">para</para>
        <para type="4">para</para>
    </sec>
    <sec>
        <para type="1">para</para>
        <para type="2">para</para>
        <para type="3">para</para>
        <para type="4">para</para>
        <para type="5">para</para>
    </sec>
    <sec>
        <para type="1">para</para>
        <para type="2">para</para>
        <para type="3">para</para>
        <para type="4">para</para>
        <para type="5">para</para>
    </sec>
</doc>

I have written xsl for do this as follows,

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

    <xsl:template match="para">
        <xsl:variable name="position" as="xs:string">
            <xsl:number count="para" level="single" select=". except para[matches(.,'§\s\d+\.\d+[A-Z]')]"/>
        </xsl:variable>

        <para>
            <xsl:if test="matches(.,'§\s\d+\.\d+[A-Z]')">
                <xsl:attribute name="type">
                    <xsl:value-of select="'XXX'"/>
                </xsl:attribute>
                <xsl:apply-templates/>
            </xsl:if>
            <xsl:if test="not(matches(.,'§\s\d+\.\d+[A-Z]'))">
                <xsl:attribute name="type">
                    <xsl:value-of select="$position"/>
                </xsl:attribute>
                <xsl:apply-templates/>
            </xsl:if>

        </para>
    </xsl:template>

problem here is, when the text() is starting from '§ 9.02A' the attribute is not skiping that level, (see the level one <para> of generated output.. current values are 1,2,XXX,4,5. it should be 1,2,XXX,3,4)

current output,

<doc>
    <sec>
        <para type="1">para</para>
        <para type="2">para</para>
        <para type="XXX">§ 9.02A spara</para>
        <para type="4">para</para>
        <para type="5">para</para>
    </sec>
    <sec>
        <para type="1">para</para>
        <para type="2">para</para>
        <para type="3">para</para>
        <para type="4">para</para>
        <para type="5">para</para>
    </sec>
    <sec>
        <para type="1">para</para>
        <para type="2">para</para>
        <para type="3">para</para>
        <para type="4">para</para>
        <para type="5">para</para>
    </sec>
</doc>

this can be done by using other method like count() function, but I really needed to do this in this way. can any one suggest me a method how can I do modified to get the correct output?

Upvotes: 1

Views: 415

Answers (1)

Joel M. Lamsen
Joel M. Lamsen

Reputation: 7173

change

<xsl:number count="para" level="single" select=". except para[matches(.,'§\s\d+\.\d+[A-Z]')]"/>

to

<xsl:number count="para[not(matches(.,'§\s\d+\.\d+[A-Z]+'))]" level="single"/>

Upvotes: 3

Related Questions