help with xpath request

M

Mat|

Hello :)

I am learning XPath, and I am trying to get child nodes
of a node whose names do *not* match a given string,
e.g :

<dummy>
<example>
<title>Example 1</title>
<body>this is an example</body>
<picture>a reference to a picture</picture>
</example>
</dummy>

I want to get "body" and "picture" child nodes of the
"example" node. I thought that this request could do
the trick but it is not working :

/dummy/example/*[name()!="title"]

Can someone help me, please ?

Thanks in advance!!!
 
P

p.lepin

Mat| said:
I am learning XPath, and I am trying to get child nodes
of a node whose names do *not* match a given string,
e.g :

<dummy>
<example>
<title>Example 1</title>
<body>this is an example</body>
<picture>a reference to a picture</picture>
</example>
</dummy>

I want to get "body" and "picture" child nodes of the
"example" node. I thought that this request could do
the trick but it is not working :

Precisely how it's not working? What's your XPath
environment? (XSLT processor? If yes, which one of them?
XPath-capable DOM API implementation? If yes, which one of
them? Some sort of XPath-capable XML editor? If yes, which
one of them? If it's XMLSpy, well, I've never used XMLSpy
myself, but every time someone comes to the group saying
'Hey! This doesn't work for me in XMLSpy!', regulars answer
that XMLSpy is broken then. I've seen this happen often
enough that I mentally filed XMLSpy away under the 'Don't
use unless your bloody life depends on it' category.)
/dummy/example/*[name()!="title"]

Given your sample XML, this sure works for me using both
xsltproc and saxon8. A few thoughts:

1. Perhaps you've got an xmlns problem. Try using
local-name():

/dummy/example/*[local-name()!="title"]

(Obviously, this does not apply if you're not using XML
Namespaces.)

2. The above solution is a bit kludgy, consider using
something like:

(/dummy/example/body|/dummy/example/picture)

Or:

(/dummy/example/NS:body|/dummy/example/NS:picture)

Where NS: is the XML Namespace your elements are in. Again,
this won't solve your problem unless there's something
wrong with namespaces.

3. In case the node order in the document matters (and you
have either knowledge or control of precisely how it does
matter) you can use something like:

/dummy/example/*[position() &gt; 1]

Or:

/dummy/example/*[preceding-sibling::title]

A bit inelegant, though.

4. If you're using XSLT, consider matching everything:

/dummy/example/*

....and controlling the result using templates (untested):

<xsl:template match="title"/>
<xsl:template match="body|picture">
<xsl:copy-of select="."/>
</xsl:template>

Hope that helps.
 
S

spiff

Hi!

the above XPath /dummy/example/*[name()!="title"] works perfectly in
XMLSpy. As a result it gives the <body> and <picture> elements.

I think your suggestions starting from 2. to 4. are a bit strange. They
all require information about the other elements, their order or their
names. The original XPath clearly just needs the "title" name as
information and does what it should.

Regards
spiff


http://www.spycomponents.com

Mat| said:
I am learning XPath, and I am trying to get child nodes
of a node whose names do *not* match a given string,
e.g :

<dummy>
<example>
<title>Example 1</title>
<body>this is an example</body>
<picture>a reference to a picture</picture>
</example>
</dummy>

I want to get "body" and "picture" child nodes of the
"example" node. I thought that this request could do
the trick but it is not working :

Precisely how it's not working? What's your XPath
environment? (XSLT processor? If yes, which one of them?
XPath-capable DOM API implementation? If yes, which one of
them? Some sort of XPath-capable XML editor? If yes, which
one of them? If it's XMLSpy, well, I've never used XMLSpy
myself, but every time someone comes to the group saying
'Hey! This doesn't work for me in XMLSpy!', regulars answer
that XMLSpy is broken then. I've seen this happen often
enough that I mentally filed XMLSpy away under the 'Don't
use unless your bloody life depends on it' category.)
/dummy/example/*[name()!="title"]

Given your sample XML, this sure works for me using both
xsltproc and saxon8. A few thoughts:

1. Perhaps you've got an xmlns problem. Try using
local-name():

/dummy/example/*[local-name()!="title"]

(Obviously, this does not apply if you're not using XML
Namespaces.)

2. The above solution is a bit kludgy, consider using
something like:

(/dummy/example/body|/dummy/example/picture)

Or:

(/dummy/example/NS:body|/dummy/example/NS:picture)

Where NS: is the XML Namespace your elements are in. Again,
this won't solve your problem unless there's something
wrong with namespaces.

3. In case the node order in the document matters (and you
have either knowledge or control of precisely how it does
matter) you can use something like:

/dummy/example/*[position() &gt; 1]

Or:

/dummy/example/*[preceding-sibling::title]

A bit inelegant, though.

4. If you're using XSLT, consider matching everything:

/dummy/example/*

...and controlling the result using templates (untested):

<xsl:template match="title"/>
<xsl:template match="body|picture">
<xsl:copy-of select="."/>
</xsl:template>

Hope that helps.
 
P

p.lepin

Please don't top-post.
the above XPath /dummy/example/*[name()!="title"] works
perfectly in XMLSpy. As a result it gives the <body> and
<picture> elements.

Good for XMLSpy.
/dummy/example/*[name()!="title"]

Given your sample XML, this sure works for me using
both xsltproc and saxon8. A few thoughts:

1. Perhaps you've got an xmlns problem. Try using
local-name():
2. The above solution is a bit kludgy, consider using
something like:

(/dummy/example/body|/dummy/example/picture)
3. In case the node order in the document matters (and
you have either knowledge or control of precisely how
it does matter) you can use something like:

/dummy/example/*[position() &gt; 1]
4. If you're using XSLT, consider matching everything:

/dummy/example/*

...and controlling the result using templates
(untested):
I think your suggestions starting from 2. to 4. are a
bit strange. They all require information about the
other elements, their order or their names.

2: Yeah, right, you have no information at all about what
you're processing, except that you don't want the title
elements. Sure, it does happen, and when it happens it's
usually a symptom of design problems, either on XML or XML
processing side.

3: It does and I said no less, I believe.

Concerning 4, it's actually just about the best way to
deal with the problem, if you are using XSLT and unless
you need to process only a few of example's children.
The original XPath clearly just needs the "title" name
as information and does what it should.

It does.

And it does break the very moment you introduce XML
Namespaces into the picture. Welcome to the 21st century.
You're a bit late, but that's ok.

KISS principle occasionally leads to PITA problems down
the road.
 
S

spiff

Pavel,
And it does break the very moment you introduce XML
Namespaces into the picture.

What's the point? I don't see any namespaces here in the sample. The
poster says he wants to learn XPath now. Maybe he has no idea about
namespaces at all (yet)? And if you want to consider namespaces take
local-name() or write them explicit.
Welcome to the 21st century.
You're a bit late, but that's ok.

Sorry, but this is just childish.

And your samples are breaking if the structure of the XML is changing
additionally that the original goal was simply to get all elements
which do not match the title element.

regards
spiff


Please don't top-post.
the above XPath /dummy/example/*[name()!="title"] works
perfectly in XMLSpy. As a result it gives the <body> and
<picture> elements.

Good for XMLSpy.
/dummy/example/*[name()!="title"]

Given your sample XML, this sure works for me using
both xsltproc and saxon8. A few thoughts:

1. Perhaps you've got an xmlns problem. Try using
local-name():
2. The above solution is a bit kludgy, consider using
something like:

(/dummy/example/body|/dummy/example/picture)
3. In case the node order in the document matters (and
you have either knowledge or control of precisely how
it does matter) you can use something like:

/dummy/example/*[position() &gt; 1]
4. If you're using XSLT, consider matching everything:

/dummy/example/*

...and controlling the result using templates
(untested):
I think your suggestions starting from 2. to 4. are a
bit strange. They all require information about the
other elements, their order or their names.

2: Yeah, right, you have no information at all about what
you're processing, except that you don't want the title
elements. Sure, it does happen, and when it happens it's
usually a symptom of design problems, either on XML or XML
processing side.

3: It does and I said no less, I believe.

Concerning 4, it's actually just about the best way to
deal with the problem, if you are using XSLT and unless
you need to process only a few of example's children.
The original XPath clearly just needs the "title" name
as information and does what it should.

It does.

And it does break the very moment you introduce XML
Namespaces into the picture. Welcome to the 21st century.
You're a bit late, but that's ok.

KISS principle occasionally leads to PITA problems down
the road.
 
J

Joe Kesselman

Mat| said:
I am learning XPath, and I am trying to get child nodes
of a node whose names do *not* match a given string,
/dummy/example/*[name()!="title"]

As others have said, that should work for the sample document you've
given us. Pavel's suggestions for what to check, and for alternatives
you might want to consider, are good ones.

And while name() certainly does work, I also have to agree with his
warning that this will turn around and bite you when you start working
with namespaced documents. Not a problem right now, but worth pointing
out so folks recognize the mistake when they make it in the future.
<smile/> Relying on name() is common as a "quick hack"... but not really
considered a best practice if you intend to write a long-term solution.
 
P

p.lepin

Much better, but you lost some context; futhermore,
there's no need to quote what you're not replying to.
(e-mail address removed) schrieb:

[local-name()-based solution to a problem]
What's the point? I don't see any namespaces here in the
sample.

XML Namespaces are fundamental enough that it's best to
learn about them as early as possible. Anyway, your
argument is woefully weak. You don't see any namespaces?
Well, I don't see <title> not being the first child node,
or any elements other than <title>, <body> and <picture>
as children of <example>. Therefore, solutions #2 and 3
are exactly as good as #1 - they work on the sample XML
given. Period.
The poster says he wants to learn XPath now. Maybe he
has no idea about namespaces at all (yet)?

And that was precisely the problem I was addressing --
telling the OP about the namespaces.
And if you want to consider namespaces take local-name()
or write them explicit.

In case you missed it, I mentioned that in my post. Of
course, local-name() alone may be not enough, because
<title> and <namespace:title> may be two totally different
things that need to be processed differently. So you also
need to consider namespace-uri().

And you can't really "write them explicit", because we
need exclusion, not inclusion. Hint: if you define
xmlns:foo="http://example.org/foo" in your transformation
and xmlns:bar="http://example.org/foo" in you document,
then match foo:baz node, what its name() is going to be?

[XML Namespaces]
Sorry, but this is just childish.

Sure it is.
And your samples are breaking if the structure of the
XML is changing additionally that the original goal was
simply to get all elements which do not match the title
element.

If the structure of the XML is changing, you can't
guarantee *any* solution will work. Sooner or later all of
them will break if you start tinkering with the XML
structure. But some of them may survive the changes that
will break the others. That's exactly the point of showing
the OP various solutions to his problem.

#1 "breaks" if you let the <example> contain the
<xhtml:title> element. Or <foo:title>. Or if you start
using namespaces for your own elements.

#2 "breaks" if you allow elements other than <title>,
<body> and <picture> as children of <example>, but isn't
bothered one bit by the document order.

#3 "breaks" if there may be more than one <title> in
<example> or if title is not required to be the first node
child of <example>, but survives if you allow elements
other than <title>, <body> and <picture>, if you start
using namespaces or even if you decide that <title> may
be replaced by <zagolovok>.

#4 "breaks" if... etc.

Simply put: if the XML structure may change, you may need
to change your code no matter what.

If you still don't understand what I'm talking about, or
why I came up with more than one possible solution, please
feel free to flame me to your heart's content, but I'm not
going to be bothered to explain this to you yet again.

Have a nice century,
 
S

spiff

If you still don't understand what I'm talking about, or
why I came up with more than one possible solution, please
feel free to flame me to your heart's content, but I'm not
going to be bothered to explain this to you yet again.

Have a nice century,

Pavel, all of your posts did end with a flame against me. Mine didn't
(against you of course).
Anyway, your
argument is woefully weak. You don't see any namespaces?
Well, I don't see <title> not being the first child node,
or any elements other than <title>, <body> and <picture>
as children of <example>. Therefore, solutions #2 and 3
are exactly as good as #1 - they work on the sample XML
given. Period.

Come on. You started to make it important to deal also with something
which is simply not present in the sample. Namespaces, do you remember?

Once again #1 only breaks if you start to deal with namespaces. I don't
know if the poster wants to. Maybe later, maybe never. All of your
suggestions are breaking if you change the structure of the XML.

But I guess you are so upset because I mentioned that XMLSpy can
process this XPath correctly. Nobody was talking about XMLSpy but you
started flaming against it. Any bad experiences here?

Have a nice day Pavel
 
P

Philippe Poulard

Joe said:
Mat| said:
I am learning XPath, and I am trying to get child nodes
of a node whose names do *not* match a given string,

/dummy/example/*[name()!="title"]


As others have said, that should work for the sample document you've
given us. Pavel's suggestions for what to check, and for alternatives
you might want to consider, are good ones.

And while name() certainly does work, I also have to agree with his
warning that this will turn around and bite you when you start working
with namespaced documents. Not a problem right now, but worth pointing
out so folks recognize the mistake when they make it in the future.
<smile/> Relying on name() is common as a "quick hack"... but not really
considered a best practice if you intend to write a long-term solution.

hi,

my 1€...

the best thing to do is :
/dummy/example/*[not(self::title)]

if you would use namespaces, it would become :
/foo:dummy/foo:example/*[not(self::foo:title)]

but if you use instead name() :
/foo:dummy/foo:example/*[name()!="foo:title"]
....will give you the same result *only* if the XML source do use the
same prefix, which is somewhat hazardous...

an equivalent expression based on the name of the tag is :
/foo:dummy/foo:example/*[local-name()!="title" or
namespace-uri()!="http://acme.org/foo"]

mmmh, self:: is really better !

--
Cordialement,

///
(. .)
--------ooO--(_)--Ooo--------
| Philippe Poulard |
-----------------------------
http://reflex.gforge.inria.fr/
Have the RefleX !
 
P

p.lepin

spiff said:
Pavel, all of your posts did end with a flame against
me. Mine didn't (against you of course).

I suppose I'm not a very patient person, especially where
incompetence or hidden agendas are concerned. Note that
all of my posts contained detailed explanations of my
point of view, while yours arbitrarily ignored my
explanations and contained no sensible arguments at all.
[There are no namespaces in the document --
therefore we don't need to consider namespaces.]

Anyway, your argument is woefully weak. You don't see
any namespaces? Well, I don't see <title> not being
the first child node, or any elements other than
<title>, <body> and <picture> as children of
<example>. Therefore, solutions #2 and 3 are exactly
as good as #1 - they work on the sample XML given.
Period.

Come on. You started to make it important to deal also
with something which is simply not present in the
sample. Namespaces, do you remember?

That's called reductio ad absurdum and is meant to
disprove something -- your argument that namespaces are
irrelevant to the discussion in this case. Funny how you
managed to ignore the detailed explanations a few
lines later. I find it hard to believe they're beyond your
level of understanding.

[local-name()-based solution]
Once again #1 only breaks if you start to deal with
namespaces.

Oh, really? How about we change <title> to
<example-title>? Shucks, doesn't work anymore. How about
we add <sub-title> elements -- that don't need to be
processed, of course? How about we allow more than one
<body> and <picture> and decide to group them into
<document> children of <example> element? Seriously, drop
it already, you're attempting to defend an indefensible
position. Well, I suppose it is defensible if you resort
to blind ignorance, but I would advise against that.
I don't know if the poster wants to. Maybe later, maybe
never. All of your suggestions are breaking if you
change the structure of the XML.

Do you imply you can offer a solution that wouldn't break
no matter what changes we make to the XML document being
processed?! See above. Try reading my previous post again.
Get a clue.
But I guess you are so upset because I mentioned that
XMLSpy can process this XPath correctly.

Oh, seriously? Well, *I* guess you're so upset because I
said in passing that I've seen several mentions of
XMLSpy's brokenness and that scared me away from it. While
we're guessing, I also guess my mention of XMLSpy was why
you wedged into the discussion and started saying my
suggestions were strange, without ever making any points I
haven't already made and blissfully ignoring my attempts
at explaining.

Oh. By the way. Where'd your .sig go? There was this funny
URL in it... hmmm, what was it... Ah, right:

Now, that's great fun!

Since we started guessing, I'd like to guess that you were
trying to indirectly discredit my statement about XMLSpy,
by implying I don't know what I'm talking about on other
matters etc. etc. Obviously, every reader of the group
will decide for himself (and I guess many of them have
already *plonk*ed us both), but really, I guess that was a
somewhat weakish attempt on your part. You gotta try
harder, seriously.

You know, I just *love* guessing.
Nobody was talking about XMLSpy but you started flaming
against it.

Yeah, I suppose I did. Now, what would a sensible person
do? A sensible person would say something like: 'That's
not true, XMLSpy is fully foo-compliant now -- here are
the results of running the foo test suites', or maybe:
'Yeah, it had its share of problems, but the dev team is
working hard, and it's getting better every day'.

Hint: 'XMLSpy runs a trivial XPath expression' is not a
statement of compliance.

A sensible person would probably also mention that he's
ever-so-indirectly affiliated with the product in
question.

Not being a particularly sensible person, I would probably
say something not particularly sensible, like: 'Well, I'd
still stay away from it, but maybe that's just me,' and
you'd be on top of it.
Any bad experiences here?

Any problems with reading skills? From my first post in
this thread:

"I've never used XMLSpy myself [...]"
Have a nice day Pavel

Thanks, I surely had a lot of laughs today.
 
J

Joseph Kesselman

Children, if you want to play S&M games you really ought to get a room
somewhere.

If you've got something worth saying, you don't need to resort to
attacking personalities. And if you're going to waste time debating
personalities, I for one don't care whether you have anything worth
saying. Killfiles are a good thing.
 
D

Dimitre Novatchev

Use:

/*/*/*[not(self::title)]


I would recommend using the XPath Visualizer, using which many people have
learned XPath the fun way.


Cheers,
Dimitre Novatchev
 
P

p.lepin

Philippe said:
Joe said:
Mat| said:
I am learning XPath, and I am trying to get child
nodes of a node whose names do *not* match a given
string,
/dummy/example/*[name()!="title"]

And while name() certainly does work, I also have to
agree with his warning that this will turn around and
bite you when you start working with namespaced
documents.

the best thing to do is :
/dummy/example/*[not(self::title)]

if you would use namespaces, it would become :
/foo:dummy/foo:example/*[not(self::foo:title)]

Definitely the most elegant solution.

Still, this got me thinking. While Philippe's solution
looks neat and works well, I have a feeling that the fact
you need to do something like that (that is, 'choose all
children but <title>s') is a fairly strong hint that you
should consider redesigning your XML structure (if you
have control over that, of course). For original poster's
sample that would be something like:

<dummy>
<example title="Example 1">
<body>this is an example</body>
<picture>a reference to a picture</picture>
</example>
</dummy>

or:

<dummy>
<example>
<title>Example 1</title>
<body>
<content>this is an example</content>
<picture>a reference to a picture</picture>
</body>
</example>
</dummy>

What I probably mean to say (yeah, I'm not sure what I'm
sayin' myself), is that in case you need a predicate in
your XPath that somehow feels unnatural*, although the
nodes you need selected seem to belong to a well-defined,
logically natural group, it might be worth it to consider
changing the XML's structure to actually group those
nodes in a parent element.

* for some values of 'unnatural'
but if you use instead name() :
/foo:dummy/foo:example/*[name()!="foo:title"]
...will give you the same result *only* if the XML
source do use the same prefix, which is somewhat
hazardous...

I wonder, by the way. Aren't

<foo:element xmlns:foo="foo"/>

and

<bar:element xmlns:bar="foo"/>

supposed to be two completely interchangeable
representations of the same document fragment? If they
are, isn't name() just a bit broken in that it makes
those two distinguishable?
 

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,994
Messages
2,570,223
Members
46,812
Latest member
GracielaWa

Latest Threads

Top