2

私は現在、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」を無視するように設定できるものはありますか?

4

2 に答える 2

0

xmlファイル全体をパーサーに渡しているように見えるため、ファイルが大きすぎると、outOfMemory例外が発生します。

ソケットからの出力をチャンクで読み取り、パーサーにフィードするようにしてください。したがって、ループ内でxr.parse()を実行します。

于 2011-08-13T09:46:34.700 に答える
0

別の投稿がSOで私の問題で作成され、そこの答えは私の問題の解決策でした。

この問題を抱えている人のための解決策は次のとおりです。

ソケットから xml データの大きなチャンクを読み取り、オンザフライで解析する

于 2011-08-16T06:44:48.257 に答える