【问题标题】:XML validation failing in java with schemaLocation a local filejava中的XML验证失败,schemaLocation是本地文件
【发布时间】:2018-04-26 15:43:42
【问题描述】:

我正在尝试根据 java 中的相关 XSD 文件验证一些 XML

输入文件 temp.xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<tagname:b
        xmlns:tagname="http://my_namespace.org/v1"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://my_namespace.org/v1 ./local_xsd_file.xsd">
</tagname>

java源码:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
factory.setNamespaceAware(true);
factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new RaiseOnErrorHandler());
builder.parse(new InputSource(new FileInputStream(filename)));

public static class RaiseOnErrorHandler implements ErrorHandler {
  public void warning(SAXParseException e) throws SAXException {
    throw new RuntimeException(e);
  }
  public void error(SAXParseException e) throws SAXException {
    throw new RuntimeException(e);
  }
  public void fatalError(SAXParseException e) throws SAXException {
    throw new RuntimeException(e);
  }
}

本地文件local_xsd_file.xsd 存在,似乎未被读取。

错误信息

java.lang.RuntimeException: org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 85; schema_reference.4: Failed to read schema document './local_xsd_file.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
    at org.XX$RaiseOnErrorHandler.warning(DigitalFileWriterTest.java:1114)
    at org.apache.xerces.util.ErrorHandlerWrapper.warning(Unknown Source)
    at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
    at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
    at org.apache.xerces.impl.xs.traversers.XSDHandler.reportSchemaWarning(Unknown Source)
    at org.apache.xerces.impl.xs.traversers.XSDHandler.getSchemaDocument(Unknown Source)
    at org.apache.xerces.impl.xs.traversers.XSDHandler.parseSchema(Unknown Source)
    at org.apache.xerces.impl.xs.XMLSchemaLoader.loadSchema(Unknown Source)
    at org.apache.xerces.impl.xs.XMLSchemaValidator.findSchemaGrammar(Unknown Source)
    at org.apache.xerces.impl.xs.XMLSchemaValidator.handleStartElement(Unknown Source)
    at org.apache.xerces.impl.xs.XMLSchemaValidator.startElement(Unknown Source)
    at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
    at org.apache.xerces.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
    at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
    at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source)
    ... 50 more

我也尝试过使用file://local_xsd_file.xsdfile://./local_xsd_file.xsd(其中shouldpossible)作为schemaLocation,结果都一样。如果我使用像file:///full/path/to/local_xsd_file.xsd 这样的“绝对路径”,那么它可以工作。如果我使用架构位置的 URL,它会从该服务器读取它们并且工作正常。

将我当前的工作目录更改为 local_xsd_file.xsd 存在的目录将使其工作,所以显然这有效但仅相对于您当前的工作目录?

是否可以在 java 中使用带有验证的相对路径?感觉像是一个实现细节?

【问题讨论】:

    标签: java xml validation xsd


    【解决方案1】:

    当您构建这样的文档时:

    DocumentBuilder builder = factory.newDocumentBuilder();
    builder.setErrorHandler(new RaiseOnErrorHandler());
    builder.parse(new InputSource(new FileInputStream(filename)));
    

    文档的基本 URI 未知(因为构建器只能看到 InputStream,并且无法发现它正在读取特定文件)。尝试使用可以建立基本 URI 的 parse() 方法之一,例如parse(file.toString())saxParser.parse(file, (DefaultHandler) null);

    没有基本 URI,就没有明智的方法来解析相对 URI。系统可能会使用当前目录(这似乎发生在这里)或者它可能会报告错误。

    【讨论】:

      【解决方案2】:

      对于追随者,如果您使用外部架构文件进行验证,这似乎也是可能的,只是避免先将其更改为字符串,例如:

      public static void verifyMatchesXsd(File xmlFileToTest, File schemaFile) throws IOException, SAXException {
          Source xmlFile = new StreamSource(xmlFileToTest);
          SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
          Schema schema = schemaFactory.newSchema(schemaFile);
          javax.xml.validation.Validator validator = schema.newValidator();
          validator.validate(xmlFile);
      }
      

      或版本,无需指定外部 XSD 在哪里(它使用内部):

        private void assertMatchesAnyXsdsMentioned(File xmlFileLocation) throws SAXException, IOException {
          SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
          Schema schema = schemaFactory.newSchema();
          Validator validator = schema.newValidator();
          Source xmlSource = new StreamSource(xmlFileLocation);
          validator.validate(xmlSource);
        }
      

      您也许还可以指定自己的 resource resolver 并让它也知道您想要哪个子目录...

      萨克斯解析器版本:

        static void assertMatchesInternalXsd(File inputFile) throws Exception {
          SAXParserFactory spf = SAXParserFactory.newInstance();
          spf.setValidating(true);
          spf.setNamespaceAware(true);
          SAXParser saxParser = spf.newSAXParser();
          saxParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
          XMLReader reader = saxParser.getXMLReader();
          reader.setErrorHandler(new RaiseOnErrorHandler());
          saxParser.parse(inputFile, (DefaultHandler) null);
        }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-21
        • 2021-11-10
        • 1970-01-01
        • 1970-01-01
        • 2010-11-08
        • 1970-01-01
        • 2011-12-26
        • 2019-06-23
        相关资源
        最近更新 更多