tags:

views:

34

answers:

3

XML:

    <mode>
        <submode>1</submode>
        <submode>2</submode>
        <submode>3</submode>
        <submode>4</submode>
        <submode>5</submode>
        <submode>6</submode>
        <submode>7</submode>
    </mode>
    <mode>
        <submode>7</submode>
        <submode>8</submode>
        <submode>9</submode>
        <submode>10</submode>
        <submode>11</submode>
        <submode>12</submode>
        <submode>13</submode>
    </mode>
    <mode>
        <submode>14</submode>
        <submode>15</submode>
        <submode>16</submode>
        <submode>17</submode>
        <submode>18</submode>
        <submode>19</submode>
        20</submode>
    </mode>   

How to test first <submode> from each <mode> (i need get numbers: 1, 7, 14) in such construction:

<xsl:template match="submode">
    <xsl:if test="(parent::mode) and (...what?...)">
        ...
    </xsl:if>
    ...
</xsl:template>

I do not understand how use position() here.

A: 

Your <xsl:template match= should read "mode/submode[1]".

Then you'd have the first submode of every mode.

Jweede
@Jweede, I know, but I can not change the `<xsl:template match="submode">` because there is more code to do that is to be executed in any case, not only for the first node in `submode`.
Kalinin
Then you can add more templates, like what Dimitre recommends.
Jweede
+1  A: 

It is not generally true that

position() = 1

evaluates to true() if the current node has a parent mode and the current node is the first submode child of its parent.

position() specifies the position of the current node-list and this is defined in a different way, depending on how the select attribute of <xsl:apply-templates> is specified.

For example (assuming that the provided XML has a top element that is the parent of the mode elements), if the template was selected when processingthe following:

<xsl:apply-templates select="/*/mode/submode[. = 3]"/>

then

position() = 1

is true only for the 3rd submode child of the first mode element.

One correct answer:

parent::mode and not(preceding-sibling::submode)

Or, recommended:

Have a separate template:

<xsl:template match="mode/submode[1]">

In this case no code within template is necessary to check if the current node is the first submode child -- this is already known to be so.

Dimitre Novatchev
@Dimitre Novatchev, thank you very much, you, as always on top! Now i'll try to understand what you wrote, but the code certainly works (like any code from you). But if i "separate template" as you said i need to copy code for the execution from `<xsl:template match="submode">` to `<xsl:template match="mode/submode[1]">` - i do not want to do it.
Kalinin
+1  A: 

To count the number of submodes in the previous mode if and only if this is the first submode of the current mode, and avoid duplicating code between <xsl:template match="submode"> and <xsl:template match="submode[1]">:

<!-- Special processing for first submode -->
<xsl:template match="submode[1]">
    <xsl:variable name="previousSubmodes" 
                  select="count(../preceding-sibling::mode/submode)"/>

    <!-- ... Do stuff with count ... -->

    <!-- Perform regular submode processing -->
    <xsl:call-template name="submode"/>

</xsl:template>

<!-- Regular processing for submodes -->
<xsl:template match="submode" name="submode">
    <!--  ... Do whatever ... -->
</xsl:template>

Alternatively, you can do the count processing from the template for mode instead. That way, you will not need any special processing for the first submode.

<xsl:template match="mode">
    <!-- ... Other processing ... -->

    <xsl:variable name="previousSubmodes" 
                  select="count(preceding-sibling::mode/submode)"/>

    <!-- ... Do stuff with count ... -->

    <!-- Handle submodes; could use select="node()|@*" instead to process 
         everything, not just submodes  -->
    <xsl:apply-templates select="submode"/>

</xsl:template>

<xsl:template match="submode">
    <!--  ... Do whatever ... -->
</xsl:template>
markusk