2011-01-28 13 views
57

का उपयोग कर XML का विश्लेषण कैसे करें मैं इस tutorial का पालन कर रहा हूं।SAX पार्सर

यह बहुत अच्छा काम करता है लेकिन मैं इसे अंतिम तत्व के साथ एक स्ट्रिंग के बजाय सभी तारों के साथ एक सरणी वापस करना चाहता हूं।

कोई भी विचार है कि यह कैसे करना है?

+0

आप अपने XML संरचना का एक अमूर्त चित्रण पोस्ट कृपया सकते हैं: इस पार्सर चलाने के लिए आपको इस कोड का उपयोग कर सकते हैं? –

+0

http://dearfriends.se/category/blog/feed/rss/ -> स्रोत देखें – Johan

उत्तर

178

तो आप इस तरह एक आरएसएस फ़ीड पार्स करने के लिए एक एक्सएमएल पार्सर बनाना चाहते हैं।

<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> 

अब आपके पास दो सैक्स कार्यान्वयन हैं जिनके साथ आप काम कर सकते हैं। या तो आप org.xml.sax या android.sax कार्यान्वयन का उपयोग करते हैं। मैं एक लघु हैंडर उदाहरण पोस्ट करने के बाद दोनों के प्रो और कॉन की व्याख्या करने जा रहा हूं।

android.sax कार्यान्वयन

के android.sax कार्यान्वयन के साथ शुरू करते हैं।

आपको पहले RootElement और Element ऑब्जेक्ट्स का उपयोग करके XML संरचना को परिभाषित करना होगा।

किसी भी मामले में मैं पीओजेओ (सादा ओल्ड जावा ऑब्जेक्ट्स) के साथ काम करता हूं जो आपके डेटा को पकड़ लेगा। यहां पीओजेओ की आवश्यकता होगी।

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 
} 

इस वर्ग Serializable इंटरफ़ेस ताकि आप इसे एक Bundle में डाल दिया है और इसके साथ कुछ कर सकते हैं लागू करता है।

अब हमें अपने सामान रखने के लिए एक कक्षा की आवश्यकता है। इस मामले में मैं बस ArrayList कक्षा का विस्तार करने जा रहा हूं।

Items.java

public class Items extends ArrayList<Item> { 

    public Items() { 
     super(); 
    } 

} 

हमारे आइटम कंटेनर के लिए यह Thats। अब हमें प्रत्येक आइटम के डेटा को पकड़ने के लिए कक्षा की आवश्यकता है।

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. 

} 

उदाहरण:

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

} 

अब जब कि एक बहुत ही त्वरित उदाहरण था, जैसा कि आप देख सकते हैं। android.sax SAX कार्यान्वयन का उपयोग करने का मुख्य लाभ यह है कि आप उस XML की संरचना को परिभाषित कर सकते हैं जिसे आप पार्स करना चाहते हैं और फिर उचित तत्वों में एक ईवेंट श्रोता जोड़ें। नुकसान यह है कि कोड काफी दोहराने और फुलाया जाता है।

org.xml.sax कार्यान्वयन

org.xml.sax SAX हैंडलर कार्यान्वयन थोड़ा अलग है।

