xsl-list
[Top] [All Lists]

Re: [xsl] how do you count based on the number of preceding attributes?

2008-06-06 19:08:03
Dear Dr. Kay and Readers,
Implementing the changes suggested below as follows, on this markup:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <div0 type="heading" id="abc.div.1.2.3">
        <div1/><div1 type="article" id="abc.div.1.2.6">
            <div2 type="subsection" id="abc.div.1.2.1"/>
            <pb n="1" id="abc.1.2.2"/>
        </div1>
    </div0>
</root>

With the sylesheet now reading:

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

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

    <xsl:template match="@id[contains(.,'div')]">
        <xsl:variable name="test_value"
select="string(count(preceding::*[contains(@id, 'div')]))"/>
        <xsl:attribute name="id"  select="replace(., '[0-9]+$', $test_value)"/>
    </xsl:template>

</xsl:stylesheet>

I get the output:

<?xml version="1.0" encoding="UTF-8"?><root>
    <div0 type="heading" id="abc.div.1.2.0">
        <div1/><div1 type="article" id="abc.div.1.2.0">
            <div2 type="subsection" id="abc.div.1.2.0"/>
            <pb n="1" id="abc.1.2.2"/>
        </div1>
    </div0>
</root>

The output I want is:
<?xml version="1.0" encoding="UTF-8"?><root>
    <div0 type="heading" id="abc.div.1.2.1">
        <div1/><div1 type="article" id="abc.div.1.2.2">
            <div2 type="subsection" id="abc.div.1.2.3"/>
            <pb n="1" id="abc.1.2.2"/>
        </div1>
    </div0>
</root>

Any further suggestions?  (If it helps to hear: the test case
represents a file where the last integers in the div @id attributes
are misnumbered, and the goal of the stylesheet is to number them
sequentially...the pb element has an @id attribute, but it's not my
concern here...).
Thanks for your help and patience with my slow learning process,
Tony Zanella




On Fri, Jun 6, 2008 at 4:47 PM, Michael Kay <mike(_at_)saxonica(_dot_)com> 
wrote:
Using xsl processor: Saxon 8B, here's my test data:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <div0 type="heading" id="abc.div.1.2.3">
        <div1 type="article" id="abc.div.1.2.6">
            <div2 type="subsection" id="abc.div.1.2.1"/>
            <pb n="1" id="abc.1.2.2"/>
            <div2 type="subsection" id="abc.div.1.2.64"/>
        </div1>
    </div0>
</root>

Here's the stylesheet I'm working on:

[identity template]+

    <xsl:template match="*/@id[contains(.,'div')]">

The "*/" adds nothing (well, it says "only match id attributes if they have
an element as a parent"). You can drop it.

        <xsl:variable name="substring"
select="substring-after(substring-after(substring-after(substr
ing-after(.,'.'),'.'),'.'),'.')"/>

You don't seem to use this variable and I don't think you need it.

        <xsl:variable name="test_value"><xsl:value-of
select="count(preceding::node())"/></xsl:variable>

NEVER write variables like this. It should be

<xsl:variable name="test_value" select="string(count(preceding::node()))"/>

You don't want a document node containing a text node; you want the integer,
converted to a string.

I want the value of $test_value to be, for example, 1 if the @id
containing the string 'div' is the first @id, 2 if it is the second, and so
on.

You haven't made it clear whether you want to count all @id attributes, or
only those that contain 'div'. In the first case it's
count(preceding::*[(_at_)id]), in the second it's
count(preceding::*[contains(@id, 'div')]).

Alternatively, use <xsl:number level="any" count="*[(_at_)id]"/>

        <xsl:attribute name="id"
select="concat(replace(.,'([a-z]{3})\.div\.([0-9]+)\.([0-9]+)\
.([0-9]+)','$1.div.$2.$3.'),$test_value)"/>

The seems very cumbersome. To replace the last number in the string, use

replace(., '[0-9]+$', $test_value)

Michael Kay
http://www.saxonica.com/



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--