【问题标题】:SAX parsing: how to fetch child nodesSAX 解析:如何获取子节点
【发布时间】:2013-01-09 13:52:54
【问题描述】:

我在 android 中使用 SAX 解析。对于以下 XML:

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
    <channel>
        <title>Game Analysis</title>
        <item>
            <title>GTA</title>
            <description>ABC</description>
            <pubDate>Sat, 21 Feb 2012 05:18:23 GMT</pubDate>
            <enclosure type="audio/mpeg" url="http://URL.mp3" length="6670315"/>
        </item>
        <item>
            <title>CoD</title>
            <description>XYZ</description>
            <pubDate>Sat, 21 Feb 2011 05:18:23 GMT</pubDate>
            <enclosure type="audio/mpeg" url="http://URL.mp3" length="6670315"/>
        </item>
    </channel>
</rss>

我需要获取&lt;title&gt; 的第一次出现(就在下面)。

然后我需要再次从每个块中提取&lt;title&gt; &amp; &lt;enclosure&gt;

我可以使用以下方法获取第一个 &lt;title&gt;: public void startElement(String uri, String localName, String qName, 属性属性)抛出 SAXException { if (qName.equals("title")) ... }

但是,我应该如何获取&lt;item&gt; block 中的标签?

【问题讨论】:

  • 谢谢..但是我应该如何区分第一个标题标签和里面的那个
  • 你找到你的答案了吗?如果是,请接受这个答案,这样对别人有用。

标签: java android xml sax


【解决方案1】:

以下是我使用 SAX 的方法。

我已经修改了一点你的 XML 文件。

XML 文件

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
    <channel>
        <title>Game Analysis</title>
        <item>
            <title>GTA</title>
            <description>ABC</description>
            <pubDate>Sat, 21 Feb 2012 05:18:23 GMT</pubDate>
            <enclosure type="audio/mpeg" url="http://URL.mp3/1" length="6670315"/>
        </item>
        <item>
            <title>CoD</title>
            <description>XYZ</description>
            <pubDate>Sat, 21 Feb 2011 05:45:10 GMT</pubDate>
            <enclosure type="audio/mpeg" url="http://URL.mp3/2" length="6670345"/>
        </item>
        <item>
            <title>AtV</title>
            <description>fgh</description>
            <pubDate>Sat, 21 Feb 2011 06:20:10 GMT</pubDate>
            <enclosure type="audio/mpeg" url="http://URL.mp3/3" length="6670364"/>
        </item>
    </channel>
    <channel>
        <title>Game Analysis 2</title>
        <item>
            <title>GTA 2</title>
            <description>ABC 2</description>
            <pubDate>Sat, 21 Feb 2012 04:18:23 GMT</pubDate>
            <enclosure type="audio/mpeg" url="http://URL.mp3/2/1" length="6670315"/>
        </item>
        <item>
            <title>CoD 2</title>
            <description>XYZ 2</description>
            <pubDate>Sat, 21 Feb 2011 04:45:10 GMT</pubDate>
            <enclosure type="audio/mpeg" url="http://URL.mp3/2/2" length="6670345"/>
        </item>
        <item>
            <title>AtV 2</title>
            <description>fgh</description>
            <pubDate>Sat, 21 Feb 2011 05:20:10 GMT</pubDate>
            <enclosure type="audio/mpeg" url="http://URL.mp3/2/3" length="6670364"/>
        </item>
    </channel>
</rss>

实体

频道

public class Channel {

    private String title;
    private ArrayList<Item> alItems;

    public Channel(){}

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public ArrayList<Item> getAlItems() {
        return alItems;
    }

    public void setAlItems(ArrayList<Item> alItems) {
        this.alItems = alItems;
    }


}

外壳

public class Enclosure {

    private String type;
    private URL url;
    private Integer length;


    public Enclosure(){}

    public String getType() {
        return type;
    }


    public void setType(String type) {
        this.type = type;
    }


    public URL getUrl() {
        return url;
    }


    public void setUrl(URL url) {
        this.url = url;
    }


    public Integer getLength() {
        return length;
    }


    public void setLength(Integer length) {
        this.length = length;
    }




}

物品

public class Item {