यहां आप एक्सएमएल संरचना निर्दिष्ट या घोषित नहीं करते हैं बल्कि घटनाओं को सुनते हैं।सबसे व्यापक रूप से इस्तेमाल किया लोगों को घटनाओं निम्नलिखित हैं:

  • दस्तावेज़ प्रारंभ
  • दस्तावेज़ समाप्ति
  • तत्व प्रारंभ
  • तत्व समाप्ति

    एक उदाहरण तत्व प्रारंभ और तत्व समाप्ति और

  • वर्ण उपरोक्त चैनल ऑब्जेक्ट का उपयोग करके हैंडलर कार्यान्वयन इस तरह दिखता है।

    उदाहरण

    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. 
        } 
    
    } 
    

    अब ईमानदारी से मैं वास्तव में आप android.sax से अधिक इस हैंडलर कार्यान्वयन के किसी भी वास्तविक लाभ नहीं बता सकता। हालांकि मैं आपको नुकसान बता सकता हूं जो अब तक स्पष्ट होना चाहिए। startElement विधि में कथन अगर अन्यथा देखें। तथ्य यह है कि हम टैग <title>, link और description हम XML संरचना हम इस समय कर रहे हैं में ट्रैक करने के लिए होता है के कारण। यही कारण है कि अगर हम एक <item> शुरू करने टैग हम true को inItem ध्वज सेट सुनिश्चित करने के लिए कि हम सही वस्तु के लिए सही डेटा को मैप मुठभेड़ और endElement विधि में हम false है कि ध्वज सेट अगर हम एक </item> टैग मुठभेड़ है। सिग्नल करने के लिए कि हम उस आइटम टैग के साथ कर रहे हैं।

    इस उदाहरण में यह है कि प्रबंधन करने के लिए, लेकिन विभिन्न स्तरों में टैग दोहरा साथ एक अधिक जटिल संरचना पार्स करने के लिए हो रही मुश्किल हो जाता है बहुत आसान है। वहां आपको या तो एनम का उपयोग करना होगा उदाहरण के लिए अपने वर्तमान राज्य और बहुत सारे स्विच/केस स्टेटमेनेट्स को सेट करने के लिए, जहां आप हैं या एक अधिक सुरुचिपूर्ण समाधान टैग स्टैक का उपयोग करके किसी प्रकार का टैग ट्रैकर होगा।

  • +0

    @Adinia ध्यान दें कि दोनों कार्यान्वयन एक साथ उपयोग करने में कोई समस्या नहीं है। ऐसा करने में कोई समस्या नहीं है जब तक आप जानते हों कि आप ऐसा क्यों करते हैं। –

    +0

    @ ऑक्टोवियन-डेमियन यह सच है कि मेरा कोड काम कर रहा था, लेकिन वास्तव में नहीं पता था कि मैंने हर पंक्ति क्यों लिखी है; मैं इसे थोड़ा सा साफ करने की कोशिश करता हूं, क्योंकि मुझे समझ में आया कि उनमें से प्रत्येक कैसे काम कर रहा है। तो नोट के लिए धन्यवाद कि दोनों एक साथ उपयोग करना ठीक है। – Adinia

    +0

    @ एडिएनिया मैं देखता हूं। आपका स्वागत है। यदि आपके पास इसके बारे में अधिक सवाल है तो आप शांत [एंड्रॉइड चैट रूम] (http://chat.stackoverflow.com/rooms/15/android) में भी शामिल हो सकते हैं। –

    2

    कई समस्याओं में यह विभिन्न प्रयोजनों के लिए एक्सएमएल फ़ाइलें के विभिन्न प्रकार का उपयोग करने के लिए आवश्यक है। मैं अखंडता को समझने और अपने अनुभव से बताने की कोशिश नहीं करूंगा कि मुझे यह सब चाहिए।

    जावा, शायद, मेरी पसंदीदा प्रोग्रामिंग भाषा। इसके अलावा, इस प्यार को इस तथ्य से मजबूत किया जाता है कि आप किसी भी समस्या का समाधान कर सकते हैं और बाइक के साथ आना आवश्यक नहीं है।

    इसलिए, यह मुझे एक डेटाबेस है कि ग्राहक को दूरस्थ डेटाबेस सर्वर में प्रविष्टियों बनाने के लिए अनुमति होगी चल क्लाइंट-सर्वर का एक समूह बनाने के लिए ले लिया। इनपुट डेटा, आदि की जांच करने की आवश्यकता नहीं है, लेकिन यह इसके बारे में नहीं है।

    काम का एक सिद्धांत के रूप में, मैं, बिना किसी हिचकिचाहट के, जानकारी के संचरण एक्सएमएल फ़ाइल के रूप में चुना है। निम्नलिखित प्रकार के:

    <? xml version = "1.0" encoding = "UTF-8" standalone = "no"?> 
    <doc> 
    <id> 3 </ id> 
    <fam> Ivanov </ fam> 
    <name> Ivan </ name> 
    <otc> I. </ otc> 
    <dateb> 10-03-2005 </ dateb> 
    <datep> 10-03-2005 </ datep> 
    <datev> 10-03-2005 </ datev> 
    <datebegin> 09-06-2009 </ datebegin> 
    <dateend> 10-03-2005 </ dateend> 
    <vdolid> 1 </ vdolid> 
    <specid> 1 </ specid> 
    <klavid> 1 </ klavid> 
    <stav> 2.0 </ stav> 
    <progid> 1 </ progid> 
    </ doc> 
    

    यह आसान किसी भी आगे पढ़ने के लिए, सिवाय इसके कि यह डॉक्टरों संस्थानों के बारे में जानकारी है। अंतिम नाम, पहला नाम, अद्वितीय आईडी, और इसी तरह। सामान्य रूप से, डेटा श्रृंखला। यह फ़ाइल सुरक्षित रूप से सर्वर की तरफ मिल गई है, और फिर फ़ाइल को पार्स करना शुरू करें।

    दो विकल्प (SAX बनाम डोम) पार्स करने के

    मैं तथ्य यह है कि वह और अधिक उज्ज्वल काम करता है की SAX दृश्य चुना है, और वह पहले मैं हाथ :)

    So. में गिर गई था जैसा कि आप जानते हैं, पार्सर के साथ सफलतापूर्वक काम करने के लिए, हमें आवश्यक विधियों को डिफॉल्ट हैंडलर को ओवरराइड करने की आवश्यकता है। शुरू करने के लिए, आवश्यक संकुल कनेक्ट करें।

    import org.xml.sax.helpers.DefaultHandler; 
    import org.xml.sax. *; 
    

    अब हम हमारी पार्सर लेखन शुरू कर सकते हैं

    public class SAXPars extends DefaultHandler { 
       ... 
    } 
    

    की विधि startDocument साथ शुरू करते हैं()। जैसा कि नाम का तात्पर्य है, दस्तावेज़ की शुरुआत में एक घटना पर प्रतिक्रिया करता है। यहाँ आप इस तरह के स्मृति आवंटन के रूप में कार्रवाई की एक किस्म लटका कर सकते हैं, या मान पुनर्स्थापित करने के लिए, लेकिन हमारे उदाहरण बहुत सरल है, बस एक उचित संदेश के काम की शुरुआत का प्रतीक तो:

    Override 
    public void startDocument() throws SAXException { 
       System.out.println ("Start parse XML ..."); 
    } 
    

    अगला। पार्सर दस्तावेज़ के माध्यम से चला जाता है इसकी संरचना के तत्व को पूरा करता है। स्टार्ट विधि प्रारंभ प्रारंभ()। और वास्तव में, उसकी उपस्थिति यह: स्टार्ट एलिमेंट (स्ट्रिंग नेमस्पेसुरि, स्ट्रिंग लोकलनाम, स्ट्रिंग क्यूनाम, एट्रिब्यूट्स एट्स)। यहां नामस्थान - नामस्थान, स्थानीय नाम - तत्व का स्थानीय नाम, qName- नामस्थान के साथ स्थानीय नाम का संयोजन (एक कोलन से अलग) और एट्स - इस तत्व के गुण। इस मामले में, सभी सरल। यह qName'om का उपयोग करने के लिए पर्याप्त है और इसे इस सेवा लाइन में कुछ सेवा लाइन में फेंक देता है। इस प्रकार हम चिह्नित करते हैं कि इस समय तत्व कौन सा है।

    @Override 
    public void startElement (String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 
       thisElement = qName; 
    } 
    

    अगला, बैठक आइटम हम इसका अर्थ प्राप्त करते हैं। यहां विधियों के वर्ण() शामिल हैं। उसके पास फॉर्म है: अक्षर (char [] ch, int start, int length)। खैर यहाँ सब कुछ स्पष्ट है। ch - एक फ़ाइल जिसमें स्ट्रिंग स्वयं तत्व के भीतर स्वयं महत्व रखती है। प्रारंभ और लंबाई - लाइन और लंबाई में शुरुआती बिंदु को इंगित करने वाली सेवा की संख्या।

    @Override 
    public void characters (char [] ch, int start, int length) throws SAXException { 
       if (thisElement.equals ("id")) { 
          doc.setId (new Integer (new String (ch, start, length))); 
       } 
       if (thisElement.equals ("fam")) { 
          doc.setFam (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("name")) { 
          doc.setName (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("otc")) { 
          doc.setOtc (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("dateb")) { 
          doc.setDateb (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("datep")) { 
          doc.setDatep (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("datev")) { 
          doc.setDatev (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("datebegin")) { 
          doc.setDatebegin (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("dateend")) { 
          doc.setDateend (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("vdolid")) { 
          doc.setVdolid (new Integer (new String (ch, start, length))); 
       } 
       if (thisElement.equals ("specid")) { 
          doc.setSpecid (new Integer (new String (ch, start, length))); 
       } 
       if (thisElement.equals ("klavid")) { 
          doc.setKlavid (new Integer (new String (ch, start, length))); 
       } 
       if (thisElement.equals ("stav")) { 
          doc.setStav (new Float (new String (ch, start, length))); 
       } 
       if (thisElement.equals ("progid")) { 
          doc.setProgid (new Integer (new String (ch, start, length))); 
       } 
    } 
    

    आह, हाँ। मैं लगभग भूल ही गया था। चूंकि जिस वस्तु की वस्तु नेपर्सनेई डेटा को फोल्ड करना होगा, वह डॉक्टरों के प्रकार से बात करता है। इस वर्ग को परिभाषित किया गया है और इसमें सभी आवश्यक सेटर्स-गेटर्स हैं।

    अगला स्पष्ट तत्व समाप्त होता है और इसके बाद अगला होता है। EndElement() को समाप्त करने के लिए जिम्मेदार। यह हमें संकेत देता है कि आइटम समाप्त हो गया है और आप इस समय कुछ भी कर सकते हैं। आगे बढ़ेंगे। स्वच्छ तत्व

    @Override 
    public void endElement (String namespaceURI, String localName, String qName) throws SAXException { 
       thisElement = ""; 
    } 
    

    पूरे दस्तावेज़ को आ रहा है, हम फ़ाइल के अंत में आते हैं। कार्य एंड डॉक्यूमेंट()। इसमें, हम स्मृति को मुक्त कर सकते हैं, कुछ डायग्नोस्टेस्यूयू प्रिंटिंग आदि कर सकते हैं। हमारे मामले में, बस पार्सिंग समाप्त होने के बारे में लिखें।

    @Override 
    public void endDocument() { 
       System.out.println ("Stop parse XML ..."); 
    } 
    

    तो हमें हमारे प्रारूप को एक्सएमएल पार्स करने के लिए एक कक्षा मिली है। यहां पूरा पाठ है:

    import org.xml.sax.helpers.DefaultHandler; 
    import org.xml.sax. *; 
      
    public class SAXPars extends DefaultHandler { 
      
    Doctors doc = new Doctors(); 
    String thisElement = ""; 
      
    public Doctors getResult() { 
       return doc; 
    } 
      
    @Override 
    public void startDocument() throws SAXException { 
       System.out.println ("Start parse XML ..."); 
    } 
      
    @Override 
    public void startElement (String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 
       thisElement = qName; 
    } 
      
    @Override 
    public void endElement (String namespaceURI, String localName, String qName) throws SAXException { 
       thisElement = ""; 
    } 
      
    @Override 
    public void characters (char [] ch, int start, int length) throws SAXException { 
       if (thisElement.equals ("id")) { 
          doc.setId (new Integer (new String (ch, start, length))); 
       } 
       if (thisElement.equals ("fam")) { 
          doc.setFam (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("name")) { 
          doc.setName (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("otc")) { 
          doc.setOtc (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("dateb")) { 
          doc.setDateb (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("datep")) { 
          doc.setDatep (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("datev")) { 
          doc.setDatev (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("datebegin")) { 
          doc.setDatebegin (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("dateend")) { 
          doc.setDateend (new String (ch, start, length)); 
       } 
       if (thisElement.equals ("vdolid")) { 
          doc.setVdolid (new Integer (new String (ch, start, length))); 
       } 
       if (thisElement.equals ("specid")) { 
          doc.setSpecid (new Integer (new String (ch, start, length))); 
       } 
       if (thisElement.equals ("klavid")) { 
          doc.setKlavid (new Integer (new String (ch, start, length))); 
       } 
       if (thisElement.equals ("stav")) { 
          doc.setStav (new Float (new String (ch, start, length))); 
       } 
       if (thisElement.equals ("progid")) { 
          doc.setProgid (new Integer (new String (ch, start, length))); 
       } 
    } 
      
    @Override 
    public void endDocument() { 
       System.out.println ("Stop parse XML ..."); 
    } 
    } 
    

    मुझे उम्मीद है कि इस विषय ने SAX पार्सर के सार को आसानी से प्रस्तुत करने में मदद की।

    कड़ाई से पहले लेख का न्याय न करें :) मुझे उम्मीद है कि कम से कम कोई उपयोगी होगा।

    युपीडी:

    SAXParserFactory factory = SAXParserFactory.newInstance(); 
    SAXParser parser = factory.newSAXParser(); 
    SAXPars saxp = new SAXPars(); 
      
    parser.parse (new File ("..."), saxp); 
    

    संबंधित मुद्दे