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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 18:41:19  来源:igfitidea点击:

SaxParseException in XSD validation does not give element name

javaxmlxsdsaxparseexception

提问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 Schemaobject, then obtain a Validatorfrom that which can be used to do validation. It accepts any Sourceimplementation 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 Schemainstance 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 SAXParseExceptiondoesn't provide you with much context information. Your best bet is to have a ContentHandlerhooked 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 DefaultHandleror DefaultHandler2is a convenient way of combining both error and content handling. You'll find those classes in package org.xml.sax.ext.

现在,对于实际问题。这并不完全容易,因为SAXParseException它没有为您提供很多上下文信息。最好的办法是在ContentHandler某处连接一个并跟踪您所在的元素或其他一些位置信息。然后,您可以在需要时将其提供给错误处理程序。类DefaultHandlerorDefaultHandler2是一种结合错误和内容处理的便捷方式。您将在 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.

这有点粗糙,但您可以从这里开始工作以获得您需要的东西。