我正试图通过套接字连接到一个远程服务器,并且我从套接字得到大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解析器解析这些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'异常关闭我的套接字流。我问了一个关于……的问题。
现在有时我得到解析错误
org.apache.harmony.xml.ExpatParser$ParseException: At line 1, column 8: not well-formed (invalid token)
我搜索了一下,发现这个错误通常出现在实际xml的编码与SAX期望的不一样的时候。我写了一个C程序并打印出xml,我所有的xml都是用UTF-8编码的。
现在我的问题是……
- xml解析中出现上述错误是否有其他原因除了编码问题以外
- 是否有办法将输入打印(或写入任何文件)到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();
}
是否有办法将输入打印(或写入任何文件)到SAX它从套接字流?
Apache Commons有一个TeeInputStream应该是有用的。
OutputStream log = new BufferedOutputStream(new FileOutputtStream("response.xml"));
InputSource xmlInputSource = new InputSource(new
CloseShieldInputStream(new TeeInputStream(mySocket.getInputStream(), log)));
我还没有使用过它,你可能想先在一个独立的程序中尝试它来弄清楚close
语义,虽然看看文档和你的需求,看起来你想在结束时单独关闭它。
我不熟悉Expat,但是为了完成您的描述,您需要一个SAX解析器,它支持将数据推入解析器,而不是让解析器从源中提取数据。检查Expat是否支持推送模型。如果是这样,那么您可以简单地从套接字中读取数据块,将其推入解析器,解析器将解析它所能解析的任何数据,缓存任何剩余的数据,以便在下一次推入时使用。根据需要重复操作,直到您准备好关闭套接字连接。在此模型中,n
分隔符将被视为节点之间的各种空白,因此必须使用SAX事件来检测新的<Response>
节点何时打开和关闭。另外,由于在数据中接收到多个<Response>
节点,而XML不允许超过1个顶级文档节点,因此在开始将套接字数据推入解析器之前,需要将自定义的开始标记推入解析器。然后,自定义开始标记将成为顶级文档节点,<Response>
节点将是它的子节点。