XML पार्स करने की तकनीक


11

मैंने हमेशा XML को प्रक्रिया के लिए कुछ बोझिल पाया है। मैं XML पार्सर को लागू करने के बारे में बात नहीं कर रहा हूं: मैं एक मौजूदा स्ट्रीम-आधारित पार्सर का उपयोग करने के बारे में बात कर रहा हूं , जैसे कि एसएएक्स पार्सर, जो नोड द्वारा XML नोड को संसाधित करता है।

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

उदाहरण के लिए, किसी विशिष्ट XML दस्तावेज़ से एक स्निपेट दिया गया:

<book>
  <title>Blah blah</title>
  <author>Blah blah</author>
  <price>15 USD</price>
</book>

... मैं कैसे निर्धारित करूँगा जब मैंने एक पुस्तक शीर्षक वाले पाठ नोड का सामना किया है? मान लें कि हमारे पास एक सरल XML पार्सर है जो एक पुनरावृत्त की तरह कार्य करता है, हमें XML दस्तावेज़ में अगले नोड देता है जिसे हम कॉल करते हैं XMLParser.getNextNode()। मैं अनिवार्य रूप से अपने आप को निम्नलिखित की तरह कोड लिख रहा हूँ:

boolean insideBookNode = false;
boolean insideTitleNode = false;

while (!XMLParser.finished())
{
    ....
    XMLNode n = XMLParser.getNextNode();

    if (n.type() == XMLTextNode)
    {
        if (insideBookNode && insideTitleNode)
        {
            // We have a book title, so do something with it
        }
    }
    else
    {
        if (n.type() == XMLStartTag)
        {
            if (n.name().equals("book")) insideBookNode = true
            else if (n.name().equals("title")) insideTitleNode = true;
        }
        else if (n.type() == XMLEndTag)
        {
            if (n.name().equals("book")) insideBookNode = false;
            else if (n.name().equals("title")) insideTitleNode = false;
        }
    }
}

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

फिर, समस्या यह प्रतीत होती है कि जिस डेटा में हम रुचि रखते हैं वह सीधे एक व्यक्तिगत नोड से जुड़ा नहीं है। यकीन है, यह हो सकता है, अगर हम XML की तरह लिखा है:

<book title="Blah blah" author="blah blah" price="15 USD" />

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

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


2
यदि आपकी .net भाषा का उपयोग करते हुए, आपको linq से xml aka XLinq देखना चाहिए।
मुदादिब 14

धन्यवाद, मैंने सोचा कि मैं इस समस्या का एकमात्र था। सच कहूँ तो, मैं अक्सर पूरे XML प्रारूप को एक मदद से अधिक बाधा के रूप में पाता हूं। हां, यह एक छोटे पाठ फ़ाइल में संरचित डेटा को संग्रहीत करने की अनुमति देता है। लेकिन अगर आपको 20+ कक्षाओं को अनपैक करने की ज़रूरत है और इस चीज़ का कोई मतलब नहीं है - इस बात की कोई गारंटी नहीं है कि आप कुछ अधिक या कम महत्वपूर्ण नहीं हैं। यह मोंटी अजगर के पवित्र कंघी बनानेवाले की रेती की तरह है।
एलिस वैन लूइज

जवाबों:


9

मेरे लिए, सवाल दूसरे तरीके का दौर है। किस बिंदु पर एक XML दस्तावेज़ इतना बोझिल हो जाता है, कि आपको DOM के बजाय SAX का उपयोग करना शुरू करना होगा?

मैं डेटा के एक बहुत बड़े, अनिश्चित आकार के धारा के लिए केवल SAX का उपयोग करूंगा; या अगर एक्सएमएल के व्यवहार का उद्देश्य वास्तव में घटना-चालित है, और इसलिए SAX- जैसा है।

जो उदाहरण आप देते हैं वह मुझे बहुत डोम-जैसा लगता है।

  1. XML लोड करें
  2. शीर्षक नोड्स निकालें और "उनके साथ कुछ करें"।

संपादित करें: मैं SAX का उपयोग उन धाराओं के लिए भी करूंगा जो विकृत हो सकती हैं, लेकिन जहां मैं डेटा प्राप्त करने का सबसे अच्छा अनुमान लगाना चाहता हूं।


2
मुझे लगता है कि यह एक अच्छा बिंदु है। यदि आप उन दस्तावेज़ों को पार्स कर रहे हैं जो डोम के लिए बहुत बड़े हैं तो आपको यह विचार करने की आवश्यकता है कि क्या आप दस्तावेज़ों को पार्स कर रहे हैं जो XML के
डीन हार्डिंग

1
+1: विकल्प को देखते हुए, मैं हमेशा DOM के साथ जाता हूँ। दुर्भाग्य से, ऐसा लगता है कि हमारी डिजाइन आवश्यकताओं में हमेशा "किसी भी आकार के दस्तावेज़ को संभालने की क्षमता" और "प्रदर्शन करने वाला होना चाहिए" शामिल हैं, जो डोम-आधारित समाधानों को बहुत अधिक नियमबद्ध करते हैं।
TMN

