Hi Susan,

You have to remember that the person supplying the input document
doesn't have to use any set prefix. A node is actually named by a (uri,
localname) pair, NOT a (prefix, localname) pair.

To give an example,
  <foo:fred xmnls:foo="http://www.acme.com/foo"/>
and
  <bar:fred xmlns:bar="http://www.acme.com/foo"/>
are matching nodes; they are both ("http://www.acme.com/foo";, "fred")
nodes.

So your xpath expressions should *not* assume that "foo" is the prefix
that will be present in the input document.

The XPathAPI.eval(node, expr) method provides a "convenience" mapping of
namespaces by looking at the namespaces declared on the context node. I
actually think this is wrong, as it leads to problems like you are
experiencing (you aren't the first one with this issue). It suggests to
people that their xpath expressions should contain the same prefixes as
are in the document, when this is not a "stable" solution.

The following method exists on XPathAPI:
  XPathAPI.eval(Node node, String expr, PrefixResolver pr);

What you need to do is create a PrefixResolver, and add mappings from
any old prefixes you want to the URIs that the input document will use.

eg [pseudocode]

myprefixresolver.addNamespaceMapping("bar", "http://foo.org";);
myprefixresolver.addNamespaceMapping("baz", "http://junky.com";);

now
  XPathAPI.eval(
   node, 
   "/bar:doc/baz:[EMAIL PROTECTED]'ls']", 
   myprefixresolver)
should match your document, despite the prefixes being different,
because the prefixes MAP to the required URIs. And your xpath will match
the input document no matter what prefixes the sender chooses (as they
are allowed to do).

As mentioned earlier, the XPathAPI.eval(node, expr) method automatically
sets up a prefixresolver instance for you populated with the namespaces
declared on the CONTEXT NODE ONLY (the one you pass in as a parameter).
It really can't set up all the namespaces declared below that node,
because the creator of the input document is technically allowed to
remap prefixes:
  <foo:node xmlns="http://foo.org";>
    <foo:node xmlns="http://bar.org"/> <!-- different node!! -->
  </foo:node>

I don't know of any class in the xalan lib that provides a concrete
implementation of PrefixResolver that can be used directly, but writing
a simple implementation of the PrefixResolver interface (with the
mappings stored as a hashmap of prefix->uri) takes only a couple of
dozen lines of code.

Regards,

Simon


On Tue, 2003-04-08 at 05:36, Susan Barretta wrote:
> There was a problem in my xpath expression.  /foo:doc/name should be 
> /foo:doc/foo:name ,  however fixing that was not sufficient.
> 
> I upgraded to Xalan 2.5 D1, and that helped.  In other words, 
> ApplyXPathDOM, with NO code modifications, under Xalan 2.5 D1, with the file
> 
> <?xml version="1.0"?>
> <foo:doc xmlns:foo="http://foo.org";>
>     <foo:name first="David" last="Marston"/>
>     <foo:name first="David" last="Bertoni"/>
>     <foo:name first="Donald" last="Leslie"/>
>     <foo:name first="Emily" last="Farmer"/>
>     <foo:name first="Joseph" last="Kesselman"/>
>     <foo:name first="Myriam" last="Midy"/>
>     <foo:name first="Paul" last="Dick"/>
>     <foo:name first="Stephen" last="Auriemma"/>
>     <foo:name first="Scott" last="Boag"/>
>     <foo:name first="Shane" last="Curcuru"/>
> </foo:doc>
> 
> and the invocation  java ApplyXPathDOM fooprefix.xml 
> /foo:doc/foo:[EMAIL PROTECTED]'David']
> 
> WORKS.
> 
> But when I tried complicating things a bit, I still get errors.
> 
> -- fooprefix.xml --
> 
> <?xml version="1.0"?>
> <foo:doc xmlns:foo="http://foo.org";>
>    <in:section name="ls" xmlns:in="http://junky.com";>
>      <in:index id="crud">
>       <ls:names xmlns:ls="http://namesls.org";>
>        <ls:name first="David" last="Marston"/>
>        <ls:name first="David" last="Bertoni"/>
>        <ls:name first="Donald" last="Leslie"/>
>        <ls:name first="Emily" last="Farmer"/>
>        <ls:name first="Joseph" last="Kesselman"/>
>        <ls:name first="Myriam" last="Midy"/>
>        <ls:name first="Paul" last="Dick"/>
>        <ls:name first="Stephen" last="Auriemma"/>
>        <ls:name first="Scott" last="Boag"/>
>        <ls:name first="Shane" last="Curcuru"/>
>       </ls:names>
>      </in:index>
>    </in:section>
> </foo:doc>
> 
> Now when I try running:
> 
>      java ApplyXPathDOM fooprefix.xml /foo:doc/in:[EMAIL PROTECTED]'ls']
> 
> I still get
> 
> Exception in thread "main" org.w3c.dom.DOMException: Prefix must resolve to 
> a namespace: in
>          at 
> org.apache.xpath.domapi.XPathEvaluatorImpl.createExpression(XPathEval
> uatorImpl.java:210)
> 
> ONE way to get around this is to put all my namespace xmlns attributes into 
> the top node - then it runs through.
> 
> We are not too happy with this solution either!
> 
> And more strange things:
> 
> -- The DOMException from the xpath expression below says: Prefix must 
> resolve to namespace: in
> 
> /foo:doc/in:[EMAIL PROTECTED]"ls"]
> 
> -- I thought maybe I should put in a predicate in for the namespace, so I 
> tried a few possibilities:
> 
> /foo:doc/in:[EMAIL PROTECTED]'ls'[EMAIL PROTECTED]:in='http://junky.com']
> 
> and still get the same error.
> 
> I tried moving the xmlns:in predicate "up" to foo:doc, like this:
> /foo:[EMAIL PROTECTED]:in="http://junky.com"]/in:[EMAIL PROTECTED]'ls']
> 
> When there are single quotes around http://junky.com,
> I get the same error about the namespace : in , but when I put double 
> quotes around http://junky.com , I get
> 
> Exception in thread "main" org.w3c.dom.DOMException: Prefix must resolve to 
> a namespace: http
> 
> which I thought was really strange.
> 
> So what is the correct way to xpath through namespaces?
> 
> Thanks for helping!
> 
> -- Susan
> 
> 

Reply via email to