2010-04-06 97 views
2

採取格式化這樣一個簡單的XML文件:計數XML元素在Android

<Lists> 
<List> 
<Note/> 
... 
<Note/> 
</List> 
<List> 
<Note/> 
... 
<Note/> 
</List> 
</Lists> 

每個節點都有實際保存文件的數據的某些屬性。我需要一種非常快速的方法來計算每種元素的數量(列表和註釋)。列表僅僅是根,並不重要。

我可以用一個簡單的字符串搜索或類似的東西來做到這一點,但我需要儘可能快地做到這一點。

設計參數:
必須在java(Android應用程序)中。
必須AVOID儘可能分配內存。
無論文件中的位置如何,都必須返回文件中Note元素的總數和List元素的數量。

列表數量通常很小(1-4),並且每個文件的筆記數可能非常大(大於1000,通常爲100)。

我期待您的建議。

+0

這個問題是不是代碼高爾夫球,但現實生活中的問題。刪除「代碼高爾夫」標籤。 – 2010-04-06 16:33:16

回答

2

XmlPullParser是流拉XML解析器,當有需要快速有效地處理所有輸入要素都應該使用。

你可以嘗試這樣的事情:

private void pullParserSample(FileInputStream xml) { 
    int lists = 0; 
    int notes = 0; 
    int eventType = -1; 

    try { 
     XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser(); 
     xpp.setInput(new InputStreamReader(xml)); 

     eventType = xpp.getEventType(); 

     do { 
      switch (eventType) { 

      case XmlPullParser.START_TAG: 
       final String tag = xpp.getName(); 
       if ("Note".equals(tag)) { 
        notes++; 
       } 
       else if ("List".equals(tag)) { 
        lists++; 
       } 
       break; 

      } 

     } while ((eventType = xpp.next()) != XmlPullParser.END_DOCUMENT) ; 

    } catch (XmlPullParserException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    Log.d(TAG, "lists=" + lists + " notes=" + notes); 
} 
0

看看實現org.xml.sax.ContentHandler並將其發送到org.xml.sax.XMLReader。

這些類與Android SDK捆綁在一起。這是一種「前向解析器」方法,當文檔從開始到結束處理時,涉及ContentHandler的每個XML元素(標籤,屬性,文本)。正向語法分析器方法在內存使用上很輕鬆,而且比構建DOM更快。

+0

Sax因爲解析所有內容而花費太長時間。我只需要計算節點數量,一個更有效的方法必須在那裏。 – CodeFusionMobile 2010-04-06 16:48:13

1

如果您只是要計算文本中的元素而不是解析文檔,您可以依次從文件中讀取每行並使用Pattern/Matcher類(我忘記了它)檢查該行是否匹配「<Note> 「或」<List>「,並分別遞增計數器。

編輯:另類的想法

通過文件一個字符的時間閱讀,當你遇到一個「<」的性格,開始附加所有後續字符是不是一個「>」字符到一個StringBuilder。然後,當你遇到一個「>」符號時,比較StringBuilder字符串到「Note」或「List」或其他什麼,並相應地增加計數器。最後,清除StringBuilder並重復,直到文檔結束。

+0

你的意思是使用正則表達式?這些在Android上極其昂貴。 – CodeFusionMobile 2010-04-06 17:40:45

+0

不一定需要正則表達式,如果標籤是在它們自己的行上,那麼你可以修剪行中的空白,並使用String.equals()方法。 – Moonshield 2010-04-06 19:27:44

+0

這些字符串方法需要內存分配,這在移動設計中也很重要。一些內存將被分配,但是如果可能的話,它應該避免具有O(n)關係。 – CodeFusionMobile 2010-04-16 17:41:44

0

quick dirty未經測試的解決方案,使用生成的狀態機Ragel。 把這個餵給ragel,它會爲你生成java代碼。

生成的代碼將使用具有常量內存要求(表和狀態變量)的基於表的FSM分析器。它也可以接受部分數據,你可以在任何位置恢復它。

這可能比任何通用解析器或系統的正則表達式都快。 (免責聲明:我不是Java程序員,因爲它缺少運行所需的框架代碼,所以也不是以下任何方式完成的,但是它可能是一個體面的基礎。)

%%{ 
    machine nodecounter; 

    note = '<Note' @{notes++;}; 
    list = '<List' ^'s' @{lists++;}; 
    set = note | list; 
    main := (set | ^set)*; 
}%% 

%% write data; 

%% write init; 

/* */ 
%% write exec;