3
@ टीएमएन, एक आदर्श दुनिया में जो पहले स्थान पर एक्सएमएल की आवश्यकता को पूरा करेगा।
लॉजिक

1
@TMN, जो उन प्रेत आवश्यकताओं में से एक लगता है: "बेशक हमारे सभी दस्तावेज लगभग 100KB के हैं, और हमने जो सबसे बड़ा देखा है वह 1MB है, लेकिन आप कभी नहीं जानते कि भविष्य क्या है, इसलिए हमें अपने विकल्प खुले रखने चाहिए और असीम रूप से बड़े दस्तावेज़ों के लिए निर्माण करें "
पॉल बुचर

@Paul कसाई, आप कभी नहीं जानते। मेरा मतलब है, विकिपीडिया का एक डंप 30GB XML की तरह है।
चैनल 72

7

मैं एक्सएमएल के साथ बहुत ज्यादा काम नहीं करता हूं, मेरी राय में, शायद एक्सएमएल को लाइब्रेरी के साथ पार्स करने के सबसे अच्छे तरीकों में से एक एक्सपीथ का उपयोग करना है।

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

books = parent.xpath ("/ book") // यह आपको सभी पुस्तक नोड्स देगा
किताबों में प्रत्येक पुस्तक के लिए
    शीर्षक = book.xpath ("/ शीर्षक / पाठ ()")
    लेखक = book.xpath ("/ लेखक / पाठ ()")
    मूल्य = book.xpath ("/ मूल्य / पाठ ()")

    // डेटा के साथ काम करो

XPath इससे कहीं अधिक शक्तिशाली है, आप शर्तों (मूल्यों और विशेषताओं दोनों) का उपयोग करके खोज कर सकते हैं, एक सूची में एक विशिष्ट नोड का चयन कर सकते हैं, पेड़ के माध्यम से स्तरों को स्थानांतरित कर सकते हैं। मेरा सुझाव है कि आप इसका उपयोग करने के तरीके के बारे में जानकारी के लिए देखें, यह बहुत से पार्सिंग पुस्तकालयों में लागू किया गया है (मैं इसका उपयोग करता हूं। पायथन के लिए .Net फ्रेमवर्क संस्करण और lxml)


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

5

धारा-आधारित XML पार्सिंग हमेशा एक विशाल राज्य मशीन में बदल जाता है?

आमतौर पर यह करता है, हाँ।

मेरे लिए एक पूरी तरह से विकसित डोमेन पार्सर का उपयोग करने के लिए इंगित करने के लिए जब मुझे फ़ाइल पदानुक्रम-इन-मेमोरी के कुछ हिस्सों की नकल करने की आवश्यकता होगी, उदाहरण के लिए दस्तावेज़ के भीतर क्रॉस-रेफरेंस को हल करने में सक्षम होना।


+1: DOM से शुरू करें। SAX से बचें।
S.Lott

या vtd-xml के साथ
vtd-xml-author

4

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

मैं हमेशा DOM का उपयोग करता हूं जब तक कि आकार या प्रदर्शन के मुद्दे अन्यथा निर्धारित न हों।


1

पूरी तरह से भाषा अज्ञेय नहीं है, लेकिन मैं आमतौर पर XML को ऑब्जेक्ट्स के बारे में सोचने के बजाय वस्तुओं में शामिल करता हूं। प्रति सेकंड पार्सिंग रणनीतियों के बारे में चिंता करने का केवल समय है यदि आपके पास गति मुद्दा है।


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

कई भाषाओं / ढेरों में बिल्ट डेसरीएलाइजेशन लाइब्रेरी हैं।
वायट बार्नेट

हाँ, तो क्या? मेरे बिंदु अभी भी पकड़ में हैं - जंगली में सभी XML फाइलें इस तरह के प्रारूप में नहीं आती हैं, और यदि आपके पास ऐसा है, तो आप इस प्रश्न को नहीं पूछते हैं क्योंकि आप बस उस deserialization पुस्तकालय का उपयोग करते हैं और अपने दम पर कुछ भी पार्स नहीं करते हैं। धाराओं से या अन्यथा।

0

यदि आप XPath का उपयोग कर सकते हैं तो यह बहुत कम बोझिल हो जाता है। और .Net भूमि LINQ to XML सार कम ग्लैमरस सामान का एक बहुत। ( संपादित करें - इन्हें पाठ्यक्रम के लिए एक डोम दृष्टिकोण की आवश्यकता होती है)

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


यदि आप XPath का उपयोग कर रहे हैं, तो आप DOM का उपयोग कर रहे हैं (जब तक कि आप इसे होम-ग्रसित XPath मूल्यांकनकर्ता के साथ उपयोग नहीं कर रहे हैं)।
TM25

हाँ, इसलिए डोम की आवश्यकता वाले अमूर्त के बारे में मेरी टिप्पणी ... लेकिन मैं स्पष्ट करूँगा, धन्यवाद!
स्टीव

0

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.