XPath Q: position of given node in arbitrary nodelist

Angus McIntyre

Usenet Archive
Joined
May 15, 2001
Messages
12
Reaction score
0
Can this be done with XPath?

I have input XML that is basically of the form:

<list>
<item att="a">s1</item>
<item att="a">s2</item>
<item att="b">s3</item>
<item att="c">s4</item>
<item att="c">s5</item>
</list>

I need to produce output of the form:

1. s1, s2
2. s3
3. s4, s5

Another way of looking at this is to say that I need to know the position of a given '<item>' node in the list of item nodes whose attribute 'att' is not the same as that of the preceding node.

(It's a little more complex because I actually need to test two attributes for non-equality with the attributes of the preceding sibling, but that's OK).

Is there a way to either (a) get a count of preceding siblings of the current context node that pass a given test (the test depending on relative properties of the siblings), or (b) to get the position of the current context node in a list of nodes which is _not_ the same as the current context nodelist.

Advice, even of the form "No, it's not possible, give up", would be very welcome.

Thanks

Angus
 

Dimitre Novatchev

Usenet Archive
Joined
Nov 7, 2000
Messages
737
Reaction score
0
This is a grouping problem and a good solution is to use the Muenchian method for grouping like this:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:eek:utput method="text"/>

<xsl:key name="kItemAtt" match="item" use="@att"/>

<xsl:template match="/">
<xsl:for-each
select="/*/item[generate-id
=
generate-id(key('kItemAtt',
@att)[1]
)
]">
<xsl:value-of select="concat(position, '. ')"/>

<xsl:for-each select="key('kItemAtt', @att)">
<xsl:value-of select="."/>
<xsl:if test="not(position = last)">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:for-each>

</xsl:template>
</xsl:stylesheet>

When this transformation is applied on your source.xml:

<list>
<item att="a">s1</item>
<item att="a">s2</item>
<item att="b">s3</item>
<item att="c">s4</item>
<item att="c">s5</item>
</list>

the wanted result is produced:

1. s1, s2
2. s3
3. s4, s5

=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL

Angus McIntyre said:
Can this be done with XPath?

I have input XML that is basically of the form:

<list>
<item att="a">s1</item>
<item att="a">s2</item>
<item att="b">s3</item>
<item att="c">s4</item>
<item att="c">s5</item>
</list>

I need to produce output of the form:

1. s1, s2
2. s3
3. s4, s5

Another way of looking at this is to say that I need to know the position of a given '<item>' node in the list of item nodes whose attribute 'att' is not the same as that of the preceding node.

(It's a little more complex because I actually need to test two attributes for non-equality with the attributes of the preceding sibling, but that's OK).

Is there a way to either (a) get a count of preceding siblings of the current context node that pass a given test (the test depending on relative properties of the siblings), or (b) to get the position of the current context node in a list of nodes which is _not_ the same as the current context nodelist.

Advice, even of the form "No, it's not possible, give up", would be very welcome.

Thanks

Angus
Kadrey]
 

Angus McIntyre

Usenet Archive
Joined
May 15, 2001
Messages
12
Reaction score
0
Dimitre Novatchev said:
This is a grouping problem and a good solution is to use the Muenchian method for grouping like this:

Thank you very much for your solution.

I actually found one of my own, which is less elegant, but which I shall post here anyway just in case it's of use to someone. (Mine generates a few stray commas, which would be easy enough to fix, but would obfuscate the code a little).

<xsl:template match="list">
<xsl:apply-templates select="item[position = 1 or
@att != preceding-sibling::item[1]/@att]"/>
</xsl:template>

<xsl:template match="item">
<xsl:variable name="att"><xsl:value-of select="@att"/></xsl:variable> <p><xsl:value-of select="position"/>. <xsl:value-of select="text"/>, <xsl:for-each select="following-sibling::item[@att = $att]"> <xsl:value-of select="text"/>, </xsl:for-each> </p> </xsl:template>

Thanks again for your help,

Angus
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
548,208
Messages
3,104,802
Members
249,594
Latest member
henrywalsh

Latest Threads

Top