java - XSD 验证中的 SaxParseException 未提供元素名称

标签 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:Error: cvc-minLength-valid: Value '' with length = '0' is not facet-valid respect to minLength '1' for type 'null '.

错误消息没有打印 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>

提前致谢

最佳答案

首先,一些建议。您不需要仅仅为了进行验证而构建 DOM 文档。这会导致大量内存开销,甚至可能会耗尽大量输入 XML 文档。您可以只使用 SAXParser。如果您使用的是 Java 1.5 或更高版本,那甚至没有必要。从那个版本开始,Java SE 中包含了一个 XML 验证 API。检查包裹javax.xml.validation获取更多信息。这个想法是,您首先构建一个 Schema 对象,然后从中获取一个可用于执行验证的 Validator。它接受任何 Source 实现作为输入。还可以为 validator 提供 ErrorHandlers,这样您就可以重用您的类。当然,您实际上可能需要一个 DOM,但在这种情况下,最好创建一个 Schema 实例并将其注册到您的 DocumentBuilderFactory

现在,针对实际问题。这并不完全容易,因为 SAXParseException 没有为您提供很多上下文信息。最好的办法是在某处连接一个 ContentHandler 并跟踪您所在的元素或其他一些位置信息。然后,您可以在需要时将其提供给错误处理程序。 DefaultHandlerDefaultHandler2 类是结合错误和内容处理的便捷方式。您将在包 org.xml.sax.ext 中找到这些类。

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

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

    }

}

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

关于java - XSD 验证中的 SaxParseException 未提供元素名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7113219/

相关文章:

java - 关闭随机 'PopUps'

java - 一个加法程序,它不断地将您输入的数字相加,直到您输入零。 java 语

javascript - jQuery 获取所有节点名称(包括父节点和子节点)

xml - 验证 XML/识别中断点的快速方法

c# - 如何重命名 XSD.exe 生成的枚举 ItemsChoiceType?

Android:在性能方面使用@id 而不是@+id 有什么好处吗?

java - 如何在 eclipse 中添加来自 XChart 的 javadocs

java - 以编程方式执行 shell 命令 : why it doesn't work?

使用 SDL Tridion 的 XSD 方面和指标

java - 在 Java 中找到一个数字的所有因子?