通过解析资源关闭流

时间:2016-04-28 13:13:55

标签: java xml validation xsd

我正在尝试使用import和includes为模式实现xsd验证器。我以this answer为例。

这是我的验证方法:

public void validate(String filePath, String schemaName) throws Exception
{
    SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    factory.setResourceResolver(new ResourceResolver());
    Source schemaFile = new StreamSource(getClass().getClassLoader().getResourceAsStream(schemaName));
    Schema schema = factory.newSchema(schemaFile);
    Validator validator = schema.newValidator();
    validator.setErrorHandler(new MySAXParseErrorHandler());
    validator.validate(new StreamSource(filePath));
}

LSInput(完全相同):

public class LSInputImpl implements LSInput
{

private String publicId;

private String systemId;

public String getPublicId()
{
    return publicId;
}

public void setPublicId(String publicId)
{
    this.publicId = publicId;
}

public String getBaseURI()
{
    return null;
}

public InputStream getByteStream()
{
    return null;
}

public boolean getCertifiedText()
{
    return false;
}

public Reader getCharacterStream()
{
    return null;
}

public String getEncoding()
{
    return null;
}

public String getStringData()
{
    synchronized (inputStream) {
        try {
            byte[] input = new byte[inputStream.available()];
            inputStream.read(input);
            String contents = new String(input);
            return contents;
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Exception " + e);
        }
        return null;
    }
}

public void setBaseURI(String baseURI)
{
}

public void setByteStream(InputStream byteStream)
{
}

public void setCertifiedText(boolean certifiedText)
{
}

public void setCharacterStream(Reader characterStream)
{
}

public void setEncoding(String encoding)
{
}

public void setStringData(String stringData)
{
}

public String getSystemId()
{
    return systemId;
}

public void setSystemId(String systemId)
{
    this.systemId = systemId;
}

public BufferedInputStream getInputStream()
{
    return inputStream;
}

public void setInputStream(BufferedInputStream inputStream)
{
    this.inputStream = inputStream;
}

private BufferedInputStream inputStream;

public LSInputImpl(String publicId, String sysId, InputStream input)
{
    this.publicId = publicId;
    this.systemId = sysId;
    this.inputStream = new BufferedInputStream(input);
}

}

ResourceResolver:

public class ResourceResolver  implements LSResourceResolver
{

   public LSInput resolveResource(String type, String namespaceURI,
                           String publicId, String systemId, String baseURI)       {


    InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(systemId);       
    return new LSInputImpl(publicId, systemId, resourceAsStream);
}

}

当我尝试使用仅包含导入的xsd验证xml时,它可以正常工作。但是当我使用include将一个模式与一个模式分开时,进程因IOException而失败:

java.io.IOException: Stream closed
at java.io.BufferedInputStream.getInIfOpen(BufferedInputStream.java:159)
at java.io.BufferedInputStream.available(BufferedInputStream.java:410)
at LSInputImpl.getStringData(LSInputImpl.java:57)
at com.sun.org.apache.xerces.internal.util.DOMEntityResolverWrapper.resolveEntity(DOMEntityResolverWrapper.java:130)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.resolveEntity(XMLEntityManager.java:1073)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.resolveDocument(XMLSchemaLoader.java:659)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.resolveSchemaSource(XSDHandler.java:2105)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.constructTrees(XSDHandler.java:1088)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.constructTrees(XSDHandler.java:1120)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:620)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:616)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:574)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:540)
at com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:255)
at javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:638)
at Main.validate(Main.java:54)
at Main.main(Main.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

org.xml.sax.SAXParseException; systemId: file:///C:/Users/adobryn/Java/sub/schema.xsd; lineNumber: 456; columnNumber: 73; src-resolve: Cannot resolve the name 'st_Term' to a(n) 'type definition' component.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:437)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4162)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:4145)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getGlobalDecl(XSDHandler.java:1741)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDElementTraverser.traverseNamedElement(XSDElementTraverser.java:405)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDElementTraverser.traverseLocal(XSDElementTraverser.java:194)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.traverseLocalElements(XSDHandler.java:3618)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:633)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:616)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:574)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:540)
at com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:255)
at javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:638)
at Main.validate(Main.java:54)
at Main.main(Main.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

包含以下内容的架构:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/schema" targetNamespace="http://www.w3.org/schema" elementFormDefault="qualified">    
    <xsd:include schemaLocation="st_Term.xsd"/>
    <xsd:element name="Term" type="st_Term" minOccurs="0" maxOccurs="1"/>
</xsd:schema>

我认为,getStringData()方法有问题。我怎么修改它?谢谢你的帮助!

2 个答案:

答案 0 :(得分:1)

问题是,包括xsd还有一个include,而ResourceResolver在资源文件夹中查找了它,而不是资源/ sub,其中包含xsd。所以,我又举了一个例子,它有path tracking,现在可以正常运行:)请注意,schemaBasePath应该以&#34; /&#34;开头。

答案 1 :(得分:-1)

几年前我在.xsd中遇到了同样的问题。

我记得我的问题是.xsd资源及其包含位于资源中的某个包(目录)中。

我已使用以下ResourceResolver解决了这个问题,其中包被传递给构造函数(resourceRoot参数):

class ResourceResolver implements LSResourceResolver {

    private String resourceRoot;

    public ResourceResolver(String resourceRoot) {
        this.resourceRoot = resourceRoot;
    }

    public LSInput resolveResource(String type, String namespaceURI,String publicId, String systemId, String baseURI) {
        InputStream resourceAsStream = this.getClass().getResourceAsStream(resourceRoot + "/" + systemId);
        return new Input(publicId, systemId, resourceAsStream);
    }

}

和输入:

static class Input implements LSInput {

    private String publicId;

    private String systemId;

    public String getPublicId() {
        return publicId;
    }

    public void setPublicId(String publicId) {
        this.publicId = publicId;
    }

    public String getBaseURI() {
        return null;
    }

    public InputStream getByteStream() {
        return null;
    }

    public boolean getCertifiedText() {
        return false;
    }

    public Reader getCharacterStream() {
        return null;
    }

    public String getEncoding() {
        return null;
    }

    public String getStringData() {
        synchronized (inputStream) {
            try {
                byte[] input = new byte[inputStream.available()];
                inputStream.read(input);
                String contents = new String(input, "UTF-8");
                return contents;
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("Exception " + e);
                return null;
            }
        }
    }

    public void setBaseURI(String baseURI) {
    }

    public void setByteStream(InputStream byteStream) {
    }

    public void setCertifiedText(boolean certifiedText) {
    }

    public void setCharacterStream(Reader characterStream) {
    }

    public void setEncoding(String encoding) {
    }

    public void setStringData(String stringData) {
    }

    public String getSystemId() {
        return systemId;
    }

    public void setSystemId(String systemId) {
        this.systemId = systemId;
    }

    private final BufferedInputStream inputStream;

    public Input(String publicId, String sysId, InputStream input) {
        this.publicId = publicId;
        this.systemId = sysId;
        this.inputStream = new BufferedInputStream(input);
    }
}