Xpath query to return "NULL" values?

M

Mario Splivalo

Here is my XML document:

<a>
<b>1</b>
<b>2</b>
<b></b>
<b>3</b>
</a>

When I execute this XPath query against it: /a/b/text()

I get only 1, 2 and 3:

mario@mike:~$ echo "<a><b>1</b><b>2</b><b></b><b>3</b></a>" | xpath -e '/a/b/@id'
Found 3 nodes in stdin:
-- NODE --
1
-- NODE --
2
-- NODE --
3
mario@mike:~$

Is there a way to extract that NULL-valued node?

Mike
 
M

Martin Honnen

Mario said:
Here is my XML document:

<a>
<b>1</b>
<b>2</b>
<b></b>
<b>3</b>
</a>

When I execute this XPath query against it: /a/b/text()

I get only 1, 2 and 3:

mario@mike:~$ echo "<a><b>1</b><b>2</b><b></b><b>3</b></a>" | xpath -e '/a/b/@id'

Why /a/b/@id? There is no 'id' attribute in there at all.

Is there a way to extract that NULL-valued node?

There is an empty 'b' element in there. If you want to select all 'b'
elements then use the XPath
/a/b
if you only want the empty 'b' elements then use
/a/b[not(node())]
 
D

David Carlisle

Mario said:
Here is my XML document:

<a>
<b>1</b>
<b>2</b>
<b></b>
<b>3</b>
</a>

When I execute this XPath query against it: /a/b/text()

I get only 1, 2 and 3:

mario@mike:~$ echo "<a><b>1</b><b>2</b><b></b><b>3</b></a>" | xpath -e '/a/b/@id'
Found 3 nodes in stdin:
-- NODE --
1
-- NODE --
2
-- NODE --
3
mario@mike:~$

Is there a way to extract that NULL-valued node?

Mike

xpath doesn't have a NULL value, and text nodes never have an empty
string as value. the third b has no child node at all.
It's actually rather rare to use text() in xpath, normally you'd just
select the b nodes
the xpath /a/b will select 4 b nodes with string values
"1" "2" "" "3"
In xpath 1 you can only have a node set so teh set of b nodes is the
nearest you can get to this.
In xpath2 you could return the sequence of string values directly as
/a/b/string(.)

David
 
M

Mario Splivalo

Why /a/b/@id? There is no 'id' attribute in there at all.

A typo, I'd say :) This is the correct Xpath query:

.... | xpath -e '/a/b/text()'
There is an empty 'b' element in there. If you want to select all 'b'
elements then use the XPath
/a/b

The 'trouble' is that I get XML portions, and I wanted 'clean' strings. I
guess I could do another XPath query on return values, and then easily see
wich ones are 'empty'.
if you only want the empty 'b' elements then use
/a/b[not(node())]

That does me no good because I need to know on (in?) which position the
empty element is. My actuall XML (shoul've written that in the OP) looks
like this:

<itemList>
<item fieldName="name">Mario</item>
<item fieldName="age">29</item>
<item fieldName="height"></item>
</itemList>

What I'm trying to get is a rowset or table, since I'm doing this from
postgres. So, my table would look like this:

fieldName fieldValue
name Mario
age 29
height NULL

The idea was to have two XPath queries on the original XML. First one
('/itemList/item/@fieldName') would extract all the attributes, and second
one would extract all the 'values' ('/itemList/item/text()'). Now I guess
I'll have to extract the nodes, as you've suggested, and then for each node
chech if it's empty or not.

Mike
 
M

Martin Honnen

Mario said:
<itemList>
<item fieldName="name">Mario</item>
<item fieldName="age">29</item>
<item fieldName="height"></item>
</itemList>

What I'm trying to get is a rowset or table, since I'm doing this from
postgres. So, my table would look like this:

fieldName fieldValue
name Mario
age 29
height NULL

The idea was to have two XPath queries on the original XML. First one
('/itemList/item/@fieldName') would extract all the attributes, and second
one would extract all the 'values' ('/itemList/item/text()'). Now I guess
I'll have to extract the nodes, as you've suggested, and then for each node
chech if it's empty or not.

Are you using XPath inside of XSLT? There is no need to use foo/text()
to get the string value of a 'foo' element, an element does have a
string value of its own for instance with XSLT
<xsl:value-of select="foo"/>
would suffice. If you are using an XPath API then check how it allows
you to extract the string value of a node.
 
M

Mario Splivalo

Are you using XPath inside of XSLT? There is no need to use foo/text()
to get the string value of a 'foo' element, an element does have a
string value of its own for instance with XSLT
<xsl:value-of select="foo"/>
would suffice. If you are using an XPath API then check how it allows
you to extract the string value of a node.

Nope, I'm using it inside postgresql. Postgresql has rudimentary XML support
(http://www.postgresql.org/docs/8.3/interactive/functions-xml.html#FUNCTIONS-XML-PROCESSING)
there is a XPath function which returns onedimensional array of type xml[]
(xml type, in postgres, is varchar/text with added support for xml
validation). Function accept xpath query and xml document, I'm clueless how
to extract string value of a node. It's based on libxml2, so it should be
able to do so, but, I guess i'm stuck:

postgres=# select xpath('/a/b', '<a><b>1</b><b></b></a>');
xpath
-----------------
{<b>1</b>,<b/>}
(1 row)

So, I have an array where each element is XML document. I could run an xpath
query ('/b') on each of those elements and like that find out which ones are
empty.

Mike
 
M

Martin Honnen

Mario said:
Nope, I'm using it inside postgresql. Postgresql has rudimentary XML support
(http://www.postgresql.org/docs/8.3/interactive/functions-xml.html#FUNCTIONS-XML-PROCESSING)
there is a XPath function which returns onedimensional array of type xml[]
(xml type, in postgres, is varchar/text with added support for xml
validation). Function accept xpath query and xml document, I'm clueless how
to extract string value of a node.

I don't know Postgresql at all so I can't help with that. You might want
to check whether there are Postgresql specific forums where you have
better chances of finding others with experience and knowledge of that
particular API.
 
J

Joe Kesselman

Mario said:
<a>
<b>1</b>
<b>2</b>
<b></b>
<b>3</b>
</a>

When I execute this XPath query against it: /a/b/text()
I get only 1, 2 and 3:

That is correct. In the XML data model, an empty element has no children
at all, so /a/b/text() or indeed /a/b/node() will skip over that entirely.

If you want an empty string, you could rewrite this as

/a/b/string(.)

which returns the string value of each <b> element in turn. Since the
string value of an element is the concatenation of its contained text
nodes, this will yield the results you expected.
 
M

Martin Honnen

Joe said:
If you want an empty string, you could rewrite this as

/a/b/string(.)

which returns the string value of each <b> element in turn.


But the above syntax is XPath 2.0 only.
 
J

Joe Kesselman

Martin said:
But the above syntax is XPath 2.0 only.

Sorry; I'm spending too much time moving between 1.0 and 2.0 right now
and got confused.

In that case... The right answer may be to separate this into separate
operations -- issue an XPath to find the b's, then explicitly loop over
those and retrieve/process the node values.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top