Java – Saxon 8 (Java version) problem

javasaxsaxonxml

I'll point out now, that I'm new to using saxon, and I've tried following the docs and examples in the package, but I'm just not having luck with this problem.

Basically, I'm trying to do some xml processing in java using saxon v8. In order to get something working, I took one of the sample files included in the package and modified to my needs. It works so long as I'm not using namespaces, and that is my question. How can I get around the namespace problem? I don't really care to use it, but it exists in my xml, so I either have to use it or ignore it. Either solution is fine.

Anyway, here is my starter code. It doesn't do anything but take an xpath query try to use it against the hard coded xml doc.

public static void main(String[] args) {
    String query = args[0];

    File XMLStream=null;
    String xmlFileName="doc.xml";
    OutputStream destStream=System.out;
    XQueryExpression exp=null;
    Configuration C=new Configuration();
    C.setSchemaValidation(false);
    C.setValidation(false);

    StaticQueryContext SQC=new StaticQueryContext(C);
    DynamicQueryContext DQC=new DynamicQueryContext(C);      
    QueryProcessor processor = new QueryProcessor(SQC);
    Properties props=new Properties();
    try{   
        exp=processor.compileQuery(query);
        XMLStream=new File(xmlFileName);
        InputSource XMLSource=new InputSource(XMLStream.toURI().toString());
        SAXSource SAXs=new SAXSource(XMLSource); 
        DocumentInfo DI=SQC.buildDocument(SAXs);
        DQC.setContextNode(DI);

        SequenceIterator iter = exp.iterator(DQC);
        while(true){
            Item i = iter.next();
            if(i != null){
                System.out.println(i.getStringValue());
            }
            else break;
        }
    }
    catch (Exception e){
        System.err.println(e.getMessage());
    }
}   

An example XML file is here…

<?xml version="1.0"?>
<ns1:animal xmlns:ns1="http://my.catservice.org/">
    <cat>
        <catId>8889</catId>
        <fedStatus>true</fedStatus>
    </cat>
</ns1:animal>

If I run this with a query including the namespace, I get an error. For example:
/ns1:animal/cat/ gives the error: "Prefix ns1 has not been declared".

If I remove the ns1: from the query, it gives me nothing. If I doctor the xml to remove the "ns1:" prepended to "animal" I can run the query /animal/cat/ with success.

Any help would be greatly appreciated. Thanks.

Best Answer

Error message correctly points out that your xpath expression does not indicate what namespace prefix "ns1" means (binds to). Just because document to operate on happens to use binding for "ns1" does not mean it is what should be used: this because in XML, it's the namespace URI that matters, and prefixes are just convenient shortcuts to the real thing.

So: how do you define the binding? There are 2 generic ways; either provide a context that can resolve the prefix, or embed actual URI within XPath expression.

Regarding the first approach, this email from Saxon author mentions JAXP method XPath.setNamespaceContext(), similarly, Jaxen XPath processor FAQ has some sample code that could help That's not very convenient, as you have to implement NamespaceContext, but once you have an implementation you'll be set.

So the notation approach... let's see: Top Ten Tips to Using XPath and XPointer shows this example:

to match element declared with namespace like:

xmlns:book="http://my.example.org/namespaces/book"

you use XPath name like:

{http://my.example.org/namespaces/book}section

which hopefully is understood by Saxon (or Jaxen).

Finally, I would recommend upgrading to Saxon9 if possible, if you have any trouble using one of above solutions.