मुझे StAX पर SAX का चयन कब करना चाहिए?


81

SAX और StAX जैसे xml-parsers को स्ट्रीम करना और DOM-parsers जैसे ट्री-स्ट्रक्चर बनाने वाले पार्सर्स की तुलना में अधिक मेमोरी कुशल होते हैं। SAX एक पुश पार्सर है, जिसका अर्थ है कि यह पर्यवेक्षक पैटर्न (जिसे श्रोता पैटर्न भी कहा जाता है) का एक उदाहरण है। एसएएक्स पहले था, लेकिन फिर स्टैक्स आया - एक पुल पार्सर, जिसका अर्थ है कि यह मूल रूप से एक पुनरावृत्त की तरह काम करता है।

आप कारणों को पा सकते हैं कि हर जगह एसएएक्स पर स्टैक्स को प्राथमिकता क्यों दी जाए, लेकिन यह आमतौर पर उबलता है: "इसका उपयोग करना आसान है"।

JAXP StAX पर जावा ट्यूटोरियल में DOM और SAX के बीच के रूप में अस्पष्ट रूप से प्रस्तुत किया गया है: "यह SAX की तुलना में आसान है और DOM से अधिक कुशल है"। हालाँकि, मुझे कभी भी ऐसा कोई सुराग नहीं मिला कि StAX धीमा हो या SAX की तुलना में कम मेमोरी वाला हो।

यह सब मुझे आश्चर्यचकित करता है: क्या स्टैक्स के बजाय एसएएक्स चुनने का कोई कारण है?

जवाबों:


22

थोड़ा सामान्य करने के लिए, मुझे लगता है कि StAXजितना कुशल हो सकता है SAX। जब तक कि विरासत कोड के साथ काम नहीं किया जाता है, तब तक StAXमुझे बेहतर डिज़ाइन के साथ कोई भी ऐसी स्थिति नहीं मिल सकती है जहाँ SAXपार्सिंग को प्राथमिकता दी जाए।

EDIT : इस ब्लॉग के अनुसार Java SAX बनाम StAX StAX कोई स्कीमा सत्यापन प्रदान नहीं करता है।


2
यह बहुत मुश्किल नहीं है कि स्टेक्स के ऊपर सत्यापन को जोड़ा जाए। दूसरे दिन खुद को लागू किया।
jtahlborn

मान्यता पर अधिक विवरण: stackoverflow.com/questions/5793087/stax-xml-validation
बेन

81

अवलोकन
एक्सएमएल दस्तावेज़ श्रेणीबद्ध दस्तावेज हैं, जहां एक ही तत्व के नाम और नामस्थान कई स्थानों पर हो सकते हैं, अलग-अलग अर्थ होते हैं, और असीम गहराई (पुनरावर्ती) में होते हैं। सामान्य के रूप में, बड़ी समस्याओं का समाधान, उन्हें छोटी समस्याओं में विभाजित करना है। XML पार्सिंग के संदर्भ में, इसका मतलब है कि XML के विशिष्ट तरीकों में XML के विशिष्ट भागों को पार्स करना। उदाहरण के लिए, तर्क का एक टुकड़ा एक पते को पार्स करेगा:

<Address>
    <Street>Odins vei</Street>    
    <Building>4</Building>
    <Door>b</Door>
</Address>

यानी आपके पास एक तरीका होगा

AddressType parseAddress(...); // A

या

void parseAddress(...); // B

अपने तर्क में कहीं, एक्सएमएल इनपुट तर्कों को लेने और एक वस्तु वापस करने (बी के परिणाम को बाद में एक क्षेत्र से प्राप्त किया जा सकता है)।

SAX
SAX 'XML' आयोजनों को आगे बढ़ाता है , जिससे यह निर्धारित होता है कि आपके कार्यक्रम / डेटा में XML इवेंट कहाँ हैं।

// method in stock SAX handler
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
    // .. your logic here for start element
}

'बिल्डिंग' स्टार्ट तत्व के मामले में, आपको यह निर्धारित करना होगा कि आप वास्तव में एक एड्रेस पार्स कर रहे हैं और फिर एक्सएमएल ईवेंट को उस विधि पर रूट करें, जिसका काम एड्रेस की व्याख्या करना है।

StAX
StAX 'XML घटनाओं को खींचता है , जिससे यह निर्धारित होता है कि XML कार्यक्रम प्राप्त करने के लिए आपके प्रोग्राम / डेटा में कहाँ निर्धारित किया गया है।

