Java 如何使用DocumentBuilder通过Socket InputStream解析Xml文档而不关闭流?
有没有一种方法可以从套接字InputStream解析Xml文档,而无需关闭客户端的流?我只有接收Xml的服务器端的控制权,套接字将保持打开状态,因为服务器将向客户端发送响应 我能告诉它在找到根元素结束标记时停止并返回文档吗?我需要修改解析器,不是吗?既然文档中有多个根元素会使其格式不好,为什么还要进一步解析呢?它在结束元素之后继续进行解析,因为它正在检查尾随注释或处理指令,在我的例子中,我并不关心这些注释或指令,并且会忽略它们 我发送的Xml格式良好,并且从FileInputStream正确解析,因为它有一个明确的EOF,但在从未关闭的套接字InputStream解析时挂起 客户端在发送Xml后不会关闭流,因为它们希望通过套接字得到响应 这是我的密码:Java 如何使用DocumentBuilder通过Socket InputStream解析Xml文档而不关闭流?,java,xml,sockets,domdocument,domparser,Java,Xml,Sockets,Domdocument,Domparser,有没有一种方法可以从套接字InputStream解析Xml文档,而无需关闭客户端的流?我只有接收Xml的服务器端的控制权,套接字将保持打开状态,因为服务器将向客户端发送响应 我能告诉它在找到根元素结束标记时停止并返回文档吗?我需要修改解析器,不是吗?既然文档中有多个根元素会使其格式不好,为什么还要进一步解析呢?它在结束元素之后继续进行解析,因为它正在检查尾随注释或处理指令,在我的例子中,我并不关心这些注释或指令,并且会忽略它们 我发送的Xml格式良好,并且从FileInputStream正确解析
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
谢谢您的建议。如果流足够小,可以放入内存中,那么您也可以读取字节数组中的字节。如果它很大,并且您想使用流,那么看看哪种方法可以有效地将InputStream复制到OutputStream并在以后处理它。这样套接字流应该保持开放。我不接受我的答案,因为我不再信任XmlFrameDecoder,因为它的XML跟踪看起来有点太幼稚了。。真正需要的是找到一个XML解析器,它可以选择在结束元素标记之后返回文档,并忽略后面的杂项数据 我想我已经意识到了一个很好的解决方案,我想我会和其他类似的人分享 我将使用Netty来构建套接字协议,而不是使用原始套接字 并使用一个框架来框显消息,并将该框架中的字节解析为文档
public class Main {
private static class MyXmlHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try (InputStream in = new ByteBufInputStream((ByteBuf) msg, true)) {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in);
// prove that we got the document
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(writer));
}
}
}
public static void main(String[] args) throws InterruptedException {
final int PORT = 8080;
EventLoopGroup parentGroup = new NioEventLoopGroup();
EventLoopGroup childGroup = new NioEventLoopGroup();
try {
ServerBootstrap server = new ServerBootstrap();
server.group(parentGroup, childGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new XmlFrameDecoder(Integer.MAX_VALUE),
new MyXmlHandler());
}
}).childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture channel = server.bind(PORT).sync();
channel.channel().closeFuture().sync();
} finally {
childGroup.shutdownGracefully();
parentGroup.shutdownGracefully();
}
}
}
如果流保持打开状态,您如何知道何时收到完整的XML文档?客户端需要通过关闭流或提前告诉您长度来告诉您。我希望它在读取根元素的结束标记时知道Xml文档已完成。@Andreas准确地说。在看到根元素结束标记之前,我不知道完整的Xml文档何时被发送。目前,我正在尝试进行一些简单的手动解析来实现这一点,但CDATA可能会让事情变得粗略,我希望只使用现有的Xml解析器。好的,我想我现在明白了,您有一个套接字,可以在其中连续获取Xml,您需要知道何时可以进行解析。当时有一个Xerces样本描述了一个解决方案-请看:。它在服务器端使用WrappedInputStream方法使XML看起来是分开的,尽管进入同一个流意味着您有权访问服务器代码。@IoannisBaourdos不幸的是,这个解决方案似乎要求我同时控制服务器和客户端。但是,我只能控制接收Xml的服务器。