【问题标题】:saxreader validation fails when reading xml from java.io.Reader instead of providing path to xml file从 java.io.Reader 读取 xml 而不是提供 xml 文件的路径时,saxreader 验证失败
【发布时间】:2016-09-08 14:29:17
【问题描述】:

我有一个简单的 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 的 read 方法,它以 java.io.Reader 作为参数,像这样

reader.read(new FileReader("xml-files/contacts.xml"));

但我得到异常

org.dom4j.DocumentException:文档第 2 行出错:cvc-elt.1:找不到元素“联系人”的声明。嵌套异常:cvc-elt.1:找不到元素“联系人”的声明。

使用自定义实体解析器显示,在第一种情况下,xsd 文件是从路径 file:///e:/devel/xsd/xml-files/contacts.xsd 加载的,在第二种情况下是 file:///e:/ devel/xsd/contacts.xsd.

有什么方法可以将 xsd 文件所在的文件夹设置为 SAXReader?

【问题讨论】:

  • 我还没有尝试过这个,但是看看这个关于另一个问题的答案,看看在 SAXParserFactory 上设置架构是否适合你:stackoverflow.com/a/8282734/1423896
  • 这可行,但我不能使用它,因为可能有更多的 xml 文件并且它们可以有不同的 xsd。
  • 查看 SchemaFactory(docs.oracle.com/javase/7/docs/api/javax/xml/validation/…) 的 Javadoc。 newSchema(..) 方法接受 Source 数组。您也许可以将所有架构文件放入 SchemaFactory 以获取合并的 Schema 以设置您的 SaxParserFactory

标签: java xml xml-validation


【解决方案1】:

未经测试,但从我上面的 cmets 来看,这是我的想法:

    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);

【讨论】:

    【解决方案2】:

    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 的路径包含通向父文件夹 (../..) 等的相对路径的情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-03
      • 2018-04-26
      • 2019-06-23
      • 1970-01-01
      • 1970-01-01
      • 2019-05-18
      相关资源
      最近更新 更多