xslt get only one value from duplicates in keys and output as another value

945 Views Asked by At

I have been working on the following xml:

<?xml version="1.0" encoding="utf-8" ?>
 <root>
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
     .....
     xmlns:dc="http://purl.org/dc/terms/">

  <skos:Concept rdf:about="http://aims.fao.org/aos/agrovoc/c_26321">
     .....
   <skos:prefLabel xml:lang="en">Abies mariesii</skos:prefLabel>
   <skos:broader rdf:resource="http://aims.fao.org/aos/agrovoc/c_10"/>
  </skos:Concept>

  <skos:Concept rdf:about="http://aims.fao.org/aos/agrovoc/c_33272">
     .....
   <skos:prefLabel xml:lang="en">Abies numidica</skos:prefLabel>
   <skos:broader rdf:resource="http://aims.fao.org/aos/agrovoc/c_10"/>
  </skos:Concept>

     .....

  <skos:Concept rdf:about="http://aims.fao.org/aos/agrovoc/c_5886">
     .....
   <skos:prefLabel xml:lang="en">Pinaceae</skos:prefLabel>
     .....
   <skos:narrower rdf:resource="http://aims.fao.org/aos/agrovoc/c_10"/>        
  </skos:Concept>

  <skos:Concept>
   <skos:narrower rdf:resource="http://aims.fao.org/skosmos/agrovoc/en/page/c_1322232213779"/>
   <skos:narrower rdf:resource="http://aims.fao.org/skosmos/agrovoc/en/page/c_19"/>
     .....
   <skos:prefLabel xml:lang="en">Abies</skos:prefLabel>
     .....
   <skos:closeMatch>

     .....

 </rdf:RDF>

The whole xml can be accessed here: http://128.199.159.143/merged-file.xml

And I have the following XSLTs (based from xslt get element value based on attribute which is referenced in another node tree) here:

<?xml version="1.0" encoding="UTF-8"?>
 <xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   .....
 xmlns:void="http://rdfs.org/ns/void#">
 <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
 <xsl:key name="concepts-by-about" match="//skos:Concept" use="@rdf:about" />

  <xsl:template match="root">
   <xsl:for-each select="rdf:RDF">
   <xsl:text>START HERE</xsl:text>
   <xsl:text>&#13;&#10;</xsl:text>
   <xsl:text>=LDR  00000nam  2200000Ia 4500</xsl:text>
   <xsl:text>&#13;&#10;</xsl:text>
   <xsl:apply-templates select="skos:Concept/skos:broader" />
   <xsl:text>&#13;&#10;</xsl:text>
   <xsl:apply-templates select="skos:Concept/skos:narrower" />
   <xsl:text>&#13;&#10;</xsl:text>
   </xsl:for-each>
  </xsl:template>

  <xsl:template match="//skos:broader[key('concepts-by-about', @rdf:resource)]">       
   <xsl:text>=301  \\$abroader$b</xsl:text><xsl:value-of select="key('concepts-by-about', @rdf:resource)/skos:prefLabel[@xml:lang='en']" />
   <xsl:text>$c</xsl:text>
   <xsl:value-of select="./@rdf:resource" />
   <xsl:text>&#13;&#10;</xsl:text>   
  </xsl:template>           

  <xsl:template match="text()" />

  <xsl:template match="//skos:narrower[key('concepts-by-about', @rdf:resource)]">       
   <xsl:text>=302  \\$anarrower$b</xsl:text><xsl:value-of select="key('concepts-by-about', @rdf:resource)/skos:prefLabel[@xml:lang='en']" />
   <xsl:text>$c</xsl:text>
   <xsl:value-of select="./@rdf:resource" />
   <xsl:text>&#13;&#10;</xsl:text>   
  </xsl:template>           

  <xsl:template match="text()" />

  <xsl:template match="skos:Concept/skos:narrower/skos:Concept/skos:prefLabel[@xml:lang='en']">
   <xsl:text>=302  \\$anarrower$b</xsl:text><xsl:value-of select="." />
   <xsl:text>$c</xsl:text>
   <xsl:value-of select="../@rdf:about" />
   <xsl:text>&#13;&#10;</xsl:text>
  </xsl:template>

 </xsl:stylesheet>

With this xslt, I am getting the following:

START HERE
=LDR  00000nam  2200000Ia 4500
=301  \\$abroader$bAbies$chttp://aims.fao.org/aos/agrovoc/c_10
=301  \\$abroader$bAbies$chttp://aims.fao.org/aos/agrovoc/c_10
  (more =301  \\$abroader$bAbies$chttp://aims.fao.org/aos/agrovoc/c_10) ...
=301  \\$abroader$bPinaceae$chttp://aims.fao.org/aos/agrovoc/c_5886

which is fine for me because, it is what I wanted with the xml, based from http://aims.fao.org/skosmos/agrovoc/en/page/c_10 which Pinaceae is a broader concept. However, 'Abies' is repeated several times, so how do I remove these duplicates and print it as another value:

=400  \\$apreferredterm$bAbies$chttp://aims.fao.org/aos/agrovoc/c_10
1

There are 1 best solutions below

3
On

I had a look at your referenced stylesheet and there's this line:

<xsl:template match="//skos:broader[key('concepts-by-about', @rdf:resource)]">

Since keys are global, and there is at least one matching node to the key, the construct [key(...)] will always be true (in a predicate, if it matches a node, it counts as "true"). You can see this for yourself if you try the following at any level:

<xsl:value-of select="count(//skos:broader[key('concepts-by-about', @rdf:resource)])" />

It will show you that there are 51 nodes matching. Probably not your intent.

It seems to me that you actually want to match skos:broader elements that have a parent (or an ancestor) that matches the @rdf-resource attribute of the current node with the @rdf:about attribute of skos:Concept. You can do that as follows:

<xsl:template
    match="skos:broader[@rdf:resource = ancestor::skos:Concept/@rdf:about]">

After I change this there is only one of the following in the output:

=301  \\$abroader$bAbies$chttp://aims.fao.org/aos/agrovoc/c_10

Then, inside that template, you do:

<xsl:value-of
    select="key('concepts-by-about', @rdf:resource)/skos:prefLabel[@xml:lang = 'en']" />

This will return the first global value matched by the key. Again, it appears to me that you actually want the ancestor skos:Concept here, but I'm guessing. If so, it should be (ignoring the match on @rdf:about, because we already know it is a match):

<xsl:value-of select="ancestor::skos:Concept/skos:prefLabel[@xml:lang = 'en']" />

Furthermore, there are a few occasions where you have a match pattern that starts with //, this has no effect. It means "starting from the root, any node, at any level, that matches what follows". But a pattern is already global anyway, so it has no effect, except that you ask the processor to do an expensive lookup each time it encounters that pattern. This is true for the key and for some matching templates.

I think that your use of the key-function is not necessary for what you are trying to accomplish, but I have to admit that I do not fully understand the width of your requirements.