0

In postgresql 9.6 the following works:

SELECT xpath(
  'text()', 
  '<hl7_message_host _valuelabel="HL7 host">10.170.117.86</hl7_message_host>');

      xpath     
-----------------
 {10.170.117.86}
(1 row)

But in postgresql 12 it doesn't:

SELECT xpath(
  'text()', 
  '<hl7_message_host _valuelabel="HL7 host">10.170.117.86</hl7_message_host>');

 xpath
-------
 {}
(1 row)

What am I missing or doing wrong?

The example in this post is much simpler than the real queries in the code: in general the xpath() expression is used to extract/convert (unnest() is often involved) name()+text() or name()+some attributes from the second parameter of xpath, and usually the tagname of the second parameter is not known beforehand, so it can't appear in the first parameter. Also, the second parameter can be many levels nested, but only the 1st one is useful.

0

2 Answers 2

1

That is due to a compatibility-breaking fix in v11 (commit e474c2b7e):

  • Correctly handle relative path expressions in xmltable(), xpath(), and other XML-handling functions (Markus Winand)

    Per the SQL standard, relative paths start from the document node of the XML input document, not the root node as these functions previously did.

From v11 on, you have to do it like this:

SELECT xpath(
  'hl7_message_host/text()', 
  '<hl7_message_host _valuelabel="HL7 host">10.170.117.86</hl7_message_host>');

      xpath      
═════════════════
 {10.170.117.86}
(1 row)
Sign up to request clarification or add additional context in comments.

2 Comments

Suppose I do not know the tag of the next level of the XML node and the node is nested several levels (the real case I have): how can i extract the text() of the top node value r from the example below? something like that: SELECT xpath('*/text()', '<root>r<sub1>s1</sub1><sub2>s2</sub2></root>');
Yes, the asterisk is a wildcard.
0

You'll need a // at the beginning to search anywhere in the tree for text nodes, rather than just at the root.

db=# SELECT xpath(
db(#    '//text()',
db(#    '<root>Hello World</root>');
      xpath      
-----------------
 {"Hello World"}
(1 row)

db=# SELECT xpath(
   'text()',
   '<root>Hello World</root>');
 xpath 
-------
 {}
(1 row)

1 Comment

again: I do not want to search everywhere, just in the top level of the xml. the real case in my code is not knowing who the xml is structured, I just need to get the text() of the topmost node: '<root>r<sub1>s1</sub1><sub2>s2</sub2></root>' In the example above I want only r, not {r, s1, s2} and I do not know whether the node is root or anything else. so probably I should change the query to: SELECT xpath('*/text()', '<root>r<sub1>s1</sub1><sub2>s2</sub2></root>'); but it's in lots of places in the code :( The could have added another xpath variant for the new syntax

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.