XSD验证中的SaxParseException不提供元素名称

时间:2011-08-18 19:46:19

标签: java xml xsd saxparseexception

我有一个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是

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

当xml不符合xsd时,我得到一个异常..但是这个异常没有xsd元素的名称,因为发生了这个错误..消息看起来像

由于org.xml.sax.SAXException,解析XML失败:错误:cvc-minLength-valid:对于类型为null的minLength'1',值''与length ='0'不是facet-valid ”。

而不是打印xsd元素的名称,错误消息只有''。因此,我无法找到并向用户显示导致错误的确切元素。

我的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>

提前致谢

1 个答案:

答案 0 :(得分:5)

首先,一些建议。您不需要构建DOM文档来进行验证。这会导致大量内存开销,甚至可能耗尽大型输入XML文档。你可以使用SAXParser。如果您使用的是Java 1.5或更高版本,则甚至不需要。从该版本开始,Java SE中包含了一个XML验证API。查看包javax.xml.validation以获取更多信息。我们的想法是,您首先构建一个Schema对象,然后从可用于进行验证的Validator中获取Source。它接受任何ErrorHandlers实现输入。验证者也可以Schema,因此您可以重复使用您的班级。当然,您实际上可能需要一个DOM,但在这种情况下,最好制作一个DocumentBuilderFactory实例并将其注册到SAXParseException

现在,针对实际问题。这并不容易,因为ContentHandler没有为您提供太多的上下文信息。你最好的办法就是让某个DefaultHandler连接起来并跟踪你所在的元素或其他位置信息。然后,您可以在需要时将其赋予错误处理程序。类DefaultHandler2package 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; } } } 是一种结合错误和内容处理的便捷方式。您可以在org.xml.sax.ext包中找到这些类。

我已经在下面发布了一个测试。现在,我确实获得了两行输出而不是预期输出。如果这是因为我正在使用Schema,或者因为我没有抛出异常并继续处理,我不确定。第二行确实包含元素的名称,因此可能就足够了。您可以在错误上设置一些标志,而不是抛出异常并结束解析。

{{1}}

这有点粗糙,但你可以从中做到这一点,以获得你需要的东西。