使用Java5验证XSD的问题

时间:2009-04-23 08:38:05

标签: java xml validation xsd

我正在尝试使用Java 5验证Atom提要(JRE 1.5.0更新11)。我在Java 6中使用的代码没有问题,但在使用

的Java 5中运行时失败了
org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'xml:base' to a(n) 'attribute declaration' component.

我想我记得读过一些与Java 5捆绑在一起的Xerces版本,但是我遇到了一些模式,但我找不到解决方法。这是一个已知的问题吗?我的代码中有错误吗?

public static void validate() throws SAXException, IOException {
    List<Source> schemas = new ArrayList<Source>();
    schemas.add(new StreamSource(AtomValidator.class.getResourceAsStream("/atom.xsd")));
    schemas.add(new StreamSource(AtomValidator.class.getResourceAsStream("/dc.xsd")));

    // Lookup a factory for the W3C XML Schema language
    SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

    // Compile the schemas.
    Schema schema = factory.newSchema(schemas.toArray(new Source[schemas.size()]));
    Validator validator = schema.newValidator();

    // load the file to validate
    Source source = new StreamSource(AtomValidator.class.getResourceAsStream("/sample-feed.xml"));

    // check the document
    validator.validate(source);
}

更新:我尝试了下面的方法,但如果我使用Xerces 2.9.0,我仍会遇到同样的问题。我也尝试将xml.xsd添加到模式列表中(因为xml:base是在xml.xsd中定义的)但这次我有

Exception in thread "main" org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document 'null', 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>.

更新2:我尝试使用VM参数-Dhttp.proxyHost=<proxy.host.com> -Dhttp.proxyPort=8080配置代理,现在可以正常工作了。我会尝试在家里发布一个“真正的答案”。

抱歉,我无法作为评论回复:由于安全原因,XHR已停止工作......

3 个答案:

答案 0 :(得分:3)

事实上,人们一直在提到Java 5 Sun提供的SchemaFactory给出了麻烦。

所以:你自己在项目中包含了Xerces吗?

包含Xerces后,您需要确保使用它。如果您想对其进行硬编码(嗯,作为最低要求,您可能会使用一些应用程序属性文件来启用和填充以下代码):

String schemaFactoryProperty = 
  "javax.xml.validation.SchemaFactory:" + XMLConstants.W3C_XML_SCHEMA_NS_URI;

System.setProperty(schemaFactoryProperty,
   "org.apache.xerces.jaxp.validation.XMLSchemaFactory");

SchemaFactory factory = 
  SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

或者,如果您不想进行硬编码,或者您的某些第三方库无法更改麻烦的代码,请在java命令行或环境选项中进行设置。例如(当然在一行上):

set JAVA_OPTS = 
  "-Djavax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema
  =org.apache.xerces.jaxp.validation.XMLSchemaFactory"

顺便说一句:除了Sun包含SchemaFactory实现给出麻烦(类似com.sun.org.apache.xerces.internal.jaxp.validation.xs.schemaFactoryImpl)之外,似乎非JDK实现的“发现”在该版本中失败。如果我理解正确,通常只是包含Xerces实际上会使SchemaFactory#newInstance找到包含库,并优先于Sun实现。据我所知,这在Java 5中也失败了,需要进行上述配置。

答案 1 :(得分:1)

  

我尝试使用VM参数-Dhttp.proxyHost=<proxy.host.com> -Dhttp.proxyPort=8080配置代理,现在它可以正常工作。

啊,我没有意识到xml.xsd实际上是http://www.w3.org/2001/xml.xsd引用的那个或类似的东西。这应该教会我们总是展示一些XML和XSD片段。 ; - )

所以,我是否正确地假设1.)要修复Java 5问题,你仍然需要包含Xerces并设置系统属性,那2.)你没有xml.xsd在本地可用?

在您找到解决方案之前,您是否碰巧尝试使用getResource而不是getResourceAsStream来查看该异常是否会向您展示更多详细信息?

如果你确实有xml.xsd可用(所以:如果getResource确实产生了一个URL),那么我想知道Xerces试图从互联网上获取的是什么。或者您可能在添加自己的架构之前没有将该架构添加到列表中?顺序很重要:必须首先添加依赖项。

对于使用搜索获得他的问题的人:也许使用自定义EntityResolver也可以指出问题的根源(如果只是在日志中写入内容并且只返回null来告诉Xerces使用默认行为。)

答案 2 :(得分:0)

嗯,只是看了你的“评论” - 编辑没有提醒人们新的回复,所以有时间向你的老板询问一些iPhone或其他直接连接到网络的小工具; - )

好吧,我假设你补充说:

schemas.add(
  new StreamSource(AtomValidator.class.getResourceAsStream("/xml.xsd")));

如果是,那么实际上是否可以在类路径中找到xml.xsd?我想知道getResourceAsStream在你的案例中是否没有产生null,以及new StreamSource(null)将如何行动。

即使getResourceAsStream没有产生null,结果StreamSource仍然不知道从哪里加载,这在尝试包含引用时可能是个问题。那么,如果您使用构造函数StreamSource(String systemId),那该怎么办:

schemas.add(new StreamSource(AtomValidator.class.getResource("/atom.xsd")));
schemas.add(new StreamSource(AtomValidator.class.getResource("/dc.xsd")));

您也可以使用StreamSource(InputStream inputStream, String systemId),但我认为上述两行没有任何优势。但是,文档解释了为什么在2个构造函数中传递systemId似乎很好:

  

此构造函数允许在输入流之外设置systemID,从而允许处理相对URI。

同样,setSystemId(String systemId)解释了一下:

  

如果存在字节流或字符流,系统标识符是可选的,但提供一个字符串仍然很有用,因为应用程序可以使用它来解析相对URI并将其包含在错误消息和警告中(解析器)只有在没有指定字节流或字符流时才会尝试打开与URI的连接。

如果这不成功,那么可能一些自定义错误处理程序可以为您提供更多详细信息:

ErrorHandlerImpl errorHandler = new ErrorHandlerImpl();
validator.setErrorHandler(errorHandler);
:
:
validator.validate(source);

if(errorHandler.hasErrors()){
    LOG.error(errorHandler.getMessages());
    throw new [..];
}
if(errorHandler.hasWarnings()){
    LOG.warn(errorHandler.getMessages());
}

...使用以下ErrorHandler捕获验证错误并尽可能继续解析:

import org.xml.sax.helpers.DefaultHandler;
private class ErrorHandlerImpl extends DefaultHandler{
    private String messages = "";
    private boolean validationError = false;
    private boolean validationWarning = false;

    public void error(SAXParseException exception) throws SAXException{
        messages += "Error: " + exception.getMessage() + "\n";
        validationError = true;
    }

    public void fatalError(SAXParseException exception) throws SAXException{
        messages += "Fatal: " + exception.getMessage();
        validationError = true;
    }

    public void warning(SAXParseException exception) throws SAXException{
        messages += "Warn: " + exception.getMessage();
        validationWarning = true;
    }

    public boolean hasErrors(){
        return validationError;
    }

    public boolean hasWarnings(){
        return validationWarning;
    }

    public String getMessages(){
        return messages;
    }
}