[ Note: I've sent this to another list which some folks on this list may
be on, so this may seem like a duplicate.  If so, please ignore this
copy. ]

I don't know how many folks are using tDOM but I'm sure more and more
are.  I keep stumbling into this problem of trying to access child nodes
which are in the default namespace but the parent is in a named
namespace ... and trying to write XPath expressions start to look really
dog-awful, like:

    $root selectNodes {/*[local-name()='foo']/*[local-name()='bar']/...}

So, I sat down for a few minutes and thought about the problem, and
after some head-scratching, it hit me: name the default namespace.  Duh.
So, here's some sample code:

    ### IMPORTANT: This code lets us get at nodes with a null prefix.
    if {[$root hasAttribute xmlns]} {
        $root setAttributeNS "" xmlns:default [$root getAttribute xmlns]
    }

So, now, I can rewrite that XPath expression above:

    $root selectNodes /default:foo/default:bar/...

Man.  Life just couldn't get any better.

If any of you are wondering why this matters, here's a sample XML doc
and some sample code illustrating the beauty:

    set xml {
        <aaa:duh xmlns="booboo" xmlns:aaa="blort">
            <foo>
                <bar>some text</bar>
            </foo>
        </aaa:duh>
    }

    $doc [dom parse $xml]
    set root [$doc documentElement]

Suppose you want to get the text node inside <bar> with an absolute
XPath expression.  You might think you could write:

    [$root selectNodes /aaa:duh/foo/bar] text

Ah, but XPath *SPANKS* us and tells us we're naughty, that <foo> and
<bar> have a null prefix and live in the unnamed namespace.  That line
of code returns an empty string, not "some text" as we might have
expected.  So, we tell XPath "well, how about you do me a favor and
pretend like any node in the unnamed namespace really has a name of my
choosing ..." by doing this:

    $root setAttributeNS "" xmlns:default [$root getAttribute xmlns]

We're telling the processor to name all nodes in the default namespace
as though they were in the namespace named "default".  N.B.:  If your
XML document really *HAS* a namespace named "default", this code will
likely CLOBBER it and give you really weird behavior.  Change
"xmlns:default" in the above line to a namespace that won't ever exist
in your document, then.

Now that we've done this, lets rewrite that XPath expression and try
again:

    [$root selectNodes /aaa:duh/default:foo/default:bar] text

Ahh!  It returned the string "some text" -- exactly what we wanted.
Notice the injection of "default:" above before "foo" and "bar" -- since
we just told the processor that nodes in the unnamed namespace (i.e.,
<foo> and <bar>) now live in the namespace named "default", in order to
specify them in an XPath expression, we need to say "default:foo" and
"default:bar".  But this is a hell of a lot easier to read than
"*[local-name()='foo']" and "*[local-name()='bar']", at least on my
eyes.

If this is all old news, feel free to ignore this email.  I hadn't seen
it documented anywhere and I know I've puzzled over this for at least an
hour or two over the past few months, so maybe this write-up might save
a few people the same agony.

-- Dossy

--
Dossy Shiobara                       mail: [EMAIL PROTECTED]
Panoptic Computer Network             web: http://www.panoptic.com/
  "He realized the fastest way to change is to laugh at your own
    folly -- then you can let go and quickly move on." (p. 70)


--
AOLserver - http://www.aolserver.com/

To Remove yourself from this list, simply send an email to <[EMAIL PROTECTED]> with the
body of "SIGNOFF AOLSERVER" in the email message. You can leave the Subject: field of 
your email blank.

Reply via email to