xsl-list
[Top] [All Lists]

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

2012-03-01 13:02:25
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>



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--


<Prev in Thread] Current Thread [Next in Thread>