    private String title;
    private String description;
    private String pubDate;
    private Enclosure enclosure;

    public Item(){}

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getPubDate() {
        return pubDate;
    }

    public void setPubDate(String pubDate) {
        this.pubDate = pubDate;
    }

    public Enclosure getEnclosure() {
        return enclosure;
    }

    public void setEnclosure(Enclosure enclosure) {
        this.enclosure = enclosure;
    }



}

处理程序

ChannelHandler

public class ChannelHandler extends DefaultHandler{

    private ArrayList<Channel> alChannels;
    private Channel channel;
    private String reading;
    private ArrayList<Item> alItems;
    private Item item;
    private Enclosure enclosure;

    public ChannelHandler(){
        super();
    }

    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {

        if(qName.equals("rss")){
                alChannels = new ArrayList<>();
        }
        else if(qName.equals("channel")){
            channel = new Channel();
        }
        else if(qName.equals("item")){
            item = new Item();
        }
        else if(qName.equals("enclosure")){

            enclosure = new Enclosure();
            enclosure.setType(attributes.getValue("type"));
            try {
                enclosure.setUrl(new URL(attributes.getValue("url")));
            } catch (MalformedURLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            enclosure.setLength(Integer.parseInt(attributes.getValue("length")));

        }

    }

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {

        if(qName.equals("channel")){
            channel.setAlItems(alItems);
            alChannels.add(channel);
            alItems = null;
        }
        if(qName.equals("title")){

            if(alItems == null){
                channel.setTitle(reading);
                alItems = new ArrayList<>();
            }
            else if(item != null) {
                item.setTitle(reading);
            }

        }
        else if(qName.equals("item")){

            if(alItems != null){
                alItems.add(item);
                item = null;
            }

        }
        else if(qName.equals("description")){
            item.setDescription(reading);
        }
        else if(qName.equals("pubDate")){
            item.setPubDate(reading);
        }
        else if(qName.equals("enclosure")){
            item.setEnclosure(enclosure);
        }

    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        reading = new String(ch, start, length);
    }

    public ArrayList<Channel> getAlChannels() {
        return alChannels;
    }


}

经理

XML 管理器

public final class XMLManager {


    public static ArrayList<Channel> getAlChannels(){
        ArrayList<Channel> alChannels = null;
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            SAXParser parser = factory.newSAXParser();
            File file = new File("D:\\Loic_Workspace\\TestSAX2\\res\\test.xml");
            ChannelHandler channelHandler = new ChannelHandler();
            parser.parse(file, channelHandler);
            alChannels = channelHandler.getAlChannels();
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return alChannels;
    }

}

主要

我的主页面

public class MyMain {

    /**
     * @param args
     */
    public static void main(String[] args) {

        Enclosure enclosure = null;
        for(Channel channel : XMLManager.getAlChannels()){
            System.out.println("Channel title : "+channel.getTitle());
            System.out.println("------------------------");
            for(Item i:channel.getAlItems()){
                System.out.println(i.getTitle());
                System.out.println(i.getPubDate());
                System.out.println("Enclosure : ");
                enclosure = i.getEnclosure();
                System.out.println(enclosure.getType());
                System.out.println(enclosure.getUrl());
                System.out.println(enclosure.getLength());
                System.out.println("------------------------");
            }
        }




    }

}

控制台输出

Channel title : Game Analysis
------------------------
GTA
Sat, 21 Feb 2012 05:18:23 GMT
Enclosure : 
audio/mpeg
http://URL.mp3/1
6670315
------------------------
CoD
Sat, 21 Feb 2011 05:45:10 GMT
Enclosure : 
audio/mpeg
http://URL.mp3/2
6670345
------------------------
AtV
Sat, 21 Feb 2011 06:20:10 GMT
Enclosure : 
audio/mpeg
http://URL.mp3/3
6670364
------------------------
Channel title : Game Analysis 2
------------------------
GTA 2
Sat, 21 Feb 2012 04:18:23 GMT
Enclosure : 
audio/mpeg
http://URL.mp3/2/1
6670315
------------------------
CoD 2
Sat, 21 Feb 2011 04:45:10 GMT
Enclosure : 
audio/mpeg
http://URL.mp3/2/2
6670345
------------------------
AtV 2
Sat, 21 Feb 2011 05:20:10 GMT
Enclosure : 
audio/mpeg
http://URL.mp3/2/3
6670364
------------------------

所以它起作用了;)

