209

Using a XPath query how do you find if a node (tag) exists at all?

For example if I needed to make sure a website page has the correct basic structure like /html/body and /html/head/title.

Syscall
  • 19,327
  • 10
  • 37
  • 52
EddyR
  • 6,891
  • 7
  • 42
  • 50
  • Maybe it's better to use XML Schema with obligatory elements indication? So check that a document uses it or not. – abatishchev Apr 20 '09 at 11:19

6 Answers6

333
<xsl:if test="xpath-expression">...</xsl:if>

so for example

<xsl:if test="/html/body">body node exists</xsl:if>
<xsl:if test="not(/html/body)">body node missing</xsl:if>
Patrick McDonald
  • 64,141
  • 14
  • 108
  • 120
  • 4
    @SearchForKnowledge, you should probably ask that as a new question at SO, but as a quick guide: `html/body and not(html/body/node())` (i.e., just test if it exists and it does not contain any child nodes, or text nodes). – Abel Sep 06 '15 at 11:30
76

Try the following expression: boolean(path-to-node)

Abel
  • 56,041
  • 24
  • 146
  • 247
annesley
  • 757
  • 5
  • 2
51

Patrick is correct, both in the use of the xsl:if, and in the syntax for checking for the existence of a node. However, as Patrick's response implies, there is no xsl equivalent to if-then-else, so if you are looking for something more like an if-then-else, you're normally better off using xsl:choose and xsl:otherwise. So, Patrick's example syntax will work, but this is an alternative:

<xsl:choose>
 <xsl:when test="/html/body">body node exists</xsl:when>
 <xsl:otherwise>body node missing</xsl:otherwise>
</xsl:choose>
Patrick McDonald
  • 64,141
  • 14
  • 108
  • 120
gkrogers
  • 8,126
  • 3
  • 29
  • 36
  • +1 for noting `if-then-else`, also what about `if-else if-else`? In davenpcj's answer can I place `test="somexpath"` in the 2nd when to make it `if-else if-else`? – AabinGunz Aug 10 '11 at 07:52
  • 4
    @Abhishek Yes, you can put more xsl:when with other conditions and have a multi-branch statement. Think of it more like a SELECT than an if-then-else, with xsl:otherwise as the default:. – davenpcj Dec 16 '11 at 16:06
  • This is awesome but what if I wanted to check if it exists OR empty? – SearchForKnowledge May 14 '15 at 19:07
14

Might be better to use a choice, don't have to type (or possibly mistype) your expressions more than once, and allows you to follow additional different behaviors.

I very often use count(/html/body) = 0, as the specific number of nodes is more interesting than the set. For example... when there is unexpectedly more than 1 node that matches your expression.

<xsl:choose>
    <xsl:when test="/html/body">
         <!-- Found the node(s) -->
    </xsl:when>
    <!-- more xsl:when here, if needed -->
    <xsl:otherwise>
         <!-- No node exists -->
    </xsl:otherwise>
</xsl:choose>
davenpcj
  • 12,508
  • 5
  • 40
  • 37
  • As indicated in the code above, more xsl:when clauses can be added to change the behavior and handle multiple conditions in different ways. – davenpcj Dec 16 '11 at 16:07
  • `count(/html/body) = 0` genius ! :D I use it as `/html[count(/body)=0]/someNode` for selecting `someNode` when `/body` (or whatever) is missing – Stefan Rogin Apr 02 '13 at 10:21
  • 1
    @clickstefan, `/html[count(/body)=0]` will never select anything, there cannot be two root nodes in XML. Maybe you meant `/html[count(body)=0]`, which would be the same as `/html[not(body)]`, or `/html[not(exists(body))]`. – Abel Oct 04 '16 at 00:21
  • @Abel yes, /html[count(//body)=0] or how you said, shameful but yes I didn't give a proper example – Stefan Rogin Oct 05 '16 at 14:36
4

I work in Ruby and using Nokogiri I fetch the element and look to see if the result is nil.

require 'nokogiri'

url = "http://somthing.com/resource"

resp = Nokogiri::XML(open(url))

first_name = resp.xpath("/movies/actors/actor[1]/first-name")

puts "first-name not found" if first_name.nil?
bcolfer
  • 639
  • 1
  • 6
  • 15
3

A variation when using xpath in Java using count():

int numberofbodies = Integer.parseInt((String) xPath.evaluate("count(/html/body)", doc));
if( numberofbodies==0) {
    // body node missing
}
user324898
  • 39
  • 1