// method in standard StAX reader
int event = reader.next();
if(event == XMLStreamConstants.START_ELEMENT) {
    // .. your logic here for start element
}

बेशक, आप हमेशा उस विधि में एक 'बिल्डिंग' इवेंट प्राप्त करना चाहेंगे जिसका काम एड्रेस की व्याख्या करना है।

चर्चा
SAX और StAX के बीच का अंतर धक्का और खींच है। दोनों मामलों में, पार्स राज्य को किसी भी तरह से संभाला जाना चाहिए।

यह B को SAX के लिए विशिष्ट विधि के रूप में अनुवाद करता है, और StAX के लिए विधि A। इसके अलावा, SAX को B अलग-अलग XML इवेंट्स देने चाहिए, जबकि Stax एक मल्टीपल इवेंट्स (XMLStreamReader इंस्टेंस पास करके) दे सकता है।

इस प्रकार बी पहले पार्सिंग की पिछली स्थिति की जांच करते हैं और फिर प्रत्येक व्यक्तिगत एक्सएमएल घटना को संभालते हैं और फिर राज्य (एक क्षेत्र में) को स्टोर करते हैं। विधि A केवल XMLStreamReader को एक बार में संतुष्ट होने तक कई बार XML घटनाओं को संभाल सकती है।

निष्कर्ष
StAX आपको XML संरचना के अनुसार अपने पार्सिंग (डेटा-बाइंडिंग) कोड की संरचना करने देता है ; इसलिए SAX के संबंध में, 'स्टेट' का अर्थ StAX के लिए प्रोग्राम फ्लो से है, जबकि SAX में, आपको हमेशा किसी न किसी प्रकार के स्टेट वेरिएबल + रूट को उस स्थिति के अनुसार संरक्षित करने की आवश्यकता होती है, अधिकांश इवेंट कॉल के लिए।

मैं सभी लेकिन सरलतम दस्तावेजों के लिए StAX की सलाह देता हूं। बाद में SAX को एक अनुकूलन के रूप में स्थानांतरित करें (लेकिन आप तब तक बाइनरी जाना चाहेंगे)।

Stax का उपयोग करते समय इस पैटर्न का पालन करें:

public MyDataBindingObject parse(..) { // provide input stream, reader, etc

        // set up parser
        // read the root tag to get to level 1
        XMLStreamReader reader = ....;

        do {
            int event = reader.next();
            if(event == XMLStreamConstants.START_ELEMENT) {
              // check if correct root tag
              break;
            }

            // add check for document end if you want to

        } while(reader.hasNext());

        MyDataBindingObject object = new MyDataBindingObject();
        // read root attributes if any

        int level = 1; // we are at level 1, since we have read the document header

        do {
            int event = reader.next();
            if(event == XMLStreamConstants.START_ELEMENT) {
                level++;
                // do stateful stuff here

                // for child logic:
                if(reader.getLocalName().equals("Whatever1")) {
                    WhateverObject child = parseSubTreeForWhatever(reader);
                    level --; // read from level 1 to 0 in submethod.

                    // do something with the result of subtree
                    object.setWhatever(child);
                }

                // alternatively, faster
                if(level == 2) {
                    parseSubTreeForWhateverAtRelativeLevel2(reader);
                    level --; // read from level 1 to 0 in submethod.

                    // do something with the result of subtree
                    object.setWhatever(child);
                }


            } else if(event == XMLStreamConstants.END_ELEMENT) {
                level--;
                // do stateful stuff here, too
            }

        } while(level > 0);

        return object;
}

तो एक ही दृष्टिकोण के बारे में सबमिथोड उपयोग करता है, यानी गिनती स्तर:

private MySubTreeObject parseSubTree(XMLStreamReader reader) throws XMLStreamException {

    MySubTreeObject object = new MySubTreeObject();
    // read element attributes if any

    int level = 1;
    do {
        int event = reader.next();
        if(event == XMLStreamConstants.START_ELEMENT) {
            level++;
            // do stateful stuff here

            // for child logic:
            if(reader.getLocalName().equals("Whatever2")) {
                MyWhateverObject child = parseMySubelementTree(reader);
                level --; // read from level 1 to 0 in submethod.

                // use subtree object somehow
                object.setWhatever(child);
            }

            // alternatively, faster, but less strict
            if(level == 2) {
              MyWhateverObject child = parseMySubelementTree(reader);
                level --; // read from level 1 to 0 in submethod.

                // use subtree object somehow
                object.setWhatever(child);
            }


        } else if(event == XMLStreamConstants.END_ELEMENT) {
            level--;
            // do stateful stuff here, too
        }

    } while(level > 0);

    return object;
}

