Peter
Peter

Reputation: 240

XSL iterate over attribute and ignore some elements

I need to do rather simple thing of iterating over elements in my XML(more explanation under the XML)

<form>
<field index="1" name="field_X_1" group="firstGroup" type="String">
<value>Value of Field X 1 of first group</value>
</field>

<field index="1" name="field_Y_1" group="firstGroup" type="String">
<value>Value of Field Y 1 of first group</value>
</field>

<field index="2" name="field_X_2" group="firstGroup" type="String">
<value>Value of Field X 2 of first group</value>
</field>

<field index="2" name="field_Y_2" group="firstGroup" type="String">
<value>Value of Field Y 2 of first group</value>
</field>

<field index="1" name="field_A_1" group="secondGroup" type="String">
<value>Value of Field A 1 of second group</value>
</field>

<field index="1" name="field_B_1" group="secondGroup" type="String">
<value>Value of Field B 1 of second group</value>
</field>

<field index="2" name="field_A_2" group="secondGroup" type="String">
<value>Value of Field A 2 of second group</value>
</field>

<field index="2" name="field_B_2" group="secondGroup" type="String">
<value>Value of Field B 2 of second group</value>
</field>


</form>

Right now I am iterating over ALL fields of firstGroup and everytime I found that index has changed(by comparing index to index of sibbling) I add new line character). Problem is I need only to iterate over index (but still keep distiction between firstGroup and secondGroup).

My output should look like

Value of Field X 1 of first group, Value of Field Y 1 of first group
Value of Field X 2 of first group, Value of Field Y 2 of first group
Value of Field A 1 of second group, Value of Field B 1 of second group
Value of Field A 2 of second group, Value of Field B 2 of second group
etc

My XSL now looks like

    <xsl:for-each select='/form/field[@group="firstGroup"]'>
                <xsl:sort select="@index" order="ascending"></xsl:sort>     
                <xsl:if test='preceding-sibling::*[@group="firstGroup"][1]/@index != @index and count(preceding-sibling::*) != 0 '>
                    <xsl:text>&#xa;</xsl:text>
                </xsl:if>
                <xsl:value-of select="//field[@name=concat('field_X_', @index,')]/value"/>                              

                <xsl:value-of select="//field[@name=concat('field_Y_', @index,')]/value"/>                              
     </xsl:for-each>    
<!-- Differente iteration for second group-->
<xsl:text>&#xa;</xsl:text>
<xsl:for-each select='/form/field[@group="firstGroup"]'>
                <xsl:sort select="@index" order="ascending"></xsl:sort>     
                <xsl:if test='preceding-sibling::*[@group="firstGroup"][1]/@index != @index and count(preceding-sibling::*) != 0 '>
                    <xsl:text>&#xa;</xsl:text>
                </xsl:if>
                <xsl:value-of select="//field[@name=concat('field_A_', @index,')]/value"/>                              

                <xsl:value-of select="//field[@name=concat('field_B_', @index,')]/value"/>                              
     </xsl:for-each>    

Upvotes: 0

Views: 1713

Answers (1)

Liam Quin
Liam Quin

Reputation: 36

<xsl:output method="text" />

<xsl:template match="form">
    <!--* find all the groups *-->
    <xsl:variable name="groups">
        <xsl:call-template name="get-group-names">
            <xsl:with-param name="nodes" select="field" />
        </xsl:call-template>
    </xsl:variable>

    <xsl:call-template name="process-all-groups">
        <xsl:with-param name="group-names" select="$groups" />
    </xsl:call-template>

</xsl:template>

<xsl:template name="get-group-names">
    <xsl:param name="nodes" />
    <xsl:param name="result-so-far" />

    <xsl:choose>
        <xsl:when test="not($nodes)">
            <xsl:value-of select="$result-so-far" />
        </xsl:when>
        <xsl:when test="contains(
            concat(' ', $result-so-far),
            concat(' ', $nodes[1]/@group, ' '))" >

            <xsl:call-template name="get-group-names">
                <xsl:with-param name="nodes" select="$nodes[position() &gt; 1]" />
                <xsl:with-param name="result-so-far" select="$result-so-far" />
            </xsl:call-template>
        </xsl:when>

        <xsl:otherwise>
            <xsl:call-template name="get-group-names">
                <xsl:with-param name="nodes" select="$nodes[position() &gt; 1]" />
                <xsl:with-param name="result-so-far"
                    select="concat($result-so-far, $nodes[1]/@group, ' ')" />
            </xsl:call-template>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="process-all-groups">
    <xsl:param name="group-names" />

    <xsl:variable name="group" select="substring-before($group-names, ' ')"/>

    <xsl:if test="not(string-length($group) = 0)">
        <xsl:call-template name="index">
            <xsl:with-param name="n" select="1" />
            <xsl:with-param name="group" select="$group" />
        </xsl:call-template>

        <xsl:call-template name="process-all-groups">
            <xsl:with-param name="group-names"
                select="substring-after($group-names, ' ')" />
        </xsl:call-template>

    </xsl:if>
</xsl:template>

<xsl:template name="index">
    <xsl:param name="n" select="1" />
    <xsl:param name="group" />

    <xsl:variable name="with-n"
        select="/form/field[@group = $group][@index = $n]" />

    <xsl:if test="$with-n">

        <xsl:for-each select="$with-n">
            <xsl:sort use="@index" order="ascending" />

            <xsl:value-of select="value" />
            <xsl:if test="not(position() = last())">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
        <xsl:text>&#xa;</xsl:text>

        <xsl:call-template name="index">
            <xsl:with-param name="n" select="$n + 1" />
            <xsl:with-param name="group" select="$group" />
        </xsl:call-template>
    </xsl:if>
</xsl:template>
<xsl:template match="field"></xsl:template>

Upvotes: 2

Related Questions