0
votes

I haved following input XML:

<library>
<elements>
    <element name="books">
        <property name="author">A</property>
        <property name="select">false</property>
    </element>
    <element name="books">
        <property name="author">B</property>
        <property name="select">false</property>
    </element>  
    <element name="books">
        <property name="author">C</property>
        <property name="select">false</property>
    </element>  
    <element name="books">
        <property name="author">A</property>
        <property name="select">true</property>
    </element>  
</elements>
</library>

I need to get output of all elements with name="books", which are selected (selected = true) and unique by author name. Must use xslt 1.0.

xsl solution:

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

 <xsl:template match="/">           
   <ul> 
     <xsl:for-each select="//elements/element[@name = 'books' and property[@name = 'select' and .='true'] ]/property[@name = 'author' and not(.=preceding::*)]">
      <li>
       <xsl:value-of select="concat('author :',.)"/>
      </li>   
     </xsl:for-each>            
    </ul>
  </xsl:template>
</xsl:stylesheet>

XSLT solution dosn't work. Any suggestions?

I have asked for help in my previous question and proposed answer didn't work in above input xml when only ONE element has select value 'true'

xslt 1.0 - find unique values by several criteria

1
What is the expected output? What exactly do you mean by "selected and unique by author name"? As I understand that, none of the elements in your xml match these criteria: author A is not unique, and authors B and C are not selected, so I would expect an empty output, which is exactly what is delivered by your XSLT.Kim Homann

1 Answers

1
votes

As mentioned in comments, the technique to use here is Muenchian Grouping. It can seem overwhelming at first, but it is a very useful technique to use.

In your case, you want to look-up "selected" books by their author, so you would define a key like so:

<xsl:key name="book" match="element[property[@name='select'] = 'true']" use="property[@name='author']" />

Then, to get the distinct authors, you look at all the element elements, and select the ones that occur first in the key for their given author. The expression to do this is as follows:

<xsl:for-each select="elements/element[generate-id() = generate-id(key('book', property[@name='author'])[1])]">

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html" indent="yes" />

    <xsl:key name="book" match="element[property[@name='select'] = 'true']" use="property[@name='author']" />

    <xsl:template match="library">
      <ul>
        <xsl:for-each select="elements/element[generate-id() = generate-id(key('book', property[@name='author'])[1])]">
            <li><xsl:value-of select="property[@name='author']" /></li>
        </xsl:for-each>
      </ul>
    </xsl:template>
</xsl:stylesheet>