views:

145

answers:

1

Hello I am trying to sort my xml by number of occurence of element 'answer' with attribute 'id' and get simply summary.

<person id="1">
 <answer id="A"/>
 <answer id="B"/>
</person>

<person id="2">
 <answer id="A"/>
 <answer id="C"/>
</person>

<person id="3">
 <answer id="C"/>
</person>

I want simply summary text on output:

A = 2 time(s)
C = 2 time(s)
B = 1 time(s)

In XSLT 2.0 i tried:

<xsl:for-each select="distinct-values(/person/answer)">
 <xsl:sort select="count(/person/answer)" data-type="number"/>
 <xsl:value-of select="./@id"/> = 
 <xsl:value-of select="count(/person/answer[@id=./@id])"/> time(s)
</xsl:for-each>

but it is not working:
in XMLSpy 2008:
"Error in XPath 2.0 expression Not a node item"

in Saxon 9:
XPTY0020: Leading '/' cannot select the root node of the tree containing the context item: the context item is an atomic value
Failed to compile stylesheet. 1 error detected.

+1  A: 

I would group and count the items in each group:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">

  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:for-each-group select="//person/answer" group-by="@id">
      <xsl:sort select="count(current-group())" order="descending"/>
      <xsl:value-of select="concat(current-grouping-key(), ' = ', count(current-group()), ' time(s).&#10;')"/>
    </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

That way, when applied to the input

<root>
<person id="1">
 <answer id="A"/>
 <answer id="B"/>
</person>

<person id="2">
 <answer id="A"/>
 <answer id="C"/>
</person>

<person id="3">
 <answer id="C"/>
</person>
</root>

I get the result

A = 2 time(s).
C = 2 time(s).
B = 1 time(s).
Martin Honnen
Thank you very much :)
Tommy