如何通过验证器获取有关无效DOM元素的更多信息?
我正在针对XSD模式使用 javax.xml.validation.Validator
类来验证内存中的DOM对象.每当填充我的DOM的信息中出现数据损坏时,我都会在验证过程中抛出 SAXParseException
.
I am validating an in-memory DOM object using the javax.xml.validation.Validator
class against an XSD schema. I am getting a SAXParseException
being thrown during the validation whenever there is some data corruption in the information I populate my DOM from.
示例错误:
org.xml.SAXParseException:cvc-datatype-valid.1.2.1:'???"?? [????? G?> ??? p〜tn ??〜0?1]'是无效的值为'hexBinary'.
org.xml.SAXParseException: cvc-datatype-valid.1.2.1: '???"??[?????G?>???p~tn??~0?1]' is not a valid valud for 'hexBinary'.
我希望有一种方法可以在内存中的DOM中找到此错误的位置,并打印出有问题的元素及其父元素.我当前的代码是:
What I am hoping is that there is a way to find the location of this error in my in-memory DOM and print out the offending element and its parent element. My current code is:
public void writeDocumentToFile(Document document) throws XMLWriteException {
try {
// Validate the document against the schema
Validator validator = getSchema(xmlSchema).newValidator();
validator.validate(new DOMSource(document));
// Serialisation logic here.
} catch(SAXException e) {
throw new XMLWriteException(e); // This is being thrown
} // Some other exceptions caught here.
}
private Schema getSchema(URL schema) throws SAXException {
SchemaFactory schemaFactory =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// Some logic here to specify a ResourceResolver
return schemaFactory.newSchema(schema);
}
我已经研究了 Validator#setErrorHandler(ErrorHandler handler)
方法,但是 ErrorHandler
接口仅使我接触了 SAXParseException
公开错误的行号和列号.因为我使用的是内存中的DOM,所以行号和列号均返回-1.
I have looked into the Validator#setErrorHandler(ErrorHandler handler)
method but the ErrorHandler
interface only gives me exposure to a SAXParseException
which only exposes the line number and column number of the error. Because I am using an in-memory DOM this returns -1 for both line and column number.
是否有更好的方法可以做到这一点?如果库为我提供了我想要的功能,我真的不需要在将字符串添加到DOM之前手动验证它们.
Is there a better way to do this? I don't really want to have to manually validate the Strings before I add them to the DOM if the libraries provide me the function I'm looking for.
我正在使用JDK 6更新26和JDK 6更新7,具体取决于此代码的运行位置.
I'm using JDK 6 update 26 and JDK 6 update 7 depending on where this code is running.
添加了此代码-
validator.setErrorHandler(new ErrorHandler() {
@Override
public void warning(SAXParseException exception) throws SAXException {
printException(exception);
throw exception;
}
@Override
public void error(SAXParseException exception) throws SAXException {
printException(exception);
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
printException(exception);
throw exception;
}
private void printException(SAXParseException exception) {
System.out.println("exception.getPublicId() = " + exception.getPublicId());
System.out.println("exception.getSystemId() = " + exception.getSystemId());
System.out.println("exception.getColumnNumber() = " + exception.getColumnNumber());
System.out.println("exception.getLineNumber() = " + exception.getLineNumber());
}
});
我得到输出:
exception.getPublicId() = null
exception.getSystemId() = null
exception.getColumnNumber() = -1
exception.getLineNumber() = -1
如果使用的是Xerces(Sun JDK的默认设置),则可以通过 http://apache.org/xml/properties/dom/current-element-node 属性:
If you are using Xerces (the Sun JDK default), you can get the element that failed validation through the http://apache.org/xml/properties/dom/current-element-node property:
...
catch (SAXParseException e)
{
Element curElement = (Element)validator.getProperty("http://apache.org/xml/properties/dom/current-element-node");
System.out.println("Validation error: " + e.getMessage());
System.out.println("Element: " + curElement);
}
示例:
String xml = "<root xmlns=\"http://www.myschema.org\">\n" +
"<text>This is text</text>\n" +
"<number>32</number>\n" +
"<number>abc</number>\n" +
"</root>";
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes("UTF-8")));
Schema schema = getSchema(getClass().getResource("myschema.xsd"));
Validator validator = schema.newValidator();
try
{
validator.validate(new DOMSource(doc));
}
catch (SAXParseException e)
{
Element curElement = (Element)validator.getProperty("http://apache.org/xml/properties/dom/current-element-node");
System.out.println("Validation error: " + e.getMessage());
System.out.println(curElement.getLocalName() + ": " + curElement.getTextContent());
//Use curElement.getParentNode() or whatever you need here
}
如果您需要从DOM获取行号/列号,请此答案解决了这个问题.
If you need to get line/column numbers from the DOM, this answer has a solution to that problem.