easy question - empty element?

V

Valery

In the following XML:

<?xml version="1.0" encoding="utf-8" ?>
<Plcy service="ILiability" boId ="LifePolicy, 1">
<Prem service="IPremium" boId ="RegularPremium, 1"></Prem>
<L1 service="ILifeMain" type = "Life1">
<FirstName>Sheila</FirstName>
<Age>65</Age>
<Relation>spouse</Relation>
</L1>
<L2 service="ILife" type = "Life2">
<FirstName>Bruce</FirstName>
<Age>70</Age>
</L2>
</Plcy>

I would like to select Nodes with boId attribute which are empty. I am
using an XPath expression:

"//*[@boId and not(text())]"

but MS VS XPathNavigator's Select() returns both Plcy and Prem. It
also sets IsEmpty field of Prem node to false.

Whose fault is it - mine or MS?

Yours,
Valery the Newbie
 
P

Pavel Lepin

Valery said:
<?xml version="1.0" encoding="utf-8" ?>
<Plcy service="ILiability" boId ="LifePolicy, 1">
<Prem service="IPremium" boId ="RegularPremium,
1"></Prem> <L1 service="ILifeMain" type = "Life1">
<FirstName>Sheila</FirstName>
<Age>65</Age>
<Relation>spouse</Relation>
</L1>
<L2 service="ILife" type = "Life2">
<FirstName>Bruce</FirstName>
<Age>70</Age>
</L2>
</Plcy>

I would like to select Nodes with boId attribute which are
empty. I am using an XPath expression:

"//*[@boId and not(text())]"

The default axis is child::, therefore this doesn't
mean 'are empty' but 'have no text node children' instead.
but MS VS XPathNavigator's Select() returns both Plcy and
Prem.

Actually, your Plcy element does have text node children.
Either you're quietly normalising whitespace somewhere (and
failed to mention it to us for some reason) or you're
posting beautified XML instead of the original document
(and failed to mention it), OR MSXML's XPath evaluator is
seriously borken, which I find a bit hard to believe.
It also sets IsEmpty field of Prem node to false.

Er, what? I can't seem to find any mention of isEmpty
property or method in DOM specs.
Whose fault is it - mine or MS?

The data is insufficient, so it's hard to tell, but I'd
guess it's yours.

Depending on what you mean by 'empty', you might actually
want one of the following:

//*[@boId and not(descendant::text())]
//*[@boId and not(node())]
//*[@boId and not(text()[normalize-space()])]
//*[@boId and not(descendant::text()[normalize-space()])]
 
M

Martin Honnen

Valery said:
I would like to select Nodes with boId attribute which are empty. I am
using an XPath expression:

"//*[@boId and not(text())]"

but MS VS XPathNavigator's Select() returns both Plcy and Prem. It
also sets IsEmpty field of Prem node to false.

Whose fault is it - mine or MS?

As for the IsEmpty property, it is documented here:
<URL:http://msdn2.microsoft.com/en-us/library/System.Xml.XmlElement.IsEmpty.aspx>.
It does not check whether an element has no child nodes, rather it
checks (or sets) whether an element is serialized as <element/> or
<element></element>, for the former case it is true, for the latter it
is false. In your example you have
<Prem service="IPremium" boId ="RegularPremium, 1"></Prem>
so the property is false. It would be true for
<Prem service="IPremium" boId ="RegularPremium, 1"/>
As for the white space problem, you can set the property
PreserveWhitespace on XmlDocument
<URL:http://msdn2.microsoft.com/en-us/library/System.Xml.XmlDocument.PreserveWhitespace.aspx>
before you load. By default it is false, set it to true for your needs.
 
A

Andy Dingley

Depending on what you mean by 'empty', you might actually
want one of the following:

//*[@boId and not(descendant::text())]
//*[@boId and not(node())]
//*[@boId and not(text()[normalize-space()])]
//*[@boId and not(descendant::text()[normalize-space()])]

