【问题标题】:Stream xml input to sax Parser, How to print the xml streamed?将 xml 输入流式传输到 sax 解析器,如何打印流式传输的 xml?
【发布时间】:2011-10-04 10:47:08
【问题描述】:

我正在尝试通过套接字连接到一台远程服务器,并且我从套接字返回大的 xml 响应,由 '\n' 字符分隔。

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <data>
       .......
       .......
    </data>
</Response>\n   <---- \n acts as delimiter 
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <data>
        ....
        ....
    </data>
</Response>\n
..

我正在尝试使用 SAX Parser 解析这些 xml。理想情况下,我想通过搜索 '\n' 来获得对字符串的完整响应,并将此响应提供给解析器。但由于我的单个响应非常大,当我在字符串中保存如此大的 xml 时,我会出现 outOfMemory 异常。所以唯一的选择是将 xml 流式传输到 SAX。

SAXParserFactory spfactory = SAXParserFactory.newInstance();
SAXParser saxParser = spfactory.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();

xmlReader.setContentHandler(new MyDefaultHandler(context));

InputSource xmlInputSource  =   new InputSource(new    
                    CloseShieldInputStream(mySocket.getInputStream()));
xmlReader.parse(xmlInputSource);

我正在使用 closeShieldInputStream 来防止 SAX 由于“\n”而在异常时关闭我的套接字流。我问了previous question ..

现在有时我会遇到解析错误

org.apache.harmony.xml.ExpatParser$ParseException: At line 1, column 8: not well-formed (invalid token)

我搜索了它,found 发现此错误通常发生在实际 xml 的编码与 SAX 所期望的不同时。我写了一个C程序,打印出xml,我所有的xml都是UTF-8编码的。

现在我的问题..

  1. 上面给出的xml解析错误还有其他原因吗 除了编码问题
  2. 有什么方法可以将 SAX 的输入打印(或写入任何文件)为 它从套接字流式传输?

在尝试了 Hemal Pandya 的回答之后..

OutputStream log = new BufferedOutputStream(new FileOutputStream("log.txt"));
InputSource xmlInputSource  =   new InputSource(new CloseShieldInputStream(new   
                                    TeeInputStream(mReadStream, log)));
xmlReader.parse(xmlInputSource);

当我挂载 SDCard 时创建了一个名为 log.txt 的新文件,但它是空的。我用对了吗?

最后我是怎么做到的..

我用 TeeInputStream 本身解决了这个问题。感谢 Hemal Pandya 提出的建议。

//open a log file in append mode..
OutputStream log = new BufferedOutputStream(new FileOutputStream("log.txt",true));
InputSource xmlInputSource  =   new InputSource(new CloseShieldInputStream(new   
                                        TeeInputStream(mReadStream, log)));
try{
  xmlReader.parse(xmlInputSource);
  //flush content in the log stream to file..this code only executes if parsing completed successfully 
  log.flush();
}catch(SaxException e){
  //we want to get the log even if parsing failed..So we are making sure we get the log in either case..
  log.flush();
}

【问题讨论】:

  • 请看我的编辑,我已经为每个响应添加了一个 doctype 元素。这是第一个错误的原因吗?
  • 除了在trycatch 块中调用log.flush(),另一种选择是在outisde 之外进行——try{ xmlReader.parse(xmlInputSource); }catch(SaxException e){ /* log exception */ } log.flush();
  • hmmm...但是在我的情况下,当我遇到异常时,我会直接从异常捕获本身返回..所以在我的情况下这是不可能的

标签: java android sockets stream saxparser


【解决方案1】:

有没有办法将 SAX 的输入打印(或写入任何文件)为 它从套接字流式传输?

Apache Commons 有一个TeeInputStream,应该很有用。

OutputStream log = new BufferedOutputStream(new FileOutputtStream("response.xml"));
InputSource xmlInputSource  =   new InputSource(new    
                    CloseShieldInputStream(new TeeInputStream(mySocket.getInputStream(), log)));

我没有使用它,你可能想先在一个独立的程序中尝试它以找出close 语义,尽管查看文档和你的要求看起来你想在最后单独关闭它。

【讨论】:

  • 感谢您的回复..你能看看我的问题中的编辑吗
  • 正如我所说,我还没有尝试过,您应该在一个小的独立程序中尝试它,例如,不要使用 socket.getInputStream(),而是使用 FileInputStream,而不是使用创建 InputSource把它打印在控制台上。但是......你最后打电话给close()吗?这很可能是它没有得到任何东西(缓冲)的原因。
【解决方案2】:

我不熟悉 Expat,但要完成您所描述的一般情况,您需要一个支持将数据推送到解析器而不是让解析器从源中提取数据的 SAX 解析器。检查 Expat 是否支持推送模型。如果是这样,那么您可以简单地从套接字读取一大块数据,将其推送到解析器,然后它将解析来自卡盘的任何内容,缓存任何剩余的数据以供下次推送时使用。根据需要重复,直到您准备好关闭套接字连接。在此模型中,\n 分隔符将被视为节点之间的杂项空白,因此您必须使用 SAX 事件来检测新的&lt;Response&gt; 节点何时打开和关闭。此外,由于您在数据中接收到多个 &lt;Response&gt; 节点,并且 XML 不允许超过 1 个顶级文档节点,因此您需要将自定义开始标记推送到解析器中,然后再开始将套接字数据推送到解析器。然后自定义开始标签将成为顶级文档节点,&lt;Response&gt; 节点将成为它的子节点。

【讨论】:

    猜你喜欢
    • 2010-12-13
    • 1970-01-01
    • 2016-02-12
    • 2013-10-30
    • 2021-02-28
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多