और फिर अंततः आप एक स्तर तक पहुंच जाते हैं जिसमें आप आधार प्रकार पढ़ेंगे।

private MySetterGetterObject parseSubTree(XMLStreamReader reader) throws XMLStreamException {

    MySetterGetterObject myObject = new MySetterGetterObject();
    // read element attributes if any

    int level = 1;
    do {
        int event = reader.next();
        if(event == XMLStreamConstants.START_ELEMENT) {
            level++;

            // assume <FirstName>Thomas</FirstName>:
            if(reader.getLocalName().equals("FirstName")) {
               // read tag contents
               String text = reader.getElementText()
               if(text.length() > 0) {
                    myObject.setName(text)
               }
               level--;

            } else if(reader.getLocalName().equals("LastName")) {
               // etc ..
            } 


        } else if(event == XMLStreamConstants.END_ELEMENT) {
            level--;
            // do stateful stuff here, too
        }

    } while(level > 0);

    // verify that all required fields in myObject are present

    return myObject;
}

यह काफी सीधा है और गलतफहमी के लिए कोई जगह नहीं है। बस सही ढंग से वृद्धि स्तर को याद रखें:

ए के बाद आप पात्रों की उम्मीद करते हैं, लेकिन कुछ टैग में एक END_ELEMENT मिला है जिसमें चार्ट (उपरोक्त पैटर्न में) होना चाहिए:

<Name>Thomas</Name>

इसके बजाय था

<Name></Name>

एक लापता सबट्री के लिए भी यही सच है, आपको यह विचार मिलता है।

बी, सबपर्सिंग विधियों को कॉल करने के बाद, जिन्हें स्टार्ट तत्वों पर कहा जाता है, और संबंधित अंतिम तत्व के बाद रिटर्न करते हैं, अर्थात विधि कॉल (उपरोक्त पैटर्न) से पहले पार्सर एक स्तर से कम है।

ध्यान दें कि यह दृष्टिकोण पूरी तरह से 'आग्नेय' व्हाट्सएप को और अधिक मजबूत कार्यान्वयन के लिए कैसे अनदेखा करता है।

पारसर्स
साथ जाओ Woodstox सबसे सुविधाओं या के लिए Aaalto-एक्सएमएल गति के लिए।


आपके प्रारंभिक वक्तव्य में यह लिखा है "... जबकि SAX में ..."। क्या यह एक टाइपो है? "StAX" के बजाय ("SAX") किसी भी मामले में उत्तर के लिए धन्यवाद। यदि मैं आपको सही तरीके से समझता हूं, तो आप कह रहे हैं कि एसएएक्स दृष्टिकोण में निहित राज्य आपके एक्सएमएल-ट्री स्थान को स्टैक्स दृष्टिकोण में ट्रैक करने की आवश्यकता की तुलना में एक लाभ है।
रिंकी

(अब और भी विस्तृत) उत्तर के लिए धन्यवाद। मुझे डर है कि मैं अभी भी नहीं देख रहा हूं कि स्टैक्स के बजाय एसएएक्स का उपयोग करने का एक अच्छा कारण क्या होगा। आपका जवाब दोनों प्रोसेसर कैसे काम करते हैं इसकी एक अच्छी व्याख्या है।
रिंकी

सरल दस्तावेजों के लिए, वे समान हैं। उदाहरण के लिए इस स्कीमा को देखें: mpeg.chiariglione.org/technologies/mpeg-21/mp21-did/index.htm और StAX अधिक व्यावहारिक होगा।
थॉमस

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

16

@ रिंक: मुझे लगता है कि केवल उसी समय जब मैं XML सामग्री को संभालने / संसाधित करने की आवश्यकता नहीं होने की स्थिति में SAX पर SAX को प्राथमिकता देने के बारे में सोचता हूं; उदाहरण के लिए केवल एक चीज जो आप करना चाहते हैं, वह आने वाले XML की अच्छी तरह से निर्मिति के लिए जाँच है और यदि यह है तो त्रुटियों को संभालना चाहते हैं ... इस मामले में आप बस SAX पार्सर पर पार्स () विधि को कॉल कर सकते हैं और किसी भी को संभालने के लिए त्रुटि हैंडलर निर्दिष्ट कर सकते हैं पार्सिंग समस्या .... इसलिए मूल रूप से STAX निश्चित रूप से उन परिदृश्यों में बेहतर विकल्प है जहाँ आप सामग्री को हैंडल करना चाहते हैं SAX सामग्री हैंडलर को कोड करना बहुत मुश्किल है ...

