java XSD 验证中的 SaxParseException 未给出元素名称
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7113219/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
SaxParseException in XSD validation does not give element name
提问by Adithya Puram
I have an xsd file and an xml file, I am validating the xml file against the xsd file using the following code
我有一个 xsd 文件和一个 xml 文件,我正在使用以下代码根据 xsd 文件验证 xml 文件
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
factory.setAttribute(
"http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema");
factory.setAttribute(
"http://java.sun.com/xml/jaxp/properties/schemaSource",
new InputSource(new StringReader(xsd)));
Document doc = null;
try {
DocumentBuilder parser = factory.newDocumentBuilder();
MyErrorHandler errorHandler = new MyErrorHandler();
parser.setErrorHandler(errorHandler);
doc = parser.parse(new InputSource(new StringReader(xml)));
return true;
} catch (ParserConfigurationException e) {
System.out.println("Parser not configured: " + e.getMessage());
} catch (SAXException e) {
System.out.print("Parsing XML failed due to a "
+ e.getClass().getName() + ":");
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println("IOException thrown");
e.printStackTrace();
}
return false;
MyErrorHanlder is
我的错误处理程序是
private static class MyErrorHandler implements ErrorHandler {
public void warning(SAXParseException spe) throws SAXException {
System.out.println("Warning: " + spe.getMessage() + " getColumnNumber is " + spe.getColumnNumber() + " getLineNumber " + spe.getLineNumber() + " getPublicId " + spe.getPublicId() + " getSystemId " + spe.getSystemId());
}
public void error(SAXParseException spe) throws SAXException {
System.out.println("Error: " + spe.getMessage() + " getColumnNumber is " + spe.getColumnNumber() + " getLineNumber " + spe.getLineNumber() + " getPublicId " + spe.getPublicId() + " getSystemId " + spe.getSystemId());
throw new SAXException("Error: " + spe.getMessage());
}
public void fatalError(SAXParseException spe) throws SAXException {
System.out.println("Fatal Error: " + spe.getMessage() + " getColumnNumber is " + spe.getColumnNumber() + " getLineNumber " + spe.getLineNumber() + " getPublicId " + spe.getPublicId() + " getSystemId " + spe.getSystemId());
throw new SAXException("Fatal Error: " + spe.getMessage());
}
}
And when the xml does not comply with xsd I get an exception.. but this exception does not have the name of the xsd element due to which this error has occured .. The message looks like
当 xml 不符合 xsd 时,我得到一个异常.. 但是这个异常没有 xsd 元素的名称,因为这个错误发生了 .. 消息看起来像
Parsing XML failed due to a org.xml.sax.SAXException:Error: cvc-minLength-valid: Value '' with length = '0' is not facet-valid with respect to minLength '1' for type 'null'.
由于 org.xml.sax.SAXException,解析 XML 失败:错误:cvc-minLength-valid:值 '' with length = '0' 对于类型 'null' 的 minLength '1' 不是方面有效的。
Instead of printing the name of the xsd element, the error message just has ''. Because of this I am not able to find and display(to the user) the exact element which is causing the error.
错误消息没有打印 xsd 元素的名称,而是只有 ''。因此,我无法找到并显示(向用户)导致错误的确切元素。
My xsd element looks like this
我的 xsd 元素看起来像这样
<xs:element name="FullName_FirstName">
<xs:annotation>
<xs:appinfo>
<ie:label>First Name</ie:label>
<ie:html_element>0</ie:html_element>
</xs:appinfo>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
Thanks in advance
提前致谢
回答by G_H
First of all, some advice. You don't need to build a DOM document just to do validation. This causes a large amount of memory overhead, maybe even running out on large input XML documents. You could just use a SAXParser
. If you're using Java 1.5 or later, that isn't even necessary. From that version on, an XML validation API was included in Java SE. Check package javax.xml.validationfor more info. The idea is that you first build a Schema
object, then obtain a Validator
from that which can be used to do validation. It accepts any Source
implementation for input. Validators can also be given ErrorHandlers
, so you can just reuse your class. Of course, it is possible that you actually will need a DOM, but in that case it's still better to make a Schema
instance and register that with your DocumentBuilderFactory
.
首先,给一些建议。您不需要为了验证而构建 DOM 文档。这会导致大量内存开销,甚至可能在大型输入 XML 文档上耗尽。你可以只使用一个SAXParser
. 如果您使用的是 Java 1.5 或更高版本,那甚至没有必要。从那个版本开始,Java SE 中包含了一个 XML 验证 API。检查包javax.xml.validation以获取更多信息。这个想法是您首先构建一个Schema
对象,然后Validator
从可用于进行验证的对象中获取一个。它接受任何Source
输入的实现。也可以给出验证器ErrorHandlers
,所以你可以重用你的类。当然,您实际上可能需要一个 DOM,但在这种情况下,最好制作一个Schema
实例并将其注册到您的DocumentBuilderFactory
.
Now, for the actual problem. This isn't entirely easy, since the SAXParseException
doesn't provide you with much context information. Your best bet is to have a ContentHandler
hooked up somewhere and keep track of what element you're in, or some other positional information. You could then have that given to the error handler when needed. The class DefaultHandler
or DefaultHandler2
is a convenient way of combining both error and content handling. You'll find those classes in package org.xml.sax.ext.
现在,对于实际问题。这并不完全容易,因为SAXParseException
它没有为您提供很多上下文信息。最好的办法是在ContentHandler
某处连接一个并跟踪您所在的元素或其他一些位置信息。然后,您可以在需要时将其提供给错误处理程序。类DefaultHandler
orDefaultHandler2
是一种结合错误和内容处理的便捷方式。您将在 org.xml.sax.ext 包中找到这些类。
I've put together a test that I'll post below. Now, I do get two lines of output instead of the expected one. If this is because I'm using a Schema, or because I'm not throwing an exception and keep on processing, I'm not certain. The second line does contain the name of the element, so that might be enough. You could have some flag set on errors instead of throwing an exception and ending the parsing.
我已经整理了一个测试,我将在下面发布。现在,我确实得到了两行输出,而不是预期的输出。如果这是因为我正在使用架构,或者因为我没有抛出异常并继续处理,我不确定。第二行确实包含元素的名称,所以这可能就足够了。您可以在错误上设置一些标志,而不是抛出异常并结束解析。
package jaxb.test;
import java.io.StringReader;
import javax.xml.XMLConstants;
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 org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
public class ValidationTest {
public static void main(String[] args) throws Exception {
//Test XML and schema
final String xml = "<?xml version=\"1.0\"?><test><test2></test2></test>";
final String schemaString =
"<?xml version=\"1.0\"?>"
+ "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"unqualified\" attributeFormDefault=\"unqualified\">"
+ "<xsd:element name=\"test\" type=\"Test\"/>"
+ "<xsd:element name=\"test2\" type=\"Test2\"/>"
+ "<xsd:complexType name=\"Test\">"
+ "<xsd:sequence>"
+ "<xsd:element ref=\"test2\" minOccurs=\"1\" maxOccurs=\"unbounded\"/>"
+ "</xsd:sequence>"
+ "</xsd:complexType>"
+ "<xsd:simpleType name=\"Test2\">"
+ "<xsd:restriction base=\"xsd:string\"><xsd:minLength value=\"1\"/></xsd:restriction>"
+ "</xsd:simpleType>"
+ "</xsd:schema>";
//Building a Schema instance
final Source schemaSource =
new StreamSource(new StringReader(schemaString));
final Schema schema =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaSource);
//Creating a SAXParser for our input XML
//First the factory
final SAXParserFactory factory = SAXParserFactory.newInstance();
//Must be namespace aware to receive element names
factory.setNamespaceAware(true);
//Setting the Schema for validation
factory.setSchema(schema);
//Now the parser itself
final SAXParser parser = factory.newSAXParser();
//Creating an instance of our special handler
final MyContentHandler handler = new MyContentHandler();
//Parsing
parser.parse(new InputSource(new StringReader(xml)), handler);
}
private static class MyContentHandler extends DefaultHandler {
private String element = "";
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if(localName != null && !localName.isEmpty())
element = localName;
else
element = qName;
}
@Override
public void warning(SAXParseException exception) throws SAXException {
System.out.println(element + ": " + exception.getMessage());
}
@Override
public void error(SAXParseException exception) throws SAXException {
System.out.println(element + ": " + exception.getMessage());
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
System.out.println(element + ": " + exception.getMessage());
}
public String getElement() {
return element;
}
}
}
It's a bit rough, but you can work on from this to get what you need.
这有点粗糙,但您可以从这里开始工作以获得您需要的东西。