Вопрос

I have servlet which uses utility packaged in .jar archive:

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

This utility takes xml file stream, performs validation against xsd schema and parses it:

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 file starts with:

<?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 file:

<?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 structure:

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

App.jar structure:

mypackage2/
    App.class
appContext.xsd

Servlet Init method throws exception:

...
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]

How I can specify to SAXParser where is xsd schema needed to validate xml file?

P.S. Sorry for my bad English

UPD:

I'm trying to add this property:

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

Now I have this exception:

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: With "classpath:appContext.xsd" in xml file:

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
;;;
Это было полезно?

Решение 2

Problem solved:

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

Другие советы

Try setting the schema source as InputStream directly

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

Check if setting this property works after removing the XSD reference from the XML file. If not, check if the property works or not by simply testing with the XSD located outside the jar and its absolute path passed as a File reference as you're doing right now.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top