简体   繁体   English

使用JRE 1.5和JDK 1.6时DocumentBuilder.parse的差异

[英]Difference in DocumentBuilder.parse when using JRE 1.5 and JDK 1.6

Recently at last we have switched our projects to Java 1.6. 最近我们最终将项目转换为Java 1.6。 When executing the tests I found out that using 1.6 a SAXParseException is not thrown which has been thrown using 1.5. 在执行测试时,我发现使用1.6时,不会抛出使用1.5抛出的SAXParseException。

Below is my test code to demonstrate the problem. 下面是我的测试代码来演示这个问题。

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

}

When using a JVM 1.5 the test passes, on 1.6 it fails with "Expected exception SAXParseException". 当使用JVM 1.5时,测试通过,在1.6上它失败并出现“Expected exception SAXParseException”。

The Javadoc of the DocumentBuilderFactory.setSchema(Schema) Method says: 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. 当验证程序发现错误时,解析器负责将它们报告给用户指定的ErrorHandler(或者如果未设置错误处理程序,则忽略它们或抛出它们),就像解析器本身找到的任何其他错误一样。 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. 换句话说,如果设置了用户指定的ErrorHandler,它必须接收这些错误,如果没有,则必须根据特定于实现的默认错误处理规则来处理它们。

The Javadoc of the DocumentBuilder.parse(InputSource) method says: DocumentBuilder.parse(InputSource)方法的Javadoc说:

BTW: I tried setting an error handler via setErrorHandler , but there still is no exception. BTW:我尝试通过setErrorHandler设置错误处理程序,但仍然没有异常。

Now my question: 现在我的问题:

What has changed to 1.6 that prevents the schema validation to throw a SAXParseException? 什么已更改为1.6,阻止架构验证抛出SAXParseException? Is it related to the schema or to the xml that I tried to parse? 它与我试图解析的模式或xml有关吗?

Update: 更新:

The following code works on 1.5 and 1.6 as I've been desiring: 以下代码适用于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 ) ) );
  }

The solution seems to be to explicitly using a Validator instance created from the Schema instance. 解决方案似乎是显式使用从Schema实例创建的Validator实例。 I've found the solution here 我在这里找到了解决方案

Still I'm not sure why that is... 我还不确定那是为什么......

Apparently, a document not complying with the schema only merits a mild rebuke on stderr from the default error handler. 显然,不符合模式的文档只能对默认错误处理程序中的stderr进行温和的谴责。 My solution was to replace the default error handler with a stricter one: 我的解决方案是用更严格的错误处理程序替换默认错误处理程序:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM