java - 使用 JRE 1.5 和 JDK 1.6 时 DocumentBuilder.parse 的区别

标签 java xml parsing sax java-6

最近我们终于将项目切换到 Java 1.6。执行测试时,我发现使用 1.6 时不会抛出 SAXParseException,而使用 1.5 时会抛出。

下面是我的测试代码来演示这个问题。

import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.SchemaFactory;

import org.junit.Test;
import org.xml.sax.InputSource;
import org.xml.sax.SAXParseException;


/**
 * Test class to demonstrate the difference between JDK 1.5 to JDK 1.6.
 * 
 * Seen on Linux:
 * 
 * <pre>
 * #java version "1.6.0_18"
 * Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
 * Java HotSpot(TM) Server VM (build 16.0-b13, mixed mode)
 * </pre>
 * 
 * Seen on OSX:
 * 
 * <pre>
 * java version "1.6.0_17"
 * Java(TM) SE Runtime Environment (build 1.6.0_17-b04-248-10M3025)
 * Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01-101, mixed mode)
 * </pre>
 * 
 * @author dhiller (creator)
 * @author $Author$ (last editor)
 * @version $Revision$
 * @since 12.03.2010 11:32:31
 */
public class TestXMLValidation {

  /**
   * Tests the schema validation of an XML against a simple schema.
   * 
   * @throws Exception
   *           Falls ein Fehler auftritt
   * @throws junit.framework.AssertionFailedError
   *           Falls eine Unit-Test-Pruefung fehlschlaegt
   */
  @Test(expected = SAXParseException.class)
  public void testValidate() throws Exception {
    final StreamSource schema = new StreamSource( new StringReader( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
      + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" "
      + "elementFormDefault=\"qualified\" xmlns:xsd=\"undefined\">" + "<xs:element name=\"Test\"/>" + "</xs:schema>" ) );
    final String xml = "<Test42/>";
    final DocumentBuilderFactory newFactory = DocumentBuilderFactory.newInstance();
    newFactory.setSchema( SchemaFactory.newInstance( "http://www.w3.org/2001/XMLSchema" ).newSchema( schema ) );
    final DocumentBuilder documentBuilder = newFactory.newDocumentBuilder();
    documentBuilder.parse( new InputSource( new StringReader( xml ) ) );
  }

}

当使用 JVM 1.5 时测试通过,在 1.6 上它失败并出现“预期异常 SAXParseException”。

DocumentBuilderFactory.setSchema(Schema) 的 Javadoc方法说:

When errors are found by the validator, the parser is responsible to report them to the user-specified ErrorHandler (or if the error handler is not set, ignore them or throw them), just like any other errors found by the parser itself. In other words, if the user-specified ErrorHandler is set, it must receive those errors, and if not, they must be treated according to the implementation specific default error handling rules.

DocumentBuilder.parse(InputSource) 的 Javadoc方法说:

顺便说一句:我尝试通过 setErrorHandler 设置错误处理程序,但仍然没有异常(exception)。

现在我的问题:

在 1.6 中有什么变化阻止模式验证抛出 SAXParseException?它与模式或我尝试解析的 xml 相关吗?

更新:

如我所愿,以下代码适用于 1.5 和 1.6:

  @Test(expected = SAXParseException.class)
  public void testValidate() throws Exception {
    final StreamSource schema = new StreamSource( new StringReader( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
      + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" "
      + "elementFormDefault=\"qualified\" xmlns:xsd=\"undefined\">" + "<xs:element name=\"Test\"/>" + "</xs:schema>" ) );
    final String xml = "<Test42/>";
    final DocumentBuilderFactory newFactory = DocumentBuilderFactory.newInstance();
    final Schema newSchema = SchemaFactory.newInstance( "http://www.w3.org/2001/XMLSchema" ).newSchema( schema );
    newFactory.setSchema( newSchema );
    final Validator newValidator = newSchema.newValidator();
    final Source is = new StreamSource( new StringReader( xml ) );
    try {
      newValidator.validate( ( Source ) is );
    }
    catch ( Exception e ) {
      e.printStackTrace();
      throw e;
    }
    final DocumentBuilder documentBuilder = newFactory.newDocumentBuilder();
    documentBuilder.parse( new InputSource( new StringReader( xml ) ) );
  }

解决方案似乎是明确使用从架构实例创建的 validator 实例。 我找到了解决方案 here

我仍然不确定为什么会这样......

最佳答案

显然,不符合模式的文档只值得默认错误处理程序对 stderr 进行温和的谴责。我的解决方案是用更严格的错误处理程序替换默认错误处理程序:

// builder is my DocumentBuilder
builder.setErrorHandler(new ErrorHandler() {
    @Override
    public void error(SAXParseException arg0) throws SAXException {
        throw arg0;             
    }

    @Override
    public void fatalError(SAXParseException arg0) throws SAXException {
        throw arg0;                 
    }

    @Override
    public void warning(SAXParseException arg0) throws SAXException {
        throw arg0;                 
    }
});

关于java - 使用 JRE 1.5 和 JDK 1.6 时 DocumentBuilder.parse 的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2432507/

相关文章:

java - 循环尝试删除 Firebase 数据库上的帐户

java - 为 tomcat 重写 URL

android - Android Studio 中的应用程序 - 不显示 XML 布局

c# - 如何在 C# 中解析字符串(以逗号和结尾的符号,即 "3,246,928-")?

c# - C#中如何获取JSON中的值?

css - Lemon Parser Generator 的二义性语法

java - 通过 DAS 在独立 Glassfish 上配置自定义登录领域和模块

java - 将患者添加到我实现的链表类中

java - 如何使用 TwitterObjectFactory.jsonStoreEnabled 获取 JSON 格式的推文?

php - 如何将 XML 文件转换为 SimpleXMLElement() 数组?