如何在 SAXParseException 的情况下获取 XML 元素信息
How to get XML element information in case of SAXParseException
在标准 java 环境中根据 xsd 模式验证 xml 源时,我无法找到一种方法来获取有关验证失败的元素的信息(在许多情况下具体案例)。
捕获SAXParseException时,元素的信息消失了。但是,当调试到 xerces.XmlSchemaValidator 时,我可以看到原因是特定的错误消息未定义为泄露有关元素的信息。
例如(在我的 java 演示中也是如此)"cvc-mininclusive-valid" 错误是这样定义的:
cvc-minInclusive-valid:对于类型“{2}”的 minInclusive“{1}”,值“{0}”不是方面有效的。
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(...) - 第二次只发生,如果第一个调用 return 没有异常抛出。
有没有办法配置验证器使用第二种报告方式或用元素信息丰富 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()));
}
尝试使用错误处理程序:
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
并从您的 Validator
查询ErrorHandler
检索验证器在报告错误时正在处理的当前 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) {}
...
}
然后用这个 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));
获取发生错误的元素
我知道这已经过时了,但 Michael Glavassevich 的回答很有魅力!我还不能投票或发表评论,但这一位提供了他真正深入的知识。
在标准 java 环境中根据 xsd 模式验证 xml 源时,我无法找到一种方法来获取有关验证失败的元素的信息(在许多情况下具体案例)。
捕获SAXParseException时,元素的信息消失了。但是,当调试到 xerces.XmlSchemaValidator 时,我可以看到原因是特定的错误消息未定义为泄露有关元素的信息。
例如(在我的 java 演示中也是如此)"cvc-mininclusive-valid" 错误是这样定义的: cvc-minInclusive-valid:对于类型“{2}”的 minInclusive“{1}”,值“{0}”不是方面有效的。 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(...) - 第二次只发生,如果第一个调用 return 没有异常抛出。
有没有办法配置验证器使用第二种报告方式或用元素信息丰富 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()));
}
尝试使用错误处理程序:
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
并从您的 Validator
查询ErrorHandler
检索验证器在报告错误时正在处理的当前 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) {}
...
}
然后用这个 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));
获取发生错误的元素
我知道这已经过时了,但 Michael Glavassevich 的回答很有魅力!我还不能投票或发表评论,但这一位提供了他真正深入的知识。