SORU
28 Ocak 2011, Cuma


Nasıl SAX XML çözümleyici kullanarak ayrıştırmak için

tutorial bunu takip ediyorum.

Harika çalışıyor ama son öğe ile tek bir dize yerine tüm dizeleri ile bir dizi dönmek istiyorum.

Bunu yapmak için nasıl herhangi bir fikir?

CEVAP
28 Ocak 2011, Cuma


Bunun gibi bir RSS beslemesi ayrıştırmak için bir XML ayrıştırıcı kurmak istiyorum.

<rss version="0.92">
<channel>
    <title>MyTitle</title>
    <link>http://myurl.com</link>
    <description>MyDescription</description>
    <lastBuildDate>SomeDate</lastBuildDate>
    <docs>http://someurl.com</docs>
    <language>SomeLanguage</language>

    <item>
        <title>TitleOne</title>
        <description><![CDATA[Some text.]]></description>
        <link>http://linktoarticle.com</link>
    </item>

    <item>
        <title>TitleTwo</title>
        <description><![CDATA[Some other text.]]></description>
        <link>http://linktoanotherarticle.com</link>
    </item>

</channel>
</rss>

Şimdi çalışabilirsiniz iki SAX uygulamaları var. Ya org.xml.sax android.sax uygulama kullanın. Pro açıklamak ve kısa kroşe bir örnek yazdıktan sonra hem de ... ... mahkum edeceğim.

android.sax Uygulanması

Hadi android.sax uygulaması ile başlar.

İlk XML yapısı RootElement Element nesneleri kullanarak tanımlamak zorunda.

