Hello,

I'm making an attempt to update XMLC ( http://xmlc.enhydra.org/ ) to Xerces2 from Xerces (XMLC has dependencies on the Xerces1 implementation classes for various valid reasons that I won't go into here). Along with that move, I lose native Xerces1 support for XCatalogs. I realize it's the old catalog format, but it's been that way forever and XMLC needs to continue to support it. However, as I've found out, XCatalog support in the resolver package is less than useful. Here's a few reasons why. Enjoy!...

1. When registered via SAXCatalogReader.setCatalogParser(String, String, String), the XCatalogReader will never be successfully instantiated via Class.forName() because it doesn't have a default constructor. You might also notice that this is the default way that Catalog.setupReaders() is implemented. OASISXMLCatalogReader has a default constructor and doesn't suffer from this problem.

2. Even if XCatalogReader had a default constructor so it could be successfully instantiated via reflection, it would fail to be found as a registered catalog parser because of a bad assumption. In Catalog.setupReaders(), the XCatalog parser is setup like this...

saxReader.setCatalogParser(null, "XMLCatalog",
                               
"org.apache.xml.resolver.readers.XCatalogReader");

Notice that null is passed for the namespaceURI. Now, here's the method in SAXCatalogReader...

public void setCatalogParser(String namespaceURI,
                               String rootElement,
                               String parserClass) {
    if (namespaceURI == null) {
      namespaceMap.put(rootElement, parserClass);
    } else {
      namespaceMap.put("{"+namespaceURI+"}"+rootElement, parserClass);
    }
  }

So, when null is passed as the namespaceURI, it uses only the rootElement as the key in the Map. The corresponding logic is done in getCatalogParser(String, String). So far, so good. However, in SAXCatalogParser.startElement(String, String, String, Attributes), when the parser is being initialized for the first time, it looks up the parser via getCatalogParser(String, String) always passing a non-null namespaceURI argument (I guess because the XML parser uses an empty string instead of null for a missing namespaceURI?). So, the assumption made in set/getCatalogParser() falls flat on its face for XCatalogReader. It will never be found because it was registered in the map with the key "XMLCatalog", but when it is looked up, it will always attempt to use the key "{}XMLCatalog", which will never exist.

3. Now lets say both 1 and 2 are fixed. Well, XCatalogReader assumes a root element of "XMLCatalog". The javadoc says it supports the "XML Catalog format developed by John Cowan and supported by Apache". Well, it was supported by Apache in Xerces1. Except the DTD supplied there defines "XCatalog" as the root element, not "XMLCatalog". This is not good for users of that DTD since the document will never validate against what XCatalogReader expects. See the Xerces1 javadoc for XCatalog.java and the xcatalog.dtd for proof of this...

http://xerces.apache.org/xerces-j/apiDocs/org/apache/xerces/readers/XCatalog.html

http://svn.apache.org/viewcvs.cgi/xerces/java/branches/xerces_j_1/src/org/apache/xerces/readers/xcatalog.dtd?rev=317487&view=markup


4. Let's say that 1 and 2 are a lost cause and we'll just ignore 3 by changing our root element to "XMLCatalog" in the XML and update the DTD to match this... or just stop referencing the DTD altogether to get around this problem (BTW, this is not an option for XMLC. It needs to be "XCatalog" so that it matches the DTD which, it seems to me, ought to be distributed with resolver.jar just like the other catalog dtd, no?). We just instantiate XCatalogReader directly and add it to the Catalog ourselves....

catalog.addReader("application/xml", new XCatalogReader(spf));

Then, we try it out. Low and behold, it bombs out with a NullPointerException in startElement(String, String, String, Attributes) after parsing the first child entry of the root "XMLCatalog" element in my catalog, which is "Map" (I know this by subclassing XCatalogReader and implementing startElement(), doing some debugging, and then passing on execution to super.startElement()). I'm not 100% sure exactly which line it blows chunks on because the classes in resovler.jar, distributed with Xerces-2.7.1, didn't have have debug enabled when compiling (does the pain ever stop?), but it is somewhere in here...

} else if (localName.equals("Map")) {
      entryType = catalog.PUBLIC;
      entryArgs.add(atts.getValue("PublicId"));
      entryArgs.add(atts.getValue("HRef"));

      catalog.getCatalogManager().debug.message(4, "Map",
                    PublicId.normalize(atts.getValue("PublicId")),
                    atts.getValue("HRef"));
} else ....


I suspect that the catalog is null for some reason, although I tried to hack it up and set the catalog in my implementation of startElement() before passing on execution to super.startElement(), but that didn't seem to help? Maybe someone else can say?


So..... I guess the question is, did anyone actually test the functionality of XCatalogReader? I'll take a wild guess at the answer. No! Why? Because it's quite simply impossible for it to have passed any test, as I've shown above.

Will this be fixed in the next release? I think Xerces-2.8.0 is going to be shipping in not too long, and it would be ever so nice if resolver.jar contained an XCatalogReader actually worked as advertised. Please forgive the sharp tongue. I tried to keep things relatively lighthearted, but I also wanted to convey a hint of bitterness after attempting, on and off, for a full day to get this to work, finally figuring out all the issues that I detailed above. In any case, I hope my descriptions are useful in mapping out how to fix the existing problems.

thanks!

Jake


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to