इस मामले का एक व्यावहारिक उदाहरण हो सकता है यदि आपके पास अपने एंटरप्राइज सिस्टम में SOAP नोड्स की श्रृंखला है और एक एंट्री लेवल SOAP नोड केवल उन SOAP XML को अगले चरण में उत्तीर्ण करने देता है जो अच्छी तरह से निर्मित हैं, तो मुझे कोई कारण नहीं दिखता है कि मैं क्यों STAX का उपयोग करेगा। मैं सिर्फ SAX का उपयोग करूंगा।


मैंने इस उत्तर को अब तक के सर्वश्रेष्ठ के रूप में चुना। हालांकि यह एक अच्छा जवाब है, मुझे नहीं लगता कि यह 100% आधिकारिक और स्पष्ट है। नए जवाब का स्वागत है।
रिंकी

1

यह सब एक संतुलन है।

आप एक अवरुद्ध पार्स और कुछ थ्रेड ट्रिक का उपयोग करके SAX पार्सर को एक पुल पार्सर में बदल सकते हैं, इसलिए, मेरे लिए, पहले की तुलना में बहुत कम अंतर है।

मेरा मानना ​​है कि वर्तमान में स्टैक्स को थर्ड-पार्टी जार के माध्यम से पैक करने की आवश्यकता है, जबकि एसएएक्स जेवैक्स में मुफ्त आता है।

मैंने हाल ही में SAX को चुना और इसके चारों ओर एक पुल पार्सर बनाया, इसलिए मुझे तीसरे पक्ष के जार पर भरोसा करने की आवश्यकता नहीं थी।

जावा के भविष्य के संस्करणों में लगभग निश्चित रूप से एक Stax कार्यान्वयन शामिल होगा ताकि समस्या दूर हो जाए।


1
Java SE 6 में StAX शामिल है। लेकिन उदाहरण के लिए Android कार्यान्वयन में यह शामिल नहीं है।
ब्रजने बोस्‍ट्रोम

0

Stax आपको द्विदिश XML पार्सर बनाने में सक्षम बनाता है जो तेज़ हैं। यह प्रदर्शन और प्रयोज्य के संदर्भ में, डोम और एसएएक्स जैसे अन्य तरीकों के लिए एक बेहतर विकल्प साबित होता है

आप जावा स्टैक्स ट्यूटोरियल में StAX के बारे में अधिक पढ़ सकते हैं


-1

उन उत्तरों द्वारा प्रदान की गई अधिकांश जानकारी कुछ हद तक पुरानी हैं ... 2013 के शोध पत्र में सभी XML पार्सिंग लिब का व्यापक अध्ययन किया गया है ... इसे पढ़ें और आप आसानी से स्पष्ट विजेता देखेंगे (संकेत: केवल एक है सच्चा विजेता) ...

http://recipp.ipp.pt/bitstream/10400.22/1847/1/ART_BrunoOliveira_2013.pdf


1
मैं कागज पढ़ता हूं, विजेता कर्सर एपीआई का उपयोग करके StAX होता है XMLStreamReader
रोलैंड

बहुत ही मजेदार :), आपका मतलब है कछुआ दौड़ का विजेता :)
vtd-xml-author

मैं सिर्फ कागज को फिर से पढ़ता हूं, और हां StaX vtd, तेज और कम मेमोरी खपत से बेहतर है। तो तुम्हारा क्या कहना है?
रोलैंड

विजेता किस तरह से स्थिर है? आप किस पेपर का जिक्र कर रहे हैं? दस्तावेज़ में संशोधन, या चयन या भेदभाव? जाहिर है कागज के लेखक ने एक अलग निष्कर्ष निकाला। लेकिन वे पूरी तरह से गलत हो सकते हैं ...
vtd-xml- लेखक

1
उदाहरण पृष्ठ 80: परिणामों के अनुसार (आंकड़ा 11 और आंकड़ा 12) हम देख सकते हैं कि StAX एपीआई है जिसमें बेहतर प्रदर्शन है, वीटीडी के बाद। हालांकि, वीटीडी मेमोरी की काफी मात्रा में खपत करता है। मेमोरी खपत पर्यावरण के लिए एक अड़चन हो सकती है जो सीमित क्षमता प्रदान करती है।
रोलैंड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.