Her durumda, veri olan POJOs (Düz Eski Java Nesneleri ile çalışmak isterim. Burada olacağını POJOs gerekli.

Channel.java

public class Channel implements Serializable {

    private Items items;
    private String title;
    private String link;
    private String description;
    private String lastBuildDate;
    private String docs;
    private String language;

    public Channel() {
        setItems(null);
        setTitle(null);
        // set every field to null in the constructor
    }

    public void setItems(Items items) {
        this.items = items;
    }

    public Items getItems() {
        return items;
    }

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

    public String getTitle() {
        return title;
    }
    // rest of the class looks similar so just setters and getters
}

Bu sınıf Bundle içine koyun ve onunla bir şeyler yapmak, böylece Serializable arabirimini uygular.

Şimdi bir sınıf öğeleri tutmak için ihtiyacımız var. Bu durumda sadece ArrayList Sınıf uzatacağım.

Items.java

public class Items extends ArrayList<Item> {

    public Items() {
        super();
    }

}

Bizim öğeler için kapsayıcı bu. Biz şimdi bir sınıf her öğenin veri tutmak gerekir.

Item.java

public class Item implements Serializable {

    private String title;
    private String description;
    private String link;

    public Item() {
        setTitle(null);
        setDescription(null);
        setLink(null);
    }

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

    public String getTitle() {
        return title;
    }

    // same as above.

}

Örnek:

public class Example extends DefaultHandler {

    private Channel channel;
    private Items items;
    private Item item;

    public Example() {
        items = new Items();
    }

    public Channel parse(InputStream is) {
        RootElement root = new RootElement("rss");
        Element chanElement = root.getChild("channel");
        Element chanTitle = chanElement.getChild("title");
        Element chanLink = chanElement.getChild("link");
        Element chanDescription = chanElement.getChild("description");
        Element chanLastBuildDate = chanElement.getChild("lastBuildDate");
        Element chanDocs = chanElement.getChild("docs");
        Element chanLanguage = chanElement.getChild("language");

        Element chanItem = chanElement.getChild("item");
        Element itemTitle = chanItem.getChild("title");
        Element itemDescription = chanItem.getChild("description");
        Element itemLink = chanItem.getChild("link");

        chanElement.setStartElementListener(new StartElementListener() {
            public void start(Attributes attributes) {
                channel = new Channel();
            }
        });

        // Listen for the end of a text element and set the text as our
        // channel's title.
        chanTitle.setEndTextElementListener(new EndTextElementListener() {
            public void end(String body) {
                channel.setTitle(body);
            }
        });

        // Same thing happens for the other elements of channel ex.

        // On every <item> tag occurrence we create a new Item object.
        chanItem.setStartElementListener(new StartElementListener() {
            public void start(Attributes attributes) {
                item = new Item();
            }
        });

        // On every </item> tag occurrence we add the current Item object
        // to the Items container.
        chanItem.setEndElementListener(new EndElementListener() {
            public void end() {
                items.add(item);
            }
        });

        itemTitle.setEndTextElementListener(new EndTextElementListener() {
            public void end(String body) {
                item.setTitle(body);
            }
        });

        // and so on

        // here we actually parse the InputStream and return the resulting
        // Channel object.
        try {
            Xml.parse(is, Xml.Encoding.UTF_8, root.getContentHandler());
            return channel;
        } catch (SAXException e) {
            // handle the exception
        } catch (IOException e) {
            // handle the exception
        }

        return null;
    }

}

Şimdi gördüğünüz gibi çok hızlı bir örnek oldu. android.sax SAX uygulamasını kullanarak büyük avantajı, ayrıştırmak ve sadece uygun elemanları için bir olay dinleyicisi ekleyin için XML yapısı tanımlayabilirsiniz. Dezavantajı kodu oldukça yinelenen ve şişmiş.

org.xml.sax Uygulanması

org.xml.sax SAX işleyicisi uygulama biraz farklı.

Burada ya da XML yapısı ama sadece olayları dinleme belirtmek ilan değilsin. En yaygın kullanılan olanlar olaylar şunlardır:

  • Belge Açın
  • Belge Sonu
  • Öğe Başlatın
  • Eleman Sonunda
  • Öğe Başlangıç arasındaki karakter ve Eleman End

Örnek işleyici bir uygulama Kanal kullanarak bu gibi görünüyor yukarıdaki nesne.

Örnek

public class ExampleHandler extends DefaultHandler {

    private Channel channel;
    private Items items;
    private Item item;
    private boolean inItem = false;

    private StringBuilder content;

    public ExampleHandler() {
        items = new Items();
        content = new StringBuilder();
    }

    public void startElement(String uri, String localName, String qName, 
            Attributes atts) throws SAXException {
        content = new StringBuilder();
        if(localName.equalsIgnoreCase("channel")) {
            channel = new Channel();
        } else if(localName.equalsIgnoreCase("item")) {
            inItem = true;
            item = new Item();
        }
    }

    public void endElement(String uri, String localName, String qName) 
            throws SAXException {
        if(localName.equalsIgnoreCase("title")) {
            if(inItem) {
                item.setTitle(content.toString());
            } else {
                channel.setTitle(content.toString());
            }
        } else if(localName.equalsIgnoreCase("link")) {
            if(inItem) {
                item.setLink(content.toString());
            } else {
                channel.setLink(content.toString());
            }
        } else if(localName.equalsIgnoreCase("description")) {
            if(inItem) {
                item.setDescription(content.toString());
            } else {
                channel.setDescription(content.toString());
            }
        } else if(localName.equalsIgnoreCase("lastBuildDate")) {
            channel.setLastBuildDate(content.toString());
        } else if(localName.equalsIgnoreCase("docs")) {
            channel.setDocs(content.toString());
        } else if(localName.equalsIgnoreCase("language")) {
            channel.setLanguage(content.toString());
        } else if(localName.equalsIgnoreCase("item")) {
            inItem = false;
            items.add(item);
        } else if(localName.equalsIgnoreCase("channel")) {
            channel.setItems(items);
        }
    }

    public void characters(char[] ch, int start, int length) 
            throws SAXException {
        content.append(ch, start, length);
    }

    public void endDocument() throws SAXException {
        // you can do something here for example send
        // the Channel object somewhere or whatever.
    }

}

Şimdi dürüst olmak gerekirse gerçekten android.sax birinin üzerine bu işleyicisi uygulama gerçek bir avantaj olduğunu söyleyemem. Ancak artık bu çok bariz olması gereken dezavantaj olduğunu söyleyebilirim. startElement yöntemi else ıf deyimi bir göz atın. Etiketler olmamız nedeniyle <title>, link description XML yapısı şu anda biz orada takip etmek zorundayız. Bu ise karşılaştığımız bir <item> başlangıç tag set inItem bayrak true sağlamak haritasını doğru veri için doğru nesne ve endElement yöntem kurduğumuz bayrak false eğer karşılaştığımız bir </item> etiket. Bu öğe etiketi ile yapmış olduğumuz signalize.

Bu örnekte çok kolay idare edilir ama farklı düzeyde yinelenen etiketleri ile daha karmaşık bir yapıya sahip ayrıştırmak zor olur. Orada daha iyi mi olurdu ya da kullanmak Çeteleler örneğin, belirlediğiniz mevcut durumu ve bir sürü düğmesi/case statemenets kontrol Neredesin ya bir daha zarif bir çözüm olabilir, bir çeşit etiket tracker kullanarak bir etiket yığını.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • EatingIn

    EatingIn

    12 EKİM 2013
  • Gee Cee

    Gee Cee

    1 AĞUSTOS 2009
  • KarnasCamillo

    KarnasCamill

    24 EKİM 2007