如何在SAXParseException中获取XML元素信息

问题描述:

在标准Java环境中针对xsd模式验证xml源时,我无法找到获取有关未通过验证的元素(在许多特定情况下)的信息的方法。如何在SAXParseException中获取XML元素信息

当捕获一个SAXParseException时,元素的信息消失了。但是,在调试到xerces.XmlSchemaValidator时,我可以看到原因是没有定义特定的错误消息来提供有关该元素的信息。

例如(我的java演示中也是这种情况)“cvc -mininclusive-valid”错误是这样定义的: cvc-minInclusive-valid:值''{0}''不是facet对于类型“{2}”,minInclusive''{1}''有效。 https://wiki.xmldation.com/Support/Validator/cvc-mininclusive-valid

什么我宁愿是,这样的信息将被产生: CVC-type.3.1.3:该值“” {1}“”元素“的” {0}“”是无效。 https://wiki.xmldation.com/Support/Validator/cvc-type-3-1-3

当调试到xerces.XMLSchemaValidator时,我可以看到有两个连续的调用reportSchemaError(...) - 第二个只发生,如果第一个没有引发异常返回。

有什么办法可以配置验证器使用第二种报告方式或用元素信息丰富SAXParseException吗?

请参阅我复制&粘贴&可运行下面的例子代码作进一步的解释:

String xsd = 
      "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + 
        "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" version=\"1.0\">" + 
        "<xs:element name=\"demo\">" + 
        "<xs:complexType>" + 
        "<xs:sequence>" + 

        // given are two elements that cannot be < 1 
        "<xs:element name=\"foo\" type=\"xs:positiveInteger\" minOccurs=\"0\" maxOccurs=\"unbounded\" />" + 
        "<xs:element name=\"bar\" type=\"xs:positiveInteger\" minOccurs=\"0\" maxOccurs=\"unbounded\" />" + 

        "</xs:sequence>" + 
        "</xs:complexType>" + 
        "</xs:element>" + 
        "</xs:schema>"; 

    String xml = 
      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 
        "<demo>" + 

        "<foo>1</foo>" + 
        // invalid! 
        "<foo>0</foo>" + 
        "<bar>2</bar>" + 

        "</demo>"; 

    Validator validator = SchemaFactory 
      .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI) 
      .newSchema(new StreamSource(new StringReader(xsd))) 
      .newValidator(); 


    try { 
     validator.validate(new StreamSource(new StringReader(xml))); 
    } catch (SAXParseException e) { 

     // unfortunately no element or line/column info: 
     System.err.println(e.getMessage()); 

     // better, but still no element info: 
     System.err.println(String.format("Line %s - Column %s - %s", 
       e.getLineNumber(), 
       e.getColumnNumber(), 
       e.getMessage())); 
    } 
+0

不幸的是,我不认为这是可能的。如果您必须具有元素名称,则可以编写自己的代码以根据行号和列号找到元素名称,但即使如此,我也不认为这些元素始终保证可靠。 – Matthew

+0

感谢您的评论,@Matthew!我会给我的问题多一点时间,直到我失去希望,你是对的:) – realsim

尝试使用错误处理:

public class LoggingErrorHandler implements ErrorHandler { 

    private boolean isValid = true; 

    public boolean isValid() { 
     return this.isValid; 
    } 

    @Override 
    public void warning(SAXParseException exc) { 
     System.err.println(exc); 
    } 

    @Override 
    public void error(SAXParseException exc) { 
     System.err.println(exc); 
     this.isValid = false; 
    } 

    @Override 
    public void fatalError(SAXParseException exc) throws SAXParseException { 
     System.err.println(exc); 
     this.isValid = false; 
     throw exc; 
    } 
} 

,并验证使用它:

 Validator validator = SchemaFactory 
       .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI) 
       .newSchema(new StreamSource(new StringReader(xsd))) 
       .newValidator(); 
     LoggingErrorHandler errorHandler = new LoggingErrorHandler(); 
     validator.setErrorHandler(errorHandler); 
     validator.validate(new StreamSource(new StringReader(xml))); 
     return errorHandler.isValid(); 

这没有很好的记录,但如果您有近期版本的Xerces-J(请参阅SVN Rev 380997),您可以验证DOMSource并从ErrorHandler查询Validator以检索验证程序在报告时正在处理的当前Element节点错误。

例如,你可以写一个ErrorHandler像:

public class ValidatorErrorHandler implements ErrorHandler { 

private Validator validator; 

public ValidatorErrorHandler(Validator v) { 
    validator = v; 
} 

... 

public void error(SAXParseException spe) throws SAXException { 
    Node node = null; 
    try { 
     node = (Node) 
      validator.getProperty(
       "http://apache.org/xml/properties/dom/current-element-node"); 
    } 
    catch (SAXException se) {} 
    ... 
} 

,然后调用Validator与此类似ErrorHandler

Validator validator = SchemaFactory 
     .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI) 
     .newSchema(new StreamSource(new StringReader(xsd))) 
     .newValidator(); 
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
dbf.setNamespaceAware(true); 
DocumentBuilder db = dbf.newDocumentBuilder(); 
Document doc = db.parse(new InputSource(new StringReader(xml)); 
ErrorHandler errorHandler = new ValidatorErrorHandler(validator); 
validator.setErrorHandler(errorHandler); 
validator.validate(new DOMSource(doc)); 

获得任何出错的元素。

+0

我一定会尝试,但有点害怕使用DOM,因为我正在处理非常大的XML。目前一切都基于我的环境中的SAX。 – realsim