2011-12-22 40 views
13

एक एक्सएमएल स्ट्रीम है जिसे मुझे पार्स करने की आवश्यकता है। चूंकि मुझे केवल एक बार ऐसा करने की ज़रूरत है और मेरी जावा वस्तुओं का निर्माण करना है, एसएएक्स प्राकृतिक पसंद की तरह दिखता है। मैं डिफॉल्ट हैंडलर का विस्तार कर रहा हूं और स्टार्ट एलिमेंट, एंडलेमेंट और कैरेक्टर विधियों को कार्यान्वित कर रहा हूं, जिसमें मेरी कक्षा में सदस्य हैं जहां मैं वर्तमान पठन मूल्य (वर्ण विधि में लिया गया) सहेजता हूं।जावा सैक्स पार्सिंग

मुझे जो चाहिए वह करने में मुझे कोई समस्या नहीं है, लेकिन मेरा कोड काफी जटिल हो गया है और मुझे यकीन है कि इसके लिए कोई कारण नहीं है और मैं चीजों को अलग-अलग कर सकता हूं।

<players> 
    <player> 
    <id></id> 
    <name></name> 
    <teams total="2"> 
     <team> 
     <id></id> 
     <name></name> 
     <start-date> 
      <year>2009</year> 
      <month>9</month> 
     </start-date> 
     <is-current>true</is-current> 
     </team> 
     <team> 
     <id></id> 
     <name></name> 
     <start-date> 
      <year>2007</year> 
      <month>11</month> 
     </start-date> 
     <end-date> 
      <year>2009</year> 
      <month>7</month> 
     </end-date> 
     </team> 
    </teams> 
    </player> 
</players> 

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

यहाँ की तरह कैसे मेरे कोड दिखाई देता है:

public class MyParser extends DefaultHandler { 

    private String currentValue; 
    private boolean inTeamsSection = false; 
    private Player player; 
    private Team team; 
    private List<Team> teams; 

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

    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { 
     if(name.equals("player")){ 
      player = new Player(); 
     } 
     if (name.equals("teams")) { 
      inTeamsSection = true; 
      teams = new ArrayList<Team>(); 
     } 
     if (name.equals("team")){ 
      team = new Team(); 
     } 
    } 

    public void endElement(String uri, String localName, String name) throws SAXException { 
     if (name.equals("id")) { 
      if(inTeamsSection){ 
       team.setId(currentValue); 
      } 
      else{ 
       player.setId(currentValue); 
      } 
     } 
     if (name.equals("name")){ 
      if(inTeamsSection){ 
       team.setName(currentValue); 
      } 
      else{ 
       player.setName(currentValue); 
      } 
     } 
     if (name.equals("team")){ 
      teams.add(team); 
     } 
     if (name.equals("teams")){ 
      player.setTeams(teams); 
      inTeamsSection = false; 
     } 
    } 
} 

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

मुझे अलग-अलग क्या करना चाहिए? उदाहरण के लिए, मुझे कैसे पता चलेगा कि नाम टैग क्या है?

धन्यवाद!

+1

मैं कहूंगा कि SAX का उपयोग 7 साल पहले प्राकृतिक विकल्प था। वर्तमान में प्राकृतिक विकल्प JAXB (या Xtream, या XmlBeans या JibX) – Tarlog

+0

का उपयोग करना है कभी-कभी आपको मैन्युअल रूप से पार्सिंग करना पड़ता है। जब आप एक्सएमएल के मेगाबाइट्स से निपटते हैं तो इसे जावा ऑब्जेक्ट्स में परिवर्तित करना बहुत अच्छा विचार नहीं है। –

+0

@ ʘleg - यदि आप एक एक्सएक्स XMLStreamReader से unmarshal ऑब्जेक्ट्स में JAXB का उपयोग करते हैं तो आप मेमोरी बाधाओं को प्रबंधित करने के लिए बड़े दस्तावेज़ के अनमर्शल उपखंडों को अनधिकृत कर सकते हैं। –

उत्तर

20

एक SAX पार्सर लिखते समय एक साफ चाल है: इसे पार्सिंग करते समय XMLReader के ContentHandler को बदलने की अनुमति है। यह विभिन्न वर्गों के लिए पार्सिंग तर्क को अलग-अलग तत्वों में अलग करने की अनुमति देता है, जो को अधिक मॉड्यूलर और पुन: प्रयोज्य पार्सिंग करता है। जब एक हैंडलर अपना अंतिम तत्व देखता है तो यह अपने माता-पिता को वापस स्विच करता है। आपके द्वारा लागू किए जाने वाले कितने हैंडलर आपको पर छोड़ देंगे।कोड इस तरह दिखेगा:

