174

Having the following XML:

<node>Text1<subnode/>text2</node>

How do I select either the first or the second text node via XPath?

Something like this:

/node/text()[2]

of course doesn't work because it's the merged result of every text inside the node.

bstpierre
  • 30,042
  • 15
  • 70
  • 103
kernel
  • 3,654
  • 3
  • 25
  • 33
  • 14
    You wrote: *`/node/text()[2]` [...] doesn't work because it's the merged result of every text inside the node* That's wrong: it means *second text node child of `node` root element*. The **string value** (concatenation of descendant text nodes) would be `string(/node)` –  Feb 17 '11 at 20:11
  • You mean that Xpath query should work? Well, I guess I have another problem somewhere else then. ;) Thanks! – kernel Feb 17 '11 at 20:16

2 Answers2

216

Having the following XML:

<node>Text1<subnode/>text2</node> 

How do I select either the first or the second text node via XPath?

Use:

/node/text()

This selects all text-node children of the top element (named "node") of the XML document.

/node/text()[1]

This selects the first text-node child of the top element (named "node") of the XML document.

/node/text()[2]

This selects the second text-node child of the top element (named "node") of the XML document.

/node/text()[someInteger]

This selects the someInteger-th text-node child of the top element (named "node") of the XML document. It is equivalent to the following XPath expression:

/node/text()[position() = someInteger]
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • 1
    Does this work in PHP? I'm trying to loop through only text nodes, even those in-between a set of tags. The problem is that is smashing the content of multiple text nodes together, regardless of tags. Using `//*[text()]` anyway. `/html/text()` does not work. – Aaron Gillion Jun 03 '15 at 20:07
  • 3
    @AaronGillion, Yes, AFAIK PHP has a correctly working XPath 1.0 evaluation. Do note that `/html/text()` doesn't select all text nodes in the document -- only the text nodes that are children (not descendents) of the top, `html` element. You probably want `/html//text()` . Some knowledge and understanding of XPath is typically required in order to construct XPath expressions. – Dimitre Novatchev Jun 03 '15 at 21:51
  • Thanks. I figured out the double-slash trick a little bit ago! – Aaron Gillion Jun 03 '15 at 23:10
  • @AaronGillion, You are welcome. You can learn the basics of XPath 1.0 and 2.0 in module 2 of this online training course: http://www.pluralsight.com/courses/xslt-foundations-part1 – Dimitre Novatchev Jun 04 '15 at 00:52
31

your xpath should work . i have tested your xpath and mine in both MarkLogic and Zorba Xquery/ Xpath implementation.

Both should work.

/node/child::text()[1] - should return Text1
/node/child::text()[2] - should return text2


/node/text()[1] - should return Text1
/node/text()[2] - should return text2
hakre
  • 193,403
  • 52
  • 435
  • 836
kadalamittai
  • 2,076
  • 1
  • 16
  • 19