tags:

views:

433

answers:

4

I have an xml file ('videofaq.xml') that defines a DTD using the following DOCTYPE

<!DOCTYPE video-faq SYSTEM "videofaq.dtd">

I am loading the file from the classpath (from a JAR actually) at Servlet initialization time using:

getClass().getResourceAsStream("videofaq.xml")

The XML is found correctly, but for the DTD in the same package, Xerces gives me a FileNotFoundException, and displays the path to the Tomcat startup script with "videofaq.dtd" appended to the end. What hints, if any, can I pass on to Xerces to make it load the DTD properly?

+1  A: 

When you do

getClass().getResourceAsStream("videofaq.xml")

It's not xerces you are calling and as such, when you give the stream to xerces, it can't know where the file is loaded from. It loads it from the application root path (which you have described).

A simple solution would be to specify the whole path in your xml file to the dtd.

Also, xerces seems to try multiple places. So you should have a look at the grammar caching mecanism or the entity resolvers (which are used in that order I think).

Xerces grammar doc: http://xerces.apache.org/xerces2-j/faq-grammars.html

Xerces features use-entity-resolver2: http://xerces.apache.org/xerces2-j/features.html

Loki
A: 

When using SAX you can provide your own EntityResolver which then loads the resource any way you want.

Joachim Sauer
A: 

In general, try to use the method overloads that take a URL (usually as a String with a parameter name like "systemId") when specifying input for an XML parser. This allows the parser to resolve relative references for you, and provide better error messages.

So, in your case, locate the DTD in the same package with videofaq.xml, and pass the String result of getClass().getResource("videofaq.xml") to the XML parser.

erickson
+1  A: 

A custom EntityResolver will work, but you might be able to avoid having to create a custom class by setting a SystemID to allow the processor to "find" relative paths.

http://www.onjava.com/pub/a/onjava/excerpt/java_xslt_ch5/index.html?page=5

By providing a system identifier as a parameter to the StreamSource, you are telling the XSLT processor where to look for commonFooter.xslt. Without this parameter, you may encounter an error when the processor cannot resolve this URI. The simple fix is to call the setSystemId( ) method as follows:

// construct a Source that reads from an InputStream
Source mySrc = new StreamSource(anInputStream);
// specify a system ID (a String) so the 
// Source can resolve relative URLs
// that are encountered in XSLT stylesheets
mySrc.setSystemId(aSystemId);
Mads Hansen