首页 > 解决方案 > 如何使用 DocumentBuilder 通过 Socket InputStream 解析 Xml 文档而不关闭流?

问题描述

有没有一种方法可以在不关闭客户端流的情况下从 Socket InputStream 解析 Xml 文档?我只控制接收 Xml 的服务器端,并且套接字将保持打开状态,因为服务器会将响应发送回客户端。

我可以告诉它在找到根元素结束标记时停止并返回 Document,我需要修改解析器不是吗?既然 Document 中有多个根元素会使其格式不正确,为什么还要费心进一步解析呢?它在结束元素之后继续解析,因为它正在检查尾随注释或处理指令,在我的情况下我不关心这些并且会忽略它们。

我发送的Xml格式正确,并且从 FileInputStream 正确解析,因为它具有明确的 EOF,但在从未关闭的 Socket InputStream 解析时挂起。

客户端在发送 Xml 后不会关闭流,因为他们希望通过套接字得到响应。

这是我的代码:

try (
    ServerSocket server = new ServerSocket(port);
    Socket sock = server.accept();
    InputStream in = sock.getInputStream(); ) {

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    db.setErrorHandler(MyErrorHandler);
    db.setEntityResolver(MyEntityResolver);
    // below hangs, waiting for stream to close I think
    Document doc = db.parse(in);

    // .. process document
    // .. send response
}   

这是挂起位置的堆栈跟踪:

SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int) line: not available [native method]    
SocketInputStream.socketRead(FileDescriptor, byte[], int, int, int) line: 116   
SocketInputStream.read(byte[], int, int, int) line: 171 
SocketInputStream.read(byte[], int, int) line: 141  
XMLEntityManager$RewindableInputStream.read(byte[], int, int) line: 2919    
UTF8Reader.read(char[], int, int) line: 302 
XMLEntityScanner.load(int, boolean, boolean) line: 1895 
XMLEntityScanner.skipSpaces() line: 1685    
XMLDocumentScannerImpl$TrailingMiscDriver.next() line: 1371 
XMLDocumentScannerImpl.next() line: 602 
XMLDocumentScannerImpl(XMLDocumentFragmentScannerImpl).scanDocument(boolean) line: 505  
XIncludeAwareParserConfiguration(XML11Configuration).parse(boolean) line: 841   
XIncludeAwareParserConfiguration(XML11Configuration).parse(XMLInputSource) line: 770    
DOMParser(XMLParser).parse(XMLInputSource) line: 141    
DOMParser.parse(InputSource) line: 243  
DocumentBuilderImpl.parse(InputSource) line: 339    
DocumentBuilderImpl(DocumentBuilder).parse(InputStream) line: 121   

感谢您的任何建议。

标签: javaxmlsocketsdomdocumentdomparser

解决方案


如果流足够小以适合内存,您不妨读取字节数组中的字节。如果它很大并且您想使用流,请查看Apache Commons IOUtils,它有效地为您提供了将 InputStream 复制到 OutputStream 并在以后处理它的方法。这样,套接字流应该保持打开状态。


推荐阅读