计数XML元素在Android

问题描述:

采取格式化这样一个简单的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

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); 
} 

看看实现org.xml.sax.ContentHandler并将其发送到org.xml.sax.XMLReader。

这些类与Android SDK捆绑在一起。这是一种“前向解析器”方法,当文档从开始到结束处理时,涉及ContentHandler的每个XML元素(标签,属性,文本)。正向语法分析器方法在内存使用上很轻松,而且比构建DOM更快。

+0

Sax因为解析所有内容而花费太长时间。我只需要计算节点数量,一个更有效的方法必须在那里。 – CodeFusionMobile 2010-04-06 16:48:13

如果您只是要计算文本中的元素而不是解析文档,您可以依次从文件中读取每行并使用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

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;