Simon
Simon

Reputation: 1590

XSL group by multiple conditions

I want to group items first by some element value, then to group the results items by other element value with 'or' condition.

I'll try to explain myself with the following XML example

<root>

    <request>
        <id_master>222</id_master>
        <id_x>1</id_x>
        <text>hey</text>
    </request>

    <response>
        <id_master>222</id_master>
        <id_y>1</id_y>
        <text>hello</text>
    </response>

    <request>
        <id_master>222</id_master>
        <id_y>1</id_y>
        <text>bye..</text>
    </request>

    <response>
        <id_master>222</id_master>
        <id_x>1</id_x>
        <text>bye</text>
    </response>

    <request>
        <id_master>222</id_master>
        <id_y>2</id_y>
        <text>I want ice..</text>
    </request>

    <response>
        <id_master>222</id_master>
        <id_x>2</id_x>
        <text>OK</text>
    </response>


    <request>
        <id_master>333</id_master>
        <id_y>5</id_y>
        <text>my name is</text>
    </request>

    <response>
        <id_master>333</id_master>
        <id_x>5</id_x>
        <text>alice</text>
    </response>

    <response>
        <id_master>333</id_master>
        <id_x>5</id_x>
        <text>I'm bob</text>
    </response> 

</root>

Now, In the above XML file I have the following IDS : 1. id_master 2. id_x 3. id_y

First I want to group each block element by id_master. Then to group the results by id_x or id_y, so the output file should be:

<div>
    <h1>Conversation id 222</h1>
    <p>[1] hey</p>
    <p>[1] hello</p>
    <p>[1] bye..</p>
    <p>[1] bye</p>
</div>

<div>
    <h1>Conversation id 222</h1>
    <p>[2] I want ice..</p>
    <p>[2] OK</p>
</div>


<div>
    <h1>Conversation id 333</h1>
    <p>[2] my name is</p>
    <p>[2] alice </p>
    <p>[2] I'm bob </p>
</div>

I succeed to group the first part (group by id_master) I'm getting trouble to group the second part...

Here's what I got so far :

<xsl:key name="key_group_by_master" match="*"  use="id_master" />
<xsl:key name="key_group_by_slave" match="*"  use="id_x or id_y" />

<!-- Group all master elements -->
<xsl:for-each select="//*[generate-id(.)=generate-id(key('key_group_by_master', id_master)[1])]">

    <div>
        <h1> Conversation id <xsl:value-of select="id_master"/> </h1>

        <!-- What I'm doing wrong here ?? Need help ... -->
        <xsl:for-each select="//*[generate-id(.)=generate-id(key('key_group_by_slave', id_x or id_y)[1])]">
            <p> [<xsl:value-of select="id_x or id_y"/>] <xsl:value-of select="text"/> </p>
        </xsl:for-each>
    </div>

</xsl:for-each>

Using the XSLT 1.0

Upvotes: 0

Views: 719

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167401

I would define the first key as

<xsl:key name="key_group_by_master" match="root/*" use="id_master"/>

and the second then needs to concatenate the master key with the slave key e.g.

<xsl:key name="slave" match="root/*" use="concat(id_master, '|', id_x | id_y)"/>

the inner for-each then needs to be

    <xsl:for-each select="//*[generate-id(.)=generate-id(key('slave', concat(id_master, '|', id_x | id_y))[1])]">

That should do as long as the elements only have either id_x or id_y but not both.

Upvotes: 2

Related Questions