xpath: predicate to choose only elements that match a one of a list of values

P

Phantom

I totally need the help of the XML experts up here, I can't figure this
one out, I've been working on it for hours today, googling my brains
out.

I need to write an xpath query string that returns one or more specific
elements on the fly, in this example, apple and/or orange. *this* works
for JUST apple:

select xpath_eval('//apple',
xtree_doc('<fruit><apple>7</apple><orange>11</orange><banana
/></fruit>'))


BUT, how do I match on not just //apple but also //orange ?? (I have to
accomplish this with an XPATH, not a complex XQUERY 'when' clause
unfortunately.)


I even had it convoluted to this working version:

select xpath_eval('//*[local-name()=("apple")]',
xtree_doc('<fruit><apple>7</apple><orange>7</orange><banana
/></fruit>'))

.... hoping I could then try to add orange with a pipe (|) operator:

local-name()=("apple"|"orange") ... no dice.


Both the source and the match value are coming in at run time, so a
series of OR clauses in the predicate won't work:

noGoExample: [local-name()="apple" or [local-name()="orange"]



I KNOW there's a simple representation for this, but just try looking
for it online when you don't know what you're looking for. like looking
for a word in the dictionary you don't know how to spell.


I thought of using an XML set, something like this:
[local-name() in {"apple|orange"}]

.... but none of the dozen combinations of syntax and quoted variations worked.

I AM LOSING MY MIND!

any help folks? save my mind, thanks!
p.
 
B

Bjoern Hoehrmann

* Phantom wrote in comp.text.xml:
I need to write an xpath query string that returns one or more specific
elements on the fly, in this example, apple and/or orange. *this* works
for JUST apple:

select xpath_eval('//apple',

So use `//apple | //orange`.
Both the source and the match value are coming in at run time, so a
series of OR clauses in the predicate won't work:

noGoExample: [local-name()="apple" or [local-name()="orange"]

Well here you have more [ than ] which usually is a syntax error. Use

//*[local-name() = 'apple' or local-name() = 'orange']
I KNOW there's a simple representation for this, but just try looking
for it online when you don't know what you're looking for. like looking
for a word in the dictionary you don't know how to spell.

http://www.w3.org/TR/xpath has many examples, and contains everything
there is to know about XPath 1.0.
 
P

Phantom

* Phantom wrote in comp.text.xml:

So use `//apple | //orange`.

nope, that only returns the first hit for me (apple).
Both the source and the match value are coming in at run time, so a
series of OR clauses in the predicate won't work:

noGoExample: [local-name()="apple" or [local-name()="orange"]

Well here you have more [ than ] which usually is a syntax error. Use

//*[local-name() = 'apple' or local-name() = 'orange']

I mean, it would function, but I can't go there... there might be 20
fields posted, I need something more straightforward than assembling an
OR predicate each time I call the xpath.
http://www.w3.org/TR/xpath has many examples, and contains everything
there is to know about XPath 1.0.

thanks for the lead, but they don't cover this example, and they don't
provide much in the way of examples.
 
J

Joseph J. Kesselman

Phantom said:
slick 8^) however, won't this also match on crabapple and applebys?

Nope. Note that he's concatenating a few non-name characters (space and
comma) before doing the test.

However, I *really* hate relying on testing localname and losing proper
namespace-awareness. Bad habit to get into.


If you really want to do it via a predicate, I'd suggest
"//*[self::apple or self::eek:range]"
which will walk the tree and return only those nodes which are apple or
orange elements.

However,
"//apple | //orange"
really should work. XPath defines the '|' character as the union
operator. This expression should return every node that is either an
apple or an orange. You say you're only getting the first hit -- but I
think that means either you're misusing your XPath API by failing to
retrieve results after the first, or it's broken and you should consider
switching implementations. (You didn't show us the surrounding code, and
I don't recognize the syntax, so I can't say much beyond that.)
 
N

nick.hanley

However,
        "//apple | //orange"
really should work. XPath defines the '|' character as the union
operator. This expression should return every node that is either an
apple or an orange. You say you're only getting the first hit -- but I
think that means either you're misusing your XPath API by failing to
retrieve results after the first, or it's broken and you should consider
switching implementations. (You didn't show us the surrounding code, and
I don't recognize the syntax, so I can't say much beyond that.)


The problem here is that the xpath_eval statement defaults a third
parameter which indicates that you only want the FIRST node returned.
From the Virtuoso Documentation....


xpath_eval (in xpath_expression varchar, in xml_tree XML Entity, [in
index integer], [in named_params vector]);

Description
This function returns the result of applying the XPath expression to
the context node. By default only the first result is returned, but
supplying a third argument allows you to specify an index for the
value; the default assumes a value of 1 here. A value of 0 returns an
array of 0 or more elements, one for each value selected by the XPath
expression.


Always pays to check the documentation!!


Nick
 

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,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top