【问题标题】:How to get XML element information in case of SAXParseException在 SAXParseException 的情况下如何获取 XML 元素信息
【发布时间】:2016-05-15 06:39:24
【问题描述】:

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

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

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

我更喜欢的是,会产生这种消息: cvc-type.3.1.3:元素“{0}”的值“{1}”无效。 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()));
    }

【问题讨论】:

  • 不幸的是,我认为这是不可能的。如果您必须拥有元素名称,则可以编写自己的代码来根据该行号和列号来定位元素名称,但即便如此,我也不认为这些总是可靠的。跨度>
  • 感谢@Matthew 的评论!我会给我的问题多一点时间,直到我失去希望,你是对的:)

标签: java xml sax saxparser xerces


【解决方案1】:

尝试使用错误处理程序:

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

【讨论】:

    【解决方案2】:

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

    例如,你可以写一个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) {}
        ...
    }
    

    然后用这个ErrorHandler 调用Validator,例如:

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

    获取发生错误的元素。

    【讨论】:

    • 我肯定会尝试这样做,但我有点害怕使用 DOM 会带来什么,因为我正在处理非常大的 XML。目前在我的环境中一切都基于 SAX。
    【解决方案3】:

    我知道这已经过时了,但 Michael Glavassevich 的回答就像魅力一样!我还不能投票或发表评论,但这个人提供了他真正的深厚知识。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-29
      • 2020-11-23
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多