【讨论】:

    【解决方案2】:

    SAX 不适合这项工作。使用 DOM 和 XPath 可以轻松解决您的要求。

    【讨论】:

    • DOM 对于我的要求来说实际上有点重。而 SAX 来自 android
    • @raul8 - DOM 也是如此。而且我不知道“有点重”是什么意思。如果您可以减少编写的代码量,那对我来说似乎更轻松。但这是你的项目,所以做任何让你开心的事情。
    • dom 一次生成 个对象,在任何移动平台上通常都是一个糟糕的选择。根据 XML 的大小,它甚至可以杀死你的堆空间——你只是无法将 100mb 的 XML 文件解析为 android 上的 dom 模型。
    • @meredrica - 感谢您解释了您的反对意见。但是,您的推理充满了 FUD。首先,我会质疑 any 试图在移动设备上解析 any 100 Mb 文件的设计。你真的必须这样做吗?其次,虽然我同意 DOM 创建了很多对象,但您是否考虑过 SAX 创建了多少对象?两种形式的基础数据都是相同的;实际上,DOM 是使用 SAX 解析器构建的。它只是保留所有对象,而不是立即将它们交给垃圾收集器。
    • 是的,我已经这样做了一百万次了。你需要做的比你想象的要多得多。也许不是 100 mb,但你真的很快就达到了 20-30 mb,这已经太多了。 SAX 根本不会创建不必要的对象。它只创建您以后需要的对象,因为您自己创建了它们。如果使用 SAX 炸毁堆空间,则需要重做设计或在其间使用数据库。如果您只使用 SAX 解析器并将 XML 提供给它,您将不会分配大量对象本身。将其与 DOM 进行比较。
    【解决方案3】:

    您使用堆栈(或类似的)并记住您需要的任何内容。 SAX 是基于事件的,因此您必须自己管理有关您所在位置的信息。 考虑这样的事情:

    public Parser extends ....
        private Item item;
        private StringBuffer buffer;
    
        startElement(String uri,)...{
            buffer = new StringBuffer();
        }
        characters(...) {
            buffer.append(...); // sorry, coding by memory directly on SO, can't remember correct syntax.
        }
        endElement(String uri, String qName...) {
            if(qName.equals("item") {
                handleOldItem();
                item = new Item();
            } else if(qname.equals("title") {
                item.setTitle(buffer.toString());
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      就地 SAX 解析器使用 Dom 解析器,以下是您的完整答案:-

      DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
                      .newInstance();
              documentBuilderFactory.setCoalescing(true);
              DocumentBuilder documentBuilder = documentBuilderFactory
                      .newDocumentBuilder();
              Document document = documentBuilder.parse(new InputSource(is));
                  title =   document.getElementsByTagName("title").item(0).getFirstChild().getNodeValue().trim();
              itemList = document.getElementsByTagName("item");
              for (int i = 0; i < itemList .getLength(); i++) {
                  if(itemModel == null){
                      itemModel = new ItemModel();
                  }
                  if(arrListItemModel==null){
                      arrListItemModel= new ArrayList<ItemModel>();
                  }
                  itemItem = (Element)itemList .item(i);
                  itemModel.setTitle(itemItem                                                                                                                          .getElementsByTagName("title").item(0).getFirstChild().getNodeValue().trim());
                  itemModel.setDescription(itemItem .getElementsByTagName("description").item(0).getFirstChild().getNodeValue().trim());
                  itemModel.setPubDate(itemItem .getElementsByTagName("pubDate").item(0).getFirstChild().getNodeValue().trim());
                  itemModel.setEnclosure(itemItem .getElementsByTagName("enclosure ").item(0).getFirstChild().getNodeValue().trim());
                  arrListItemModel.add(tippsModel);
                  itemModel =null;
              }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-28
        • 2015-11-10
        • 2011-05-16
        • 2011-01-05
        • 1970-01-01
        • 2023-03-10
        • 2023-03-10
        • 1970-01-01
        相关资源
        最近更新 更多