从 java.io.Reader 读取 xml 而不是提供 xml 文件的路径时,saxreader 验证失败
saxreader validation fails when reading xml from java.io.Reader instead of providing path to xml file
我有简单的 xml 文件 contacts.xml 位于实际文件夹的子文件夹 xml-files 中。
<contacts xsi:noNamespaceSchemaLocation="contacts.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<contact>
<firstname>AAA</firstname>
<lastname>BBB</lastname>
</contact>
</contacts>
架构文件也位于子文件夹 xml-files.
解析文件的代码:
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
SAXParser parser = factory.newSAXParser();
parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
SAXReader reader = new SAXReader(parser.getXMLReader());
reader.setValidation(true);
reader.read("xml-files/contacts.xml");
我想像这样使用 SAXReader 的读取方法,它以 java.io.Reader 作为参数
reader.read(new FileReader("xml-files/contacts.xml"));
但我遇到异常
org.dom4j.DocumentException:文档第 2 行错误:cvc-elt.1:找不到元素 'contacts' 的声明。嵌套异常:cvc-elt.1:找不到元素 'contacts'.
的声明
使用自定义实体解析器显示,在第一种情况下,xsd 文件是从路径 file:///e:/devel/xsd/xml-files/contacts.xsd 加载的,在第二种情况下,文件是:/ //e:/devel/xsd/contacts.xsd.
有什么方法可以将 xsd 文件所在的文件夹设置为 SAXReader?
未经测试,但根据我上面的评论,这就是我的想法:
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
SchemaFactory schemafactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Source[] sources = new Source[] {
new StreamSource(new File("path/to/schema1.xsd")),
new StreamSource(new File("path/to/schema2.xsd")),
new StreamSource(new File("path/to/schema3.xsd")),
new StreamSource(new File("path/to/schema4.xsd")),
};
Schema sc = schemafactory.newSchema(sources);
factory.setSchema(sc);
SAXParser parser = factory.newSAXParser();
parser.parse(file, handler);
受到Java: How to prevent 'systemId' in EntityResolver#resolveEntity(String publicId, String systemId) from being absolutized to current working directory的启发,我使用了自己的 EntityResolver2 实现
private static class EntityResolver2Impl implements EntityResolver2 {
private File xmlFile;
public EntityResolver2Impl(File xmlFile) {
this.xmlFile = xmlFile;
}
@Override
public InputSource getExternalSubset(String name, String baseURI) throws SAXException, IOException {
return null;
}
@Override
public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId) throws SAXException, IOException {
File entityPath = new File(xmlFile.getParent(), systemId);
return new InputSource(new FileReader(entityPath));
}
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
return null;
}
}
调用代码如下所示
File xmlFile = new File("xml-files/contacts.xml");
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
SAXParser parser = factory.newSAXParser();
parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
SAXReader reader = new SAXReader(parser.getXMLReader());
reader.setEntityResolver(new EntityResolver2Impl(xmlFile));
reader.setValidation(true);
reader.read(new FileReader(xmlFile));
此代码还可以处理 xsd 的路径包含指向父文件夹 (../..) 等的相对路径的情况
我有简单的 xml 文件 contacts.xml 位于实际文件夹的子文件夹 xml-files 中。
<contacts xsi:noNamespaceSchemaLocation="contacts.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<contact>
<firstname>AAA</firstname>
<lastname>BBB</lastname>
</contact>
</contacts>
架构文件也位于子文件夹 xml-files.
解析文件的代码:
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
SAXParser parser = factory.newSAXParser();
parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
SAXReader reader = new SAXReader(parser.getXMLReader());
reader.setValidation(true);
reader.read("xml-files/contacts.xml");
我想像这样使用 SAXReader 的读取方法,它以 java.io.Reader 作为参数
reader.read(new FileReader("xml-files/contacts.xml"));
但我遇到异常
org.dom4j.DocumentException:文档第 2 行错误:cvc-elt.1:找不到元素 'contacts' 的声明。嵌套异常:cvc-elt.1:找不到元素 'contacts'.
的声明使用自定义实体解析器显示,在第一种情况下,xsd 文件是从路径 file:///e:/devel/xsd/xml-files/contacts.xsd 加载的,在第二种情况下,文件是:/ //e:/devel/xsd/contacts.xsd.
有什么方法可以将 xsd 文件所在的文件夹设置为 SAXReader?
未经测试,但根据我上面的评论,这就是我的想法:
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
SchemaFactory schemafactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Source[] sources = new Source[] {
new StreamSource(new File("path/to/schema1.xsd")),
new StreamSource(new File("path/to/schema2.xsd")),
new StreamSource(new File("path/to/schema3.xsd")),
new StreamSource(new File("path/to/schema4.xsd")),
};
Schema sc = schemafactory.newSchema(sources);
factory.setSchema(sc);
SAXParser parser = factory.newSAXParser();
parser.parse(file, handler);
受到Java: How to prevent 'systemId' in EntityResolver#resolveEntity(String publicId, String systemId) from being absolutized to current working directory的启发,我使用了自己的 EntityResolver2 实现
private static class EntityResolver2Impl implements EntityResolver2 {
private File xmlFile;
public EntityResolver2Impl(File xmlFile) {
this.xmlFile = xmlFile;
}
@Override
public InputSource getExternalSubset(String name, String baseURI) throws SAXException, IOException {
return null;
}
@Override
public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId) throws SAXException, IOException {
File entityPath = new File(xmlFile.getParent(), systemId);
return new InputSource(new FileReader(entityPath));
}
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
return null;
}
}
调用代码如下所示
File xmlFile = new File("xml-files/contacts.xml");
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
SAXParser parser = factory.newSAXParser();
parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
SAXReader reader = new SAXReader(parser.getXMLReader());
reader.setEntityResolver(new EntityResolver2Impl(xmlFile));
reader.setValidation(true);
reader.read(new FileReader(xmlFile));
此代码还可以处理 xsd 的路径包含指向父文件夹 (../..) 等的相对路径的情况