public class RootHandler extends DefaultHandler { 
    private XMLReader reader; 
    private List<Team> teams; 

    public RootHandler(XMLReader reader) { 
     this.reader = reader; 
     this.teams = new LinkedList<Team>(); 
    } 

    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { 
     if (name.equals("team")) { 
      // Switch handler to parse the team element 
      reader.setContentHandler(new TeamHandler(reader, this)); 
     } 
    } 
} 

public class TeamHandler extends DefaultHandler { 
    private XMLReader reader; 
    private RootHandler parent; 
    private Team team; 
    private StringBuilder content; 

    public TeamHandler(XMLReader reader, RootHandler parent) { 
     this.reader = reader; 
     this.parent = parent; 
     this.content = new StringBuilder(); 
     this.team = new Team(); 
    } 

    // characters can be called multiple times per element so aggregate the content in a StringBuilder 
    public void characters(char[] ch, int start, int length) throws SAXException { 
     content.append(ch, start, length); 
    } 

    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { 
     content.setLength(0); 
    } 

    public void endElement(String uri, String localName, String name) throws SAXException { 
     if (name.equals("name")) { 
      team.setName(content.toString()); 
     } else if (name.equals("team")) { 
      parent.addTeam(team); 
      // Switch handler back to our parent 
      reader.setContentHandler(parent); 
     } 
    } 
} 
+0

यदि सबटेम्स, प्लेयर्स इत्यादि हैं तो उनमें से सभी को एक दूसरे के संदर्भ में शामिल नहीं होना चाहिए जिसके परिणामस्वरूप _VERY_ तंग युग्मन होगा? –

+1

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

+0

धन्यवाद, अब मैं इस ट्रेक का उपयोग कर रहा हूं और यह मेरे लिए बहुत अच्छा काम करता है। बस इस उपयोग के मामले के लिए मुझे क्या चाहिए। – Haji

1

मैं दृढ़ता से खुद को पार्सिंग रोकने की सलाह देता हूं, और अच्छी XML डेटा-बाइंडिंग लाइब्रेरी को पकड़ता हूं। एक्सस्ट्रीम (http://x-stream.github.io/) व्यक्तिगत पसंदीदा हो सकता है, लेकिन कई अलग-अलग पुस्तकालय हैं। यह किसी भी कॉन्फ़िगरेशन के बिना, आपके POJO को स्पॉट पर पार्स करने में भी सक्षम हो सकता है (यदि आप XML संरचना से मेल खाने के लिए प्रॉपर्टी नाम और बहुवचन का उपयोग करते हैं)।

0

मैं बहुत समान है, लेकिन बजाय boolean झंडे होने मुझे बताने की क्या राज्य मैं में हूँ, मैं player या team जा रहा है गैर null के लिए परीक्षण के लिए कुछ करना। चीजों को थोड़ा साफ करता है। जब आप इसे प्रासंगिक सूची में जोड़ते हैं, तो आपको प्रत्येक तत्व के अंत का पता लगाने पर उन्हें null पर सेट करने की आवश्यकता होती है।

0

यदि आपको सुंदर कोड की आवश्यकता है तो कृपया StAX का उपयोग करें, यह comparison of all XML parsing APIs बताता है कि स्टैक्स एक बेहतर विकल्प है।

StAX performance अधिकांश परीक्षणों में भी किसी भी अन्य एपीआई कार्यान्वयन की तुलना में बेहतर है।

इसलिए मुझे व्यक्तिगत रूप से SAX के साथ जाने का कोई कारण नहीं दिखता है जब तक कि आप कुछ विरासत से संबंधित प्रोग्रामिंग नहीं कर रहे हैं।

2

यह अपनी आवश्यकताओं के बारे में और अधिक जानने के बिना सलाह देने के लिए मुश्किल है, लेकिन तथ्य यह है कि आप हैरान होंगे कि "मेरे कोड काफी जटिल हो गया" कर रहे हैं पता चलता है कि आप अच्छी तरह से सूचित नहीं किया गया है कि जब आप चुना है SAX। SAX एक निम्न स्तरीय प्रोग्रामिंग इंटरफ़ेस है जो बहुत अधिक प्रदर्शन करने में सक्षम है, लेकिन ऐसा इसलिए है क्योंकि पार्सर आपके लिए बहुत कम काम कर रहा है, और इसलिए आपको अपने आप को और अधिक काम करने की ज़रूरत है।

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