java 使用 Java5 对 XSD 进行验证时出现问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/780811/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 13:45:38  来源:igfitidea点击:

Problem validating against an XSD with Java5

javaxmlvalidationxsd

提问by Guillaume

I'm trying to validate an Atom feed with Java 5 (JRE 1.5.0 update 11). The code I have works without problem in Java 6, but fails when running in Java 5 with a

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

org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'xml:base' to a(n) 'attribute declaration' component.

I think I remember reading something about the version of Xerces bundled with Java 5 having some problems with some schemas, but i cant find the workaround. Is it a known problem ? Do I have some error in my code ?

我想我记得读过一些关于与 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);
}

Update :I tried the method below, but I still have the same problem if I use Xerces 2.9.0. I also tried adding xml.xsd to the list of schemas (as xml:base is defined in xml.xsd) but this time I have

更新:我尝试了下面的方法,但如果我使用 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>.

Update 2:I tried to configure a proxy with the VM arguments -Dhttp.proxyHost=<proxy.host.com> -Dhttp.proxyPort=8080and now it works. I'll try to post a "real answer" from home.

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

and sorry, I cant reply as a comment : because of security reasons XHR is disabled from work ...

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

回答by Arjan

Indeed, people have been mentioning the Java 5 Sun provided SchemaFactory is giving troubles.

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

So: did you include Xerces in your project yourself?

那么:您自己在项目中包含了 Xerces 吗?

After including Xerces, you need to ensure it is being used. If you like to hardcode it (well, as a minimal requirement you'd probably use some application properties file to enable and populate the following code):

在包含 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);

Or, if you don't want to hardcode, or when your troublesome code would be in some 3rd party library that you cannot change, set it on the javacommand line or environment options. For example (on one line of course):

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

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

By the way: apart from the Sun included SchemaFactory implementation giving trouble (something like com.sun.org.apache.xerces.internal.jaxp.validation.xs.schemaFactoryImpl), it also seems that the "discovery" of non-JDK implementations fails in that version. If I understand correctly than, normally, just including Xerces would in fact make SchemaFactory#newInstancefind that included library, and give it precedence over the Sun implementation. To my knowledge, that fails as well in Java 5, making the above configuration required.

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

回答by Arjan

I tried to configure a proxy with the VM arguments -Dhttp.proxyHost=<proxy.host.com> -Dhttp.proxyPort=8080and now it works.

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

Ah, I didn't realize that xml.xsdis in fact the one referenced as http://www.w3.org/2001/xml.xsdor something like that. That should teach us to always show some XML and XSD fragments as well. ;-)

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

So, am I correct to assume that 1.) to fix the Java 5 issue, you still needed to include Xerces and set the system property, and that 2.) you did not have xml.xsdavailable locally?

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

Before you found your solution, did you happen to try using getResourcerather than getResourceAsStream, to see if the exception would then have showed you some more details?

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

If you actually did have xml.xsdavailable (so: if getResourcedid in fact yield a URL) then I wonder what Xerces was trying to fetch from the internet then. Or maybe you did not add that schema to the list prior to adding your own schemas? The order is important: dependencies must be added first.

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

For whoever gets tot his question using the search: maybe using a custom EntityResolvercould have indicated the source of the problem as well (if only writing something to the log and just returning nullto tell Xerces to use the default behavior).

对于使用搜索提出问题的任何人:也许使用自定义EntityResolver也可以指出问题的根源(如果只向日志写入一些内容并返回null告诉 Xerces 使用默认行为)。

回答by Arjan

Hmmm, just read your "comment" -- editing does not alert people for new replies, so time to ask your boss for some iPhone or some other gadget that is connected to the net directly ;-)

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

Well, I assume you added:

好吧,我假设您添加了:

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

If so, is xml.xsdactually to be found on the classpath then? I wonder if the getResourceAsStreamdid not yield nullin your case, and how new StreamSource(null)would act then.

如果是这样,xml.xsd实际上是在类路径上找到的吗?我想知道如果在你的情况下getResourceAsStream没有屈服null,那么new StreamSource(null)将如何行动。

Even if getResourceAsStreamdid not yield null, the resulting StreamSourcewould still not know where it was loaded from, which may be a problem when trying to include references. So, what if you use the constructor StreamSource(String systemId)instead:

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

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

You might also use StreamSource(InputStream inputStream, String systemId), but I don't see any advantage over the above two lines. However, the documentation explains why passing the systemId in either of the 2 constructors seems good:

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

This constructor allows the systemID to be set in addition to the input stream, which allows relative URIs to be processed.

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

Likewise, setSystemId(String systemId)explains a bit:

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

The system identifier is optional if there is a byte stream or a character stream, but it is still useful to provide one, since the application can use it to resolve relative URIs and can include it in error messages and warnings (the parser will attempt to open a connection to the URI only if there is no byte stream or character stream specified).

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

If this doesn't work out, then maybe some custom error handler can give you more details:

如果这不起作用,那么也许一些自定义错误处理程序可以为您提供更多详细信息:

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

...using the following ErrorHandler to capture the validation errors and continue parsing as far as possible:

...使用以下 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;
    }
}