tags:

views:

39

answers:

2

I have an XML list of "devices".

<devices>
  <device>NOKIA-43</device>
  <device>HTC-7</device>
  <device>SAMSUNG-376</device>
<devices>

Using XSLT, I want to retrieve the first "HTC*" device if there is one, or the first device if there are no HTC devices.

What XSLT code would do this?
Thank you!

+1  A: 

Here's one possibility (tested with Oxygen/XML):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:template match="//devices">
        <xsl:choose>
            <xsl:when test="device[starts-with(text(),'HTC')]">
                <xsl:apply-templates select="device[starts-with(text(),'HTC')][position()=1]"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="device[position()=1]"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template match="device">
        <xsl:value-of select="text()"/>
    </xsl:template>
</xsl:stylesheet>
Jim Garrison
Thanks for pointing me in the direction! But with this code, if there are several HTC devices, they are all returned, instead of just the first one, right?
Nicolas Raoul
OK, just adding [position()=1] at the end of the first apply-templates apparently did the trick. Could you please update your answer so that I can accept it?
Nicolas Raoul
I've added the predicate
Jim Garrison
+2  A: 

Use this XPath one-liner:

  /*/device[starts-with(., 'HTC')][1] 
| 
  /*/device[1][not(/*/device[starts-with(., 'HTC')])]

Generally, to select node $n1 when some $condition is true() and to select node $n2 when this condition is false():

   $n1[$condition] | $n2[not($condition)]

Explanation:

The above expression is the union (|) of two sub-expressions of which only one selects a node, depending on the value of the specific $condition.

Finally, in XSLT one will use this XPath expression like this:

  <xsl:apply-templates select=
   "  /*/device[starts-with(., 'HTC')][1] 
    | 
      /*/device[1][not(/*/device[starts-with(., 'HTC')])]
   "/>
Dimitre Novatchev
@Dimitre: +1 Excellent, and with explanation!
Alejandro