如何使用SAX解析器解析命名空间?

时间:2010-08-14 15:46:47

标签: java android xml parsing

使用Twitter搜索网址即。 http://search.twitter.com/search.rss?q=android返回包含以下项目的CSS:

<item>
      <title>@UberTwiter still waiting for @ubertwitter  android app!!!</title>
      <link>http://twitter.com/meals69/statuses/21158076391</link>
      <description>still waiting for an app!!!</description>
      <pubDate>Sat, 14 Aug 2010 15:33:44 +0000</pubDate>
      <guid>http://twitter.com/meals69/statuses/21158076391</guid>
      <author>Some Twitter User</author>
      <media:content type="image/jpg" height="48" width="48" url="http://a1.twimg.com/profile_images/756343289/me2_normal.jpg"/>
      <google:image_link>http://a1.twimg.com/profile_images/756343289/me2_normal.jpg</google:image_link>
      <twitter:metadata>
        <twitter:result_type>recent</twitter:result_type>
</twitter:metadata>
</item>

非常简单。我的代码解析了所有内容(标题,链接,描述,pubDate等),没有任何问题。但是,我正在使用null:

<google:image_link>

我正在使用Java来解析RSS提要。我是否必须以不同于更简单的本地名称来处理复合本地名称?

这是解析Link,Description,pubDate等的代码:

@Override
    public void endElement(String uri, String localName, String name)
            throws SAXException {
        super.endElement(uri, localName, name);
        if (this.currentMessage != null){
            if (localName.equalsIgnoreCase(TITLE)){
                currentMessage.setTitle(builder.toString());
            } else if (localName.equalsIgnoreCase(LINK)){
                currentMessage.setLink(builder.toString());
            } else if (localName.equalsIgnoreCase(DESCRIPTION)){
                currentMessage.setDescription(builder.toString());
            } else if (localName.equalsIgnoreCase(PUB_DATE)){
                currentMessage.setDate(builder.toString());
            } else if (localName.equalsIgnoreCase(GUID)){
                currentMessage.setGuid(builder.toString());
            } else if (uri.equalsIgnoreCase(AVATAR)){
                currentMessage.setAvatar(builder.toString());
            } else if (localName.equalsIgnoreCase(ITEM)){
                messages.add(currentMessage);
            } 
            builder.setLength(0);   
        }
    }

startDocument看起来像:

@Override
    public void startDocument() throws SAXException {
        super.startDocument();
        messages = new ArrayList<Message>();
        builder = new StringBuilder();

    }

startElement看起来像:

@Override
    public void startElement(String uri, String localName, String name,
            Attributes attributes) throws SAXException {
        super.startElement(uri, localName, name, attributes);
        if (localName.equalsIgnoreCase(ITEM)){
            this.currentMessage = new Message();
        } 
    }

5 个答案:

答案 0 :(得分:1)

<google:image_link>这样的元素具有属于image_link命名空间的本地名称google。您需要确保XML解析框架知道命名空间,然后您需要使用适当的命名空间来查找此元素。

例如,package org.xml.sax中的一些SAX1接口已被弃用,取而代之的是包含命名空间支持的SAX2对应(例如SAX1 Parser已被弃用并被SAX2 XMLReader取代)。请参阅有关如何指定名称空间uri或限定(加前缀)qName的文档。

另见

答案 1 :(得分:1)

从示例中,实际上并不清楚'google'前缀绑定到哪个命名空间 - 之前的答案稍有不正确,因为它不在“google”命名空间中;相反,它是前缀“google”绑定的名称空间。因此,您必须匹配命名空间(由URI标识),而不是前缀。 SAX确实有令人困惑的方式报告本地名称/名称空间前缀组合,它取决于是否启用了名称空间处理。

您还可以考虑其他XML处理库/ API;虽然SAX实现具有高性能,但有更快,更方便的替代方案。像Woodstox这样的Stax(javax.xml.stream。*)实现(甚至是JDK 1.6附带的默认实现)都快速且方便。构建在Stax之上的StaxMate库更易于用于读取和写入,并且像Xerces这样的SAX实现速度快。加上Stax API在命名空间处理方面的行李更少,因此更容易看到元素的实际命名空间。

答案 2 :(得分:0)

与用户polygenelubricants说:通常解析器需要知道名称空间来处理属于某个前缀命名空间的元素。 (就像那个<google:image_link>元素一样。)

这需要设置为“解析器功能”,AFAIK可以通过几种不同的方式完成:XMLReader接口本身具有方法setFeature(),可用于为某个解析器设置功能,但您也可以对SAXParserFactory类使用相同的方法,以便此工厂生成已经打开或关闭这些功能的解析器。 SAX2标准功能标志应该在SAXproject的网站上,但至少其中一些标志也列在包org.xml.sax的Java API文档中。

对于简单文档,您可以尝试使用快捷方式。如果您实际上并不像URL +本地名称组合那样关心名称空间和元素名称,并且您可以相信您要查找的元素(并且只有这些元素)始终具有某些前缀,并且没有来自具有相同本地名称的其他名称空间然后您可以通过qname方法使用startElement()方法而不是localName或反之亦然或通过添加/删除标记名称字符串中的前缀来解决您的问题你比较。

参数namespaceUriqnamelocalName的内容根据Java规范实际上是可选的,而AFAIK则可能是null因此。它们中的哪些是null取决于那些影响命名空间的前述“解析器功能”。我不知道null的参数是否可以在命名空间中的元素和没有命名空间的元素之间变化 - 我没有调查过这种行为。

PS。 XML区分大小写。理想情况下,您不需要忽略标记名称字符串比较中的大小写。
-First post,yay!

答案 3 :(得分:0)

可以帮助某人使用Android SAX util。我正在尝试使用geo:lat来获取地理名称空间的lat元素。

示例XML:

<item> 
 <title>My Item title</title> 
 <geo:lat>40.720741</geo:lat> 
</item>

第一次尝试返回null:

item.getChild("geo:lat");

如上所述,我发现将名称空间URI传递给getChild方法。

item.getChild("http://www.w3.org/2003/01/geo/wgs84_pos#", "lat");

答案 4 :(得分:0)

使用我的xml处理程序的startPrefixMapping方法,我能够解析出命名空间的文本。

我在处理程序实例化下面对这个方法进行了多次调用。

GoogleReader xmlhandler = new GoogleReader();
xmlhandler.startPrefixMapping("dc", "http://purl.org/dc/elements/1.1/");

其中dc是命名空间<dc:author>some text</dc:author>