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]