【问题标题】:Java servlets: xml validation against xsdJava servlet:针对 xsd 的 xml 验证
【发布时间】:2013-09-05 22:52:57
【问题描述】:

我有 servlet,它使用打包在 .jar 存档中的实用程序:

@Override
public void init() throws ServletException {
    ...
    try (InputStream stream = getClass().getResourceAsStream("/fileToParse.xml")) {
        App.check(stream);
    } catch (Exception e) {
        throw new ServletException(e);
    }
    ...
}

此实用程序获取 xml 文件流,针对 xsd 模式执行验证并对其进行解析:

public class App {
    private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
    private static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; 
    ...   
    public static void check(InputStream stream) {    
        SAXParserFactory spf = SAXParserFactory.newInstance();
        spf.setNamespaceAware(true);
        spf.setValidating(true);
        MyHandler handler = new MyHandler();
        try {
            SAXParser sp = spf.newSAXParser();
            sp.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
            XMLReader rdr = sp.getXMLReader();
            rdr.setContentHandler(handler);
            rdr.setErrorHandler(new MyErrorHandler());
            rdr.parse(new InputSource(stream));
        }
        ...
    }
    ...
}

xsd 文件以:

开头
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://www.mydomain.org"
           elementFormDefault="qualified"
           xmlns:t="http://www.mydomain.org">
    <xs:element name="appContext">
        ...

xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<appContext xmlns="http://www.mydomain.org"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://www.mydomain.org appContext.xsd">
    ...

.war 结构:

css/
js/
WEB-INF/
    classes/
        mypackage/
            MyServlet.class
        fileToParse.xml
    lib/
        App.jar
    web.xml

App.jar 结构:

mypackage2/
    App.class
appContext.xsd

Servlet Init 方法抛出异常:

...
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_21]
    at java.lang.Thread.run(Thread.java:722) [na:1.7.0_21]
Caused by: java.io.FileNotFoundException: /PATH_TO_TOMCAT/bin/appContext.xsd (No such file or directory)
    at java.io.FileInputStream.open(Native Method) ~[na:1.7.0_21]
    at java.io.FileInputStream.<init>(FileInputStream.java:138) ~[na:1.7.0_21]

如何向 SAXParser 指定验证 xml 文件所需的 xsd 架构在哪里?

附:对不起我的英语不好

UPD:

我正在尝试添加此属性:

    private static final String JAXP_SCHEMA_SOURCE =
            "http://java.sun.com/xml/jaxp/properties/schemaSource";
    ....
    public static void check(InputStream stream) {
        ...
        try {
            ...
            sp.setProperty(JAXP_SCHEMA_SOURCE, new File(getPath("/appContext.xsd")));
            ...
        }
    }
    public static String getPath(String path) {
        return App.class.getResource(path).toString();
    }

现在我有这个例外:

ERROR mypackage2.App - Error: URI=null Line=5: schema_reference.4: Failed to read schema document 'jar:file:/PATH_TO_TOMCAT/webapps/myapp/WEB-INF/lib/App.jar!/appContext.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document 'jar:file:/PATH_TO_TOMCAT/webapps/myapp/WEB-INF/lib/App.jar!/appContext.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198) ~[na:1.7.0_21]

UPD2: 在 xml 文件中使用“classpath:appContext.xsd”:

WARN  mypackage.App - Warning: URI=null Line=5: schema_reference.4: Failed to read schema document 'classpath:appContext.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document 'classpath:appContext.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198) ~[na:1.7.0_21]
...
    at java.lang.Thread.run(Thread.java:722) [na:1.7.0_21]
Caused by: java.net.MalformedURLException: unknown protocol: classpath
    at java.net.URL.<init>(URL.java:592) ~[na:1.7.0_21
;;;

【问题讨论】:

    标签: java xml servlets xsd jaxp


    【解决方案1】:

    尝试将架构源直接设置为InputStream

    public static void check(InputStream stream) {
        ...
        try {
            ...
            sp.setProperty(JAXP_SCHEMA_SOURCE, getInputStream("/appContext.xsd")));
            ...
        }
    }
    
    public static InputStream getInputStream(String path) {
        return SAXLoader.class.getResourceAsStream(path);
    }
    

    检查从 XML 文件中删除 XSD 引用后设置此属性是否有效。如果没有,请检查该属性是否有效,只需使用位于 jar 之外的 XSD 进行测试,并且它的绝对路径作为 File 引用传递,就像您现在所做的那样。

    【讨论】:

    • 感谢您的回答。不幸的是,现在我有异常(UPD2)
    • @chepiov 那行不通。我错误地认为这是一个 Spring 应用程序(classpath 协议不被识别)。但是,你能试试我的更新并告诉我吗?
    【解决方案2】:

    问题解决了:

    public class App {
        ...   
        public static void check(InputStream stream) {    
            SAXParserFactory spf = SAXParserFactory.newInstance();
            spf.setNamespaceAware(true);
            spf.setValidating(true);
            MyHandler handler = new MyHandler();
            try (InputStream schemaStream = App.class.getResourceAsStream("/appContext.xsd")) {
                SAXParser sp = spf.newSAXParser();
                sp.setProperty(JAXPConstants.JAXP_SCHEMA_LANGUAGE, JAXPConstants.W3C_XML_SCHEMA);
                sp.setProperty(JAXPConstants.JAXP_SCHEMA_SOURCE, new InputSource(schemaStream));
                XMLReader rdr = sp.getXMLReader();
                rdr.setContentHandler(handler);
                rdr.setErrorHandler(new MyErrorHandler());
                rdr.parse(new InputSource(stream));
            }
            ...
        }
        ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-24
      • 2012-07-26
      • 1970-01-01
      • 1970-01-01
      • 2012-09-20
      • 2011-10-12
      • 2011-07-18
      • 1970-01-01
      相关资源
      最近更新 更多