简体   繁体   English

解析时调用SAX error()处理程序方法,但未引发异常-为什么?

[英]SAX error() handler method called while parsing but no exception thrown — why?

I want to validate an XML file while it's being parsed. 我想在解析XML文件时对其进行验证。 Stand-alone validation with Validator.validate() says it's OK, no exception is thrown while parsing, but the [overridden] error() method from the parsing handler gets called. 使用Validator.validate()进行独立验证表示可以,在解析时不会引发任何异常,但是会调用解析处理程序中的[overridden] error()方法。 Why? 为什么? Is there some state I need to initialize? 是否需要初始化某些状态? If I deliberately make the XML file incorrect, stand-alone validation will fail and if I comment out validation, parsing also fails -- both with SAXParseException, and with the error I expected. 如果我故意使XML文件不正确,则独立验证将失败,并且如果我将验证注释掉,则解析也会失败-既发生SAXParseException,也发生预期的错误。

[code below edited down from actual stuff with lots of println's to illustrate the issue] [下面的代码从带有大量println的实际内容中进行了编辑以说明问题]

short.xsd: short.xsd:

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://www.myapp.com/sample"
           xmlns:smp="http://www.myapp.com/sample"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified">
  <xs:element name="Sample" type="xs:string"/>
</xs:schema>

short.xml: short.xml:

<?xml version="1.0"?>
<Sample
  xmlns="http://www.myapp.com/sample"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.myapp.com/sample shortxsd.xsd"
>
  hello
</Sample>

Source: 资源:

import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

public static void main(String... args)
      throws IOException
  {
    String xsdFileName = "shortxsd.xsd";
    URL xsdURL = Thread.currentThread().getContextClassLoader().getResource(xsdFileName);
    String xsdPath = xsdURL.getPath();
    System.out.println("xsdFileName: " + xsdFileName);
    System.out.println("xsdURL: " + xsdURL);
    System.out.println("xsdPath: " + xsdPath);

    String xmlFileName = "shortxml.xml";
    URL xmlURL = Thread.currentThread().getContextClassLoader().getResource(xmlFileName);
    String xmlPath = xmlURL.getPath();
    System.out.println("xmlFileName: " + xmlFileName);
    System.out.println("xmlURL: " + xmlURL);
    System.out.println("xmlPath: " + xmlPath);

    /* Schema creation: */
    SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Schema schema = null;
    try {
      schema = schemaFactory.newSchema(new File(xsdURL.getFile()));
    }
    catch (SAXException ex) {
      System.out.println("Schema creation exception: " + ex);
      return;
    }
    System.out.println("+ Schema creation OK");

    /* Stand-alone Validation: */
    Validator validator = schema.newValidator();
    Source xmlFile = new StreamSource(xmlURL.openStream());
    try {
      validator.validate(xmlFile);
    }
    catch (SAXException ex) {
      System.out.println("Validation exception: " + ex);
      return;
    }
    System.out.println("+ Stand-alone Validation OK");

    /* Parsing with validation: */
    SAXParserFactory parserFactory = SAXParserFactory.newInstance();
    parserFactory.setSchema(schema);
    SAXParser saxParser = null;
    try {
      saxParser = parserFactory.newSAXParser();
    }
    catch (ParserConfigurationException |
           SAXException ex) {
      System.out.println("Parser creation exception: " + ex);
      return;
    }
    System.out.println("+ Parser creation OK");

    try (InputStream xmlInput = xmlURL.openStream()) {
      saxParser.parse(xmlInput, new DefaultHandler()
                  {
                    @Override
                    public void error(SAXParseException e)
                    {
                      System.out.println("# Error: " + e);
                    }
      });
    }
    catch (SAXException ex) {
      System.out.println("Parsing exception: " + ex);
      return;
    }
    System.out.println("+ Parsing OK");
  }

Output: 输出:

xsdFileName: shortxsd.xsd
xsdURL: file:/.../target/classes/shortxsd.xsd
xsdPath: /.../target/classes/shortxsd.xsd
xmlFileName: shortxml.xml
xmlURL: file:/.../target/classes/shortxml.xml
xmlPath: /.../target/classes/shortxml.xml
+ Schema creation OK
+ Stand-alone Validation OK
+ Parser creation OK
# Error: org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 2; cvc-elt.1: Cannot find the declaration of element 'Sample'.
+ Parsing OK

You need to configure your SAX parser to be namespace-aware. 您需要将SAX解析器配置为可识别名称空间。

If you remove the xmlns="..." attribute from your XML document, and the xmlns:smp="..." and targetNamespace="..." attributes from your XML schema, your code does not produce any error messages. 如果从XML文档中删除xmlns="..."属性,并且从XML模式中删除xmlns:smp="..."targetNamespace="..."属性,则代码不会产生任何错误消息。 So the problem has to be something to do with namespaces. 因此,问题必须与名称空间有关。

To make the SAX parser namespace-aware, set an option in the factory: 要使SAX解析器能够识别名称空间,请在工厂中设置一个选项:

    /* Parsing with validation: */
    SAXParserFactory parserFactory = SAXParserFactory.newInstance();
    parserFactory.setNamespaceAware(true); // add this line
    parserFactory.setSchema(schema);

I made this change to your code and it printed out four OK messages at the end. 我对您的代码进行了更改,并在最后打印了四个OK消息。

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

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