Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

selecting one of several elements that differ in attribute

I'm an experienced programmer, but a novice to XSLT and am finding it quite baffling. I apologize if this is a question that's been asked before, but I'm so frustrated by XSLT that I'm not even sure what to search for...

I have a problem that if a certain XML element appears only once, I want its contents output, but if it occurs more than once, I want only the contents of those that have a certain attribute.

For example, suppose I have one XML file (call it "file 1") that contains

<food>
    <snack>Chips</snack>
    <snack type="nuts">Peanuts</snack>
</food>

and another XML file ("file 2") that contains

<food>
    <snack>Cheese puffs</snack>
</food>

I need an XSLT that outputs only "Peanuts" (but not "Chips") upon processing file 1, but still outputs "Cheese puffs" for file 2 (i.e. I can't just select only those elements that have a "type" attribute, that would be too easy).

This is probably simple, but I'm stuck...

like image 289
NumerousHats Avatar asked Nov 13 '22 19:11

NumerousHats


1 Answers

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match=
   "*[snack/@type]/snack[not(@type)]"/>
</xsl:stylesheet>

produces the wanted results in both cases.

Explanation:

  1. The identity rule/template copies every node "as-is".

  2. The second template is overriding the identity template for any snack element without a type attribute that has sibling snack elements that have a type attribute. This template has empty body, which effectively "deletes" the matched element from (being copied to) the output.

like image 144
Dimitre Novatchev Avatar answered Jan 05 '23 18:01

Dimitre Novatchev