Re: [xsl] Finding triples with same/distinct attribute value

Subject: Re: [xsl] Finding triples with same/distinct attribute value
From: Michael Müller-Hillebrand <mmh@xxxxxxxxxxxxx>
Date: Thu, 1 Mar 2012 20:02:08 +0100
Am 29.02.2012 um 22:27 schrieb Michael Kay:

>> There is a number of elements with an attribute. The task is to find every
triple of elements with the same attribute value or with distinct attribute
values. I solved it using xsl:for-each loops but feel like having missed some
XPath 2 features. I am looking forward to your comments.
> I think you need to state the requirement more clearly. Reverse-engineering
it from your code isn't that easy. Is your definition of a "triple" this: "a
sequence of three distinct <pot> elements, not necessarily adjacent, but in
document order"?

Michael Kay,

Thanks for reminding me how important precision is when dealing with logic.

A triple is a sequence of any three distinct <pot> elements. The result does
not have to be in document order. But because the nodes have no id, my
stylesheet reports their position in the parent element (using a complicated
method instead of position() which features the cool >> operator).

- Michael M|ller-Hillebrand

>> PS: I get a result of 60 triples with the sample file.
>>
>> Input:
>>
>> <pots>
>>  <pot a="3" />
>>  <pot a="3" />
>>  <pot a="3" />
>>  <pot a="1" />
>>  <pot a="1" />
>>  <pot a="1" />
>>  <pot a="1" />
>>  <pot a="1" />
>>  <pot a="1" />
>>  <pot a="3" />
>>  <pot a="2" />
>>  <pot a="3" />
>> </pots>
>>
>> XSL:
>>
>> <?xml version="1.0" encoding="UTF-8"?>
>> <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="2.0"
>>  xmlns:xs="http://www.w3.org/2001/XMLSchema";
>>  xmlns:my="http://my";
>>  exclude-result-prefixes="xs my"
>>  >
>>  <xsl:output indent="yes"/>
>>
>>  <xsl:template match="pots">
>>   <result>
>>    <xsl:sequence select="my:triples(*)" />
>>   </result>
>>  </xsl:template>
>>
>>  <xsl:function name="my:triples" as="node()*">
>>   <xsl:param name="nodes" as="node()+"/>
>>
>>   <!-- common values -->
>>   <xsl:for-each select="$nodes">
>>    <xsl:variable name="t1" select="."/>
>>    <xsl:for-each select="$t1/following-sibling::*[@a eq $t1/@a]">
>>     <xsl:variable name="t2" select="."/>
>>     <xsl:for-each select="$t2/following-sibling::*[@a eq $t1/@a]">
>>      <triple>
>>       <xsl:value-of select="string-join((my:pos($nodes, $t1),
my:pos($nodes, $t2), my:pos($nodes, .)), ' ')" />
>>      </triple>
>>     </xsl:for-each>
>>    </xsl:for-each>
>>   </xsl:for-each>
>>
>>   <!-- distinct values -->
>>   <xsl:for-each select="$nodes">
>>    <xsl:variable name="t1" select="."/>
>>    <xsl:for-each select="$t1/following-sibling::*[@a ne $t1/@a]">
>>     <xsl:variable name="t2" select="."/>
>>     <xsl:for-each select="$t2/following-sibling::*[@a ne $t1/@a and @a ne
$t2/@a]">
>>      <triple>
>>       <xsl:value-of select="string-join((my:pos($nodes, $t1),
my:pos($nodes, $t2), my:pos($nodes, .)), ' ')" />
>>      </triple>
>>     </xsl:for-each>
>>    </xsl:for-each>
>>   </xsl:for-each>
>>
>>  </xsl:function>
>>
>>  <xsl:function name="my:pos" as="xs:string">
>>   <xsl:param name="nodes" as="node()+"/>
>>   <xsl:param name="node" as="node()"/>
>>   <xsl:value-of select="count($nodes[$node>>  .]) + 1" />
>>  </xsl:function>
>>
>> </xsl:transform>

Current Thread