tags:

views:

160

answers:

1

Hello,

I've read with interest the techniques available on the web to extract a unique list of items from a XML file containing duplicates using XSL.

These range into 2 categories: 1) The Muenchian method (example: http://www.jenitennison.com/xslt/grouping/) 2) Or the previous-sibling look-up These both rely on an XPath expression to select the data to group by.

However, in the XML file that I'm trying to work out, the data is not present "natively" in the XML file. I am using a xsl:template to compute some aggregated data from my elements. And I would like to group based on the aggregated data.

For example I have:

<filmsreview>
    <record><data name='movie'>Star Wars</data><data name='ratings'>John:Good, Mary:Good</data></record>
    <record><data name='movie'>Indiana Jones</data><data name='ratings'>John:Good, Mary:Bad, Helen:Average</data></record>
    <record><data name='movie'>Titanic</data><data name='ratings'>John:Bad, Helen:Good</data></record>
</filmsreview>

I know that the structuration of data is not perfect and that by creating sub-elements I could do something easier, but I cannot change the data source easily, so let's take this as a challenge.

And I would like to build a recap where I have John's distinct ratings: John's ratings: Good Bad

I have a xsl:template that can take a record element and return John's rating for this record: Example:

<xsl:template name="get_rating">
   <xsl:param name="reviewer" />
     <!-- I use some string manipulation, and xsl:value-of to return the review for John-->
</xsl:template>

I can just call it under a xsl:for-each to get the exhaustive list of John's review. But I cannot combine this call with any of the methods to get unique values.

Do I have to use an intermediary XSL to convert my XML file to a more structured way? Or can I do in a single step?

Many thanks Gerard

+1  A: 

Hmm... This should be possible using xslt variables and the nodeset method, perhaps something like this:

<xsl:variable name="_johnsRatings">
   <xsl:apply-templates select="/" mode="johnsRatings" />
</xsl:variable>
<xsl:variable name="johnsRatings" select="msxsl:node-set($_johnsRatings)" />

<xsl:template match="/" mode="johnsRatings">
    <Ratings>
         <xsl:for-each select="/filmsReview/record/data[@name='ratings']">
              <Rating><xsl:call-template name="get_rating" /></Rating>
         </xsl:for-each>
    </Ratings>
</xsl:template>

At this point, it should be possible to query the $johnsRatings variable using standard XPath queries, and you can use either of the two methods you mentioned above to retrieve unique values from it...

Hope that helps

EDIT: I don't know what XSLT engine you are using, I assumed you have access to the msxsl:node-set() function. However, most XSLT processors have similar methods, so you might have to search around for an equivalent method in your processor

LorenVS
Thanks, this answer helped me find the solution.A few things that might complete the answer:The following attribute must be added to the xsl:stylesheet elementxmlns:msxsl="urn:schemas-microsoft-com:xslt"The following key needs to be defined:<xsl:key name="keyratings" match="Rating" use="." />The following loop can be done to the get the unique items:<xsl:for-each select="$ratings/Ratings/Rating[generate-id() = generate-id(key('keyratings', .)[1])]"> <xsl:value-of select="."/></xsl:for-each>
Gerard Yin