I can't imagine many situations where "//*[...]" is a good idea,
especially not for an XPath newbie. That's going to match every
element in the tree, depending only on a complex predicate to filter
them. Predicates aren't easy to get right when you're starting out!

As you usually know the element name you're trying to match, it's
often going to be easier to match on the <policy> or <premium>
elements with "policy [...]" or "premium [...]" and a simpler and more
reliable predicate.

I'd also advise using "policy [...]" rather than "//policy [...]",
unless you really need to. That "//" operation can be a nuisance too.

I'd also strongly recommend a more readable element named "<policy>"
rather than "<Plcy>". Abbreviating these names and introducing mixed-
case is just setting yourself up to make maintenance awkward in the
future and there's no benefit to doing it.
 
P

Pavel Lepin

Martin Honnen said:
Valery said:
I would like to select Nodes with boId attribute which
are empty. I am using an XPath expression:

"//*[@boId and not(text())]"

but MS VS XPathNavigator's Select() returns both Plcy and
Prem. It also sets IsEmpty field of Prem node to false.

As for the IsEmpty property, it is documented here:

[long-ish url snipped]

Oh my goodness! It's a serialisation property that actually
messes with the document structure when manually set to
true?!

Returns true if the element is to be serialized in the
short tag format "<item/>"; false for the long
format "<item></item>". When setting this property, if set
to true, the children of the element are removed and the
element is serialized in the short tag format.

This is SO brain-damaged.
 
P

Pavel Lepin

Andy Dingley said:
Depending on what you mean by 'empty', you might actually
want one of the following:

//*[@boId and not(descendant::text())]
//*[@boId and not(node())]
//*[@boId and not(text()[normalize-space()])]
//*[@boId and
not(descendant::text()[normalize-space()])]

I can't imagine many situations where "//*[...]" is a good
idea, especially not for an XPath newbie.

There certainly are some. Processing meta-data stored in
attributes from a dedicated namespace seems to be one of
the more common use cases.
That's going to match every element in the tree, depending
only on a complex predicate to filter them.

Them's the breaks.
As you usually know the element name you're trying to
match...

Usually, but not necessarily.
I'd also strongly recommend a more readable element named
"<policy>" rather than "<Plcy>".

Agreed in principle, but in this case it took me all of a
quarter a second to parse 'Plcy'.
 
A

Andy Dingley

It does not check whether an element has no child nodes, rather it
checks (or sets) whether an element is serialized as <element/> or
<element></element>, for the former case it is true, for the latter it
is false.

Ooh, nice ! A pseudo-DOM property that's tightly coupled to a minor
detail of serialization: that some child nodes (elements and text)
appear in one place, whilst other child nodes (attributes) don't.

What on earth is this thing _for_, and when is it ever going to be a
good idea to actually use the damned thing? Sometimes I wonder what
they're smoking in Redmond
 
A

Andy Dingley

I can't imagine many situations where "//*[...]" is a good
idea, especially not for an XPath newbie.

There certainly are some. Processing meta-data stored in
attributes from a dedicated namespace seems to be one of
the more common use cases.

Even in that case, you're likely to know the attribute name you're
after - it's the same situation I describe, just with attributes
rather than elements.

Now there are admittedly many cases when you do want to apply a less
procedural and more declarative coding style to XSLT, as this is good
practice in many cases (usually where you don't know the document
structure beforehand). This is a tricky technique though, not newbie
stuff.
Agreed in principle, but in this case it took me all of a
quarter a second to parse 'Plcy'.

I can't afford a quarter of a second. I've got a DB schema here that's
3-4 thousand lines long XML document. Now I know that the _computers_
can make sense of it all and can tie the column entities to the type
and purpose information, but I as a human can't. I need help from
naming conventions. Repeat this over the thousands of instances in a
typical system and all those quarter seconds add up.
 

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

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top