Search code examples
xmlxsltskos

xslt apply templates with same parent node


I have the following xml:

<root>    
<rdf:RDF 
   ....
   ....>
  <skos:Concept rdf:about="http://aims.fao.org/skosmos/agrovoc/en/page/c_26321">
    <skos:prefLabel xml:lang="fa">آبیس ماریزی‌ای</skos:prefLabel>
    ....
    <skos:prefLabel xml:lang="en">Abies mariesii</skos:prefLabel>
    <skos:broader rdf:resource="http://aims.fao.org/skosmos/agrovoc/en/page/c_10"/>
  </skos:Concept>

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

Please take note that skos:Concept is a parent node of skos:prefLabel with values Abies mariesii and Pinaceae. Abies mariesii in this case is a broader term () while Pinaceae is a narrower term ()

I have the following xslt:

<xsl:template match="root">
  <xsl:for-each select="rdf:RDF">
  <xsl:text>START HERE</xsl:text>
  <xsl:text>&#13;&#10;</xsl:text>
  <xsl:apply-templates select="skos:Concept" />
  <xsl:text>&#13;&#10;</xsl:text>
  </xsl:for-each>
 </xsl:template>

 <xsl:template match="skos:Concept">
   <xsl:if test="skos:broader">
   <xsl:for-each select="skos:prefLabel|skos:Concept" />
   <xsl:text>=301  \\$abroader$b</xsl:text><xsl:value-of select="skos:prefLabel[@xml:lang='en']" /><xsl:text>$c</xsl:text><xsl:value-of select="./@rdf:about" />
   <xsl:text>&#13;&#10;</xsl:text>
   </xsl:if>
 </xsl:template>

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

With this particular template only one is being processed, the latter one. How do I go about this iteration? Of processing both - the broader and the narrower.

Thanks in advance!


Solution

  • It is considered an error to have two templates matching exactly the same node with the same priority. XSLT processors can either flag an error, or ignore all but the last matching template. (See http://www.w3.org/TR/xslt#conflict)

    What you need to do is move the xsl:if test out of the body of the template and make it part of the template match itself.

    <xsl:template match="skos:Concept[skos:broader]">
       ...
    </xsl:template>
    
    <xsl:template match="skos:Concept[skos:narrower]">
       ...
    </xsl:template>
    

    Note that this would still fail if an skos:Concept had both a "broader" and "narrower" element present, as then both templates would match the same node again.

    Alternatively, simply combine the two templates into one using xsl:choose inside whether different processing is required.

    <xsl:template match="skos:Concept">
      <xsl:for-each select="skos:prefLabel|skos:Concept" />
      <xsl:choose>
        <xsl:when test="skos:broader">
           <xsl:text>=301  \\$abroader$b</xsl:text>
        </xsl:when>
        <xsl:when test="skos:narrower">
          <xsl:text>=302  \\$anarrower$b</xsl:text>
        </xsl:when>
      <xsl:value-of select="skos:prefLabel[@xml:lang='en']" />
      <xsl:text>$c</xsl:text>
      <xsl:value-of select="./@rdf:about" />
      <xsl:text>&#13;&#10;</xsl:text>
      </xsl:if>
    </xsl:template> 
    

    Switch to using two xsl:if statements if you could have both an "broader" and "narrower" in one skos:Concept