Why am I getting "MalformedURLException: no protocol" when using SAXParser?
I'm copying code from one part of our application (an applet) to inside the app. I'm parsing XML as a String. It's been awhile since I parsed XML, but from the error that's thrown it looks like it might have to do with not finding the .dtd. The stack trace makes it difficult to find the exact cause of the error, but here's the message:
java.net.MalformedURLException: no protocol: <a href="http://www.mycomp.com/MyComp.dtd">http://www.mycomp.com/MyComp.dtd</a>
and the XML has this as the first couple lines:
<?xml version='1.0'?>
<!DOCTYPE MYTHING SYSTEM '<a href="http://www.mycomp.com/MyComp.dtd">http://www.mycomp.com/MyComp.dtd</a>'>
and here's the relevant code snippets
class XMLImportParser extends DefaultHandler {
private SAXParser m_SaxParser = null;
private String is_InputString = "";
XMLImportPars开发者_如何学运维er(String xmlStr) throws SAXException, IOException {
super();
is_InputString = xmlStr;
createParser();
try {
preparseString();
parseString(is_InputString);
} catch (Exception e) {
throw new SAXException(e); //"Import Error : "+e.getMessage());
}
}
void createParser() throws SAXException {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
try {
factory.setFeature("http://xml.org/sax/features/namespaces", true);
factory.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
m_SaxParser = factory.newSAXParser();
m_SaxParser.getXMLReader().setFeature("http://xml.org/sax/features/namespaces", true);
m_SaxParser.getXMLReader().setFeature("http://xml.org/sax/features/namespace-prefixes", true);
} catch (SAXNotRecognizedException snre){
throw new SAXException("Failed to create XML parser");
} catch (SAXNotSupportedException snse) {
throw new SAXException("Failed to create XML parser");
} catch (Exception ex) {
throw new SAXException(ex);
}
}
void preparseString() throws SAXException {
try {
InputSource lSource = new InputSource(new StringReader(is_InputString));
lSource.setEncoding("UTF-8");
m_SaxParser.parse(lSource, this);
} catch (Exception ex) {
throw new SAXException(ex);
}
}
}
It looks like the error is happening in the preparseString() method, on the line that actually does the parsing, the m_SaxParser.parse(lSource, this);
line.
FYI, the 'MyComp.dtd' file does exist at that location and is accessible via http. The XML file comes from a different service on the server, so I can't change it to a file:// format and put the .dtd file on the classpath.
I think you have some extra code in the XML declaration. Try this:
<?xml version='1.0'?>
<!DOCTYPE MYTHING SYSTEM "http://www.mycomp.com/MyComp.dtd">
The above was captured from the W3C Recommendations: http://www.w3.org/QA/2002/04/valid-dtd-list.html
You can use the http link to set the Schema on the SAXParserFactory before creating your parser.
void createParser() throws SAXException {
Schema schema = SchemaFactory.newSchema(new URL("http://www.mycomp.com/MyComp.dtd"));
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
factory.setSchema(schema);
The problem is that this:
<a href="http://www.mycomp.com/MyComp.dtd">http://www.mycomp.com/MyComp.dtd</a>
is an HTML hyperlink, not a URL. Replace it with this:
http://www.mycomp.com/MyComp.dtd
Since this XML comes from an external source, the first thing to do would be to complain to them that they are sending invalid XML.
As a workaround, you can set an EntityResolver on your parser that compares the SystemId to this invalid url and returns a correct http url:
m_SaxParser.getXMLReader().setEntityResolver(
new EntityResolver() {
public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException {
if ("<a href=\"http://www.mycomp.com/MyComp.dtd\">http://www.mycomp.com/MyComp.dtd</a>".equals(systemId)) {
return new InputSource("http://www.mycomp.com/MyComp.dtd");
} else {
return null;
}
}
}
);
精彩评论