Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用相同的inputstream进行验证和读取_Java_Xml_Validation_Xsd_Inputstream - Fatal编程技术网

Java 使用相同的inputstream进行验证和读取

Java 使用相同的inputstream进行验证和读取,java,xml,validation,xsd,inputstream,Java,Xml,Validation,Xsd,Inputstream,我有一个Web服务,它从xml文件中获取输入流。现在,我想用相同的inputstream验证和读取它。我使用标记和重置 在Glassfish和Websphere上,效果很好。但是,当我使用openEJB运行集成测试时,验证后流将关闭。我可以用一个简单的例子来重现它 我怎样才能更好地认识到这一点?验证器实现总是相同的。但是每个环境都使用inputstream的另一个实现 public class XMLReader { public static void main(String[] args)

我有一个Web服务,它从xml文件中获取输入流。现在,我想用相同的inputstream验证和读取它。我使用标记和重置

在Glassfish和Websphere上,效果很好。但是,当我使用openEJB运行集成测试时,验证后流将关闭。我可以用一个简单的例子来重现它

我怎样才能更好地认识到这一点?验证器实现总是相同的。但是每个环境都使用inputstream的另一个实现

public class XMLReader {
public static void main(String[] args) {
    try {
        XMLReader reader = new XMLReader();
        InputStream stream = new BufferedInputStream(new FileInputStream(
                new File("myXML.xml")));
        reader.read(stream);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void read(InputStream xmlInputStream) throws SAXException,
        IOException {
    if (xmlInputStream.markSupported()) {
        xmlInputStream.mark(0);
        validateXML(xmlInputStream);
        xmlInputStream.reset();
        readXML(xmlInputStream);
    }
}

private void readXML(InputStream xmlInputStream) {
    // READ xmInputStream with STAX, JAXB, etc. whatever

}

private void validateXML(InputStream xmlInputStream) throws SAXException,
        IOException {
    Source schemaFile = new StreamSource(new File("myXSD.xsd"));
    Source xmlFile = new StreamSource(xmlInputStream);
    SchemaFactory schemaFactory = SchemaFactory
            .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Schema schema = schemaFactory.newSchema(schemaFile);
    Validator validator = schema.newValidator();
    try {
        validator.validate(xmlFile);
        System.out.println("is valid");
    } catch (SAXException e) {
        System.out.println("is NOT valid");
        System.out.println("Reason: " + e.getLocalizedMessage());
    }
}
}
例外情况:

  java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:145)
at java.io.BufferedInputStream.reset(BufferedInputStream.java:414)
at xmltest.XMLReader.read(XMLReader.java:36)
at xmltest.XMLReader.main(XMLReader.java:27)

不幸的是,XML解析器在完成读取后关闭流。我不明白为什么它真的会这样做,我也不会建议任何人关闭他们不拥有的流。也许有一个原因我不能很快理解

无论如何,您可以使用BufferedInputStream,它不会关闭包装的InputSteam:

public static void main(String[] args) {
    try (FileInputStream in = new FileInputStream(new File("myXML.xml"))){
        XMLReader reader = new XMLReader();
        InputStream stream = new BufferedInputStream(in) {
            @Override
            public void close() throws IOException {
               // don't close
            }
        };
        reader.read(stream);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

这让我想到了一个类似于覆盖SAX实现的东西,它在验证结束时关闭inputstream

如果您对validateXML行进行注释,是否一切正常:

if (xmlInputStream.markSupported()) {
    xmlInputStream.mark(0);
    // validateXML(xmlInputStream);
    xmlInputStream.reset();
    readXML(xmlInputStream);
}
如果有的话,在openEJB类路径中是否有一个xerces jar,而Glassfish中没有


我很确定我在过去遇到过这样的问题,但不记得确切的问题。

对Marcel Steinbach的解决方案进行了一个小小的修改:BufferedInputStream将维护一个缓冲区,这只是为了防止关闭输入流而没有必要。相反,您可以创建一个匿名InputStream类,该类仅将read方法委托给包含XML的可标记输入流。由于InputStream中close方法的默认实现是不执行任何操作,因此验证后该流将保持打开状态:

validator.validate(new StreamSource(new InputStream() {
    @Override
    public int read() throws IOException {
        return xmlInputStream.read();
    }
}));
final StringWriter sw = new StringWriter(is.available());
validator.validate(new StreamSource(new InputStream() {
    @Override public int read() throws IOException {
        int ch = is.read();
        sw.write(ch);
        return ch;
    }
}));
readXML(new ByteArrayInputStream(sw.toString().getBytes()));

如果不确定输入流是否受标记支持,则可以使用以下方法将其高效复制到缓冲区,验证后可以从缓冲区读取XML:

validator.validate(new StreamSource(new InputStream() {
    @Override
    public int read() throws IOException {
        return xmlInputStream.read();
    }
}));
final StringWriter sw = new StringWriter(is.available());
validator.validate(new StreamSource(new InputStream() {
    @Override public int read() throws IOException {
        int ch = is.read();
        sw.write(ch);
        return ch;
    }
}));
readXML(new ByteArrayInputStream(sw.toString().getBytes()));

如果你从网络上阅读,我可以理解这种情况。当部署到服务器中时,您是否仍在从物理文件读取XML?我们通过REST服务将XML文件作为字符串获取。我用来创建Inputstream的字符串。上面的示例仅用于演示行为。请显示从字符串创建InputStream的代码。请注意,将内容加载到任意长的字符串中通常不是一个好主意。首先将其复制到临时文件(可能使用)。谢谢。我使用了NoCloseStream,它工作得很好。这比简单地完全消除
BufferedInputStream
要好吗?从逻辑上讲,这比保留它更好吗?这些又是如何解决实际问题的呢?