XML验证在使用本地文件作为schemaLocation时在Java中失败。

10 浏览
0 Comments

XML验证在使用本地文件作为schemaLocation时在Java中失败。

我正在尝试使用Java中的相对XSD文件验证一些XML。

输入文件temp.xml:




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 .
    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.xsd和file://./local_xsd_file.xsd(应该是可能的)作为schemaLocation,但结果都相同。如果我使用类似file:///full/path/to/local_xsd_file.xsd的“绝对路径”,它就可以工作。如果我使用模式位置的URL,则它会从该服务器读取并正常工作。

将当前工作目录更改为存在local_xsd_file.xsd的目录会使其工作,所以显然这只适用于相对于当前工作目录的路径?

在Java中是否可以使用相对路径进行验证?这似乎可能是一个实现细节?

0
0 Comments

问题的出现原因是在构建文档时,由于没有指定文档的基本URI,导致无法解析相对URI。在上述代码中,使用了builder.parse(new InputSource(new FileInputStream(filename)))方法来解析XML文件,但是这个方法无法获取到文件的基本URI。没有基本URI,解析器无法正确解析相对URI,可能会使用当前目录进行解析,或者报告错误。

解决方法是使用可以建立基本URI的parse()方法,例如parse(file.toString())saxParser.parse(file, (DefaultHandler) null);。这样可以确保解析器能够正确解析相对URI。

要解决在Java中使用schemaLocation本地文件进行XML验证失败的问题,需要使用可以建立基本URI的parse()方法来解析XML文件。这样可以确保解析器能够正确解析相对URI。

0
0 Comments

问题:在Java中使用schemaLocation验证XML时失败。

原因:出现此问题的原因可能是将外部模式文件转换为字符串导致的。需要避免这样的转换。

解决方法:

1. 避免将外部模式文件转换为字符串:

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

2. 可以使用内部模式而不必指定外部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);
}

3. 也可以自定义资源解析器,并告知其所需的子目录:

参考链接:https://stackoverflow.com/questions/2342808

4. 使用SAX解析器版本:

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

0