私は現在、TCP ソケットを作成し、着信 xml をサーバーにリッスンするプロジェクトに取り組んでいます。xml はかなり大きい場合があり、約 1 ~ 3 MB になります。xml はソケットから送信され続けるため、送信時に解析する必要があります。DomParser、XMLPullParser、SaxParser などの多くのパーサーを試しました。サックスが一番速かったのでそちらに進みました。しかし、今では時々 OutOfMemory 例外が発生します。
この投稿で、パーサーにデータをチャンクで送信する必要があることを読みました。
AndroidアプリケーションでWebサービスから巨大なxmlデータを解析するには?
誰かがそれがどのように行われるか教えてもらえますか. 私の現在のコードは
InputSource xmlInputSource = new InputSource(new StringReader(response));
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = null;
XMLReader xr = null;
try{
sp = spf.newSAXParser();
xr = sp.getXMLReader();
ParseHandler xmlHandler = new ParseHandler(context.getSiteListArray().indexOf(website), context);
xr.setContentHandler(xmlHandler);
xr.parse(xmlInputSource);
postSuccessfullParsingNotification();
}catch(SAXException e){
e.printStackTrace();
}catch(ParserConfigurationException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
e.toString();
}
response は、ソケットから受け取った文字列です。
VTD-XML のような他のパーサーを調べる必要がありますか? または、Sax を効率的に機能させる方法はありますか?
ところで:新しい文字列がソケットに到着して解析されるたびに、文字列を解析するために新しいスレッドを開きます。
This is my handler code
public class ParseHandler extends DefaultHandler {
private Website mWebsite;
private Visitor mVisitor;
private VisitorInfo mVisitorInfo;
private boolean isVisit;
private boolean isVisitor;
private AppContext appContext;
public ParseHandler(int index,AppContext context){
appContext = context;
mWebsite = appContext.getSiteListArray().get(index);
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
}
@Override
public void startElement(String namespaceURI, String localName,String qName, Attributes atts)
throws SAXException {
if(localName.equals("visit")) {
isVisit = true;
} else if(localName.equals("visitor") && isVisit) {
isVisitor = true;
mVisitor = new Visitor();
mVisitor.mDisplayName = "Visitor - #"+atts.getValue("id");
mVisitor.mVisitorId = atts.getValue("id");
mVisitor.mStatus = atts.getValue("idle");
} else if(localName.equals("info") && isVisitor){
mVisitorInfo = mVisitor.new VisitorInfo();
mVisitorInfo.mBrowser = atts.getValue("browser");
mVisitorInfo.mBrowserName = atts.getValue("browser").replace("+", " ");
mVisitorInfo.mCity = atts.getValue("city").replace("+", " ");
mVisitorInfo.mCountry = atts.getValue("country");
mVisitorInfo.mCountryName = atts.getValue("country");
mVisitorInfo.mDomain = atts.getValue("domain");
mVisitorInfo.mIp = atts.getValue("ip");
mVisitorInfo.mLanguage = atts.getValue("language");
mVisitorInfo.mLatitude = atts.getValue("lat");
mVisitorInfo.mLongitude = atts.getValue("long");
mVisitorInfo.mOrg = atts.getValue("org").replace("+", " ");
mVisitorInfo.mOs = atts.getValue("os");
mVisitorInfo.mOsName = atts.getValue("os").replace("+", " ");
mVisitorInfo.mRegion = atts.getValue("region").replace("+", " ");
mVisitorInfo.mScreen = atts.getValue("screen");
}
}
@Override
public void characters(char ch[], int start, int length) {
}
@Override
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
if(localName.equals("visit")) {
isVisit = false;
} else if(localName.equals("visitor")) {
isVisitor = false;
if(mVisitor == null){
Log.e("mVisitor","mVisitor");
} else if(mVisitor.mVisitorId == null){
Log.e("mVisitor.mVisitorId","mVisitor.mVisitorId");
}
mWebsite.mVisitors.put(mVisitor.mVisitorId, mVisitor);
} else if(localName.equals("info") && isVisitor) {
mVisitor.mVisitorInfo = mVisitorInfo;
}
}
@Override
public void endDocument() throws SAXException {
}
}
**
編集:考えた後..
**
さらに調査したところ、解析が例外を引き起こしていないことがわかりました。ソケットからストリームを受信するたびに、それを文字列に格納し、ストリームに "\n" が入るまでそれを追加し続けます。「\n」は、xml のブロックの終わりを示すために使用されます。文字列が原因でメモリ例外が発生しています。私はStringBuilderを試しましたが、それも同じ問題を引き起こしました。なぜこれが起こっているのかわかりません。
ここで、解析のために入力ストリームを直接送信しようとしましたが、最後に「\ n」が原因で解析例外が発生します。パーサーが「\n」を無視するように設定できるものはありますか?