You are viewing a plain text version of this content. The canonical link for it is here.
Posted to j-users@xalan.apache.org by Susan Barretta <ba...@itmedicine.net> on 2003/04/07 16:47:29 UTC

Need help with ApplyXPathDOM

Hi,

I've run the Xalan example ApplyXPathDOM with foo.xml, now I am trying to 
get it to work with namespaces.

I do not understand the 
FAQ  http://xml.apache.org/xalan-j/faq.html#faq-N101BE  where it says, "add 
a namespace declaration with a prefix".

Well, that's what I THINK I've been doing, but I still cannot get 
ApplyXPathDOM to run. I modified foo.xml with prefixes and a namespace 
(fooprefix.xml), but I still get errors when I run ApplyXPathDOM.

I've got setNamespaceAware(true) .

<?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>

I try to access this file with the expression:

java ApplyXPathDOM fooprefix.xml /foo:doc/name[@first='David']

but still get this error:

Exception in thread "main" org.w3c.dom.DOMException: Prefix must resolve to 
a namespace: foo
         at 
org.apache.xpath.domapi.XPathEvaluatorImpl.createExpression(XPathEval
uatorImpl.java:206)
The ONLY way I can force this to work is if I subclass  XPathNSResolverImpl 
and hard code it with
a hashtable containing all the prefixes and namespaces I anticipate in a 
file, then forcing it to return
the appropriate URI for a prefix.

Then in ApplyXPathDOM I make the following modification:

       //XPathNSResolver resolver = evaluator.createNSResolver(doc);
       XPathNSResolver resolver = new DataServerNSResolverImpl(doc);


This is not an acceptable solution for us.  I would expect ApplyXPathDOM to 
work automatically recognizing fooprefix.xml, without my subclass.

Somebody on a Sun Forum suggested I need a different a different sort of 
factory instance and then totally failed to specify which one.


-- Susan


Re: Need help with ApplyXPathDOM

Posted by Susan Barretta <ba...@itmedicine.net>.

Simon,

You have explained that SOOO well that as far as I am concerned your post 
should be included in Xalan documentation.

My initial attempt to get this to work by subclassing a resolver, then, was 
definitely the right direction to go, since we need to be able "query" our 
documents with certain data source prefixes.

Thanks very much!


Re: Need help with ApplyXPathDOM

Posted by Simon Kitching <si...@ecnetwork.co.nz>.
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:section[@name='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:name[@first='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:section[@name='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:section[@name="ls"]
> 
> -- I thought maybe I should put in a predicate in for the namespace, so I 
> tried a few possibilities:
> 
> /foo:doc/in:section[@name='ls'][@xmlns:in='http://junky.com']
> 
> and still get the same error.
> 
> I tried moving the xmlns:in predicate "up" to foo:doc, like this:
> /foo:doc[@xmlns:in="http://junky.com"]/in:section[@name='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
> 
> 


Re: Need help with ApplyXPathDOM

Posted by Susan Barretta <ba...@itmedicine.net>.

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:name[@first='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:section[@name='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:section[@name="ls"]

-- I thought maybe I should put in a predicate in for the namespace, so I 
tried a few possibilities:

/foo:doc/in:section[@name='ls'][@xmlns:in='http://junky.com']

and still get the same error.

I tried moving the xmlns:in predicate "up" to foo:doc, like this:
/foo:doc[@xmlns:in="http://junky.com"]/in:section[@name='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