Java 如何使用DocumentBuilder通过Socket InputStream解析Xml文档而不关闭流?

Java 如何使用DocumentBuilder通过Socket InputStream解析Xml文档而不关闭流?,java,xml,sockets,domdocument,domparser,Java,Xml,Sockets,Domdocument,Domparser,有没有一种方法可以从套接字InputStream解析Xml文档,而无需关闭客户端的流?我只有接收Xml的服务器端的控制权,套接字将保持打开状态,因为服务器将向客户端发送响应 我能告诉它在找到根元素结束标记时停止并返回文档吗?我需要修改解析器,不是吗?既然文档中有多个根元素会使其格式不好,为什么还要进一步解析呢?它在结束元素之后继续进行解析,因为它正在检查尾随注释或处理指令,在我的例子中,我并不关心这些注释或指令,并且会忽略它们 我发送的Xml格式良好,并且从FileInputStream正确解析

有没有一种方法可以从套接字InputStream解析Xml文档,而无需关闭客户端的流?我只有接收Xml的服务器端的控制权,套接字将保持打开状态,因为服务器将向客户端发送响应

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

我发送的Xml格式良好,并且从FileInputStream正确解析,因为它有一个明确的EOF,但在从未关闭的套接字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   

谢谢您的建议。

如果流足够小,可以放入内存中,那么您也可以读取字节数组中的字节。如果它很大,并且您想使用流,那么看看哪种方法可以有效地将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的服务器。