मैं पायथन में XML को पार्स कैसे करूं?


1001

मेरे पास एक डेटाबेस में कई पंक्तियाँ हैं जिनमें XML है और मैं एक विशेष नोड विशेषता के उदाहरणों को गिनने के लिए एक पायथन स्क्रिप्ट लिखने की कोशिश कर रहा हूं।

मेरा पेड़ ऐसा दिखता है:

<foo>
   <bar>
      <type foobar="1"/>
      <type foobar="2"/>
   </bar>
</foo>

पायथन का उपयोग करके मैं एक्सटेंशन्स "1"और "2"XML में कैसे पहुँच सकता हूँ ?


जवाबों:


780

मैं सुझाव देता हूं ElementTree। उसी एपीआई के अन्य संगत कार्यान्वयन हैं, जैसे कि lxml, और cElementTreeपायथन मानक पुस्तकालय में ही; लेकिन, इस संदर्भ में, जो वे मुख्य रूप से जोड़ते हैं वह और भी अधिक गति है - प्रोग्रामिंग भाग की आसानी एपीआई पर निर्भर करती है, जो ElementTreeपरिभाषित करती है।

पहले rootXML से एक एलिमेंट इंस्टेंस का निर्माण करें , जैसे XML फ़ंक्शन के साथ, या किसी फ़ाइल को कुछ इस तरह से पार्स करके:

import xml.etree.ElementTree as ET
root = ET.parse('thefile.xml').getroot()

या कई अन्य तरीकों से दिखाया गया है ElementTree। फिर कुछ ऐसा करें:

for type_tag in root.findall('bar/type'):
    value = type_tag.get('foobar')
    print(value)

और इसी तरह, आमतौर पर बहुत सरल, कोड पैटर्न।


41
आप xml.etree.cElementTree को अनदेखा करते दिखते हैं जो पायथन के साथ आता है और कुछ पहलुओं में तेजी से tham lxml ("lxml का iterparse () cET में एक से थोड़ा धीमा है" - lxml लेखक से ई-मेल है)।
जॉन मैकिन

7
ElementTree काम करता है और पायथन के साथ शामिल है। हालांकि सीमित XPath समर्थन है और आप किसी तत्व के माता-पिता तक नहीं पहुंच सकते हैं, जो विकास को धीमा कर सकता है (विशेषकर यदि आप यह नहीं जानते हैं)। अजगर एक्सएमएल क्वेरी देखें विवरण के लिए माता-पिता प्राप्त करें।
शमूएल

11
lxmlगति से अधिक जोड़ता है। यह पैरेंट नोड, एक्सएमएल स्रोत में लाइन नंबर आदि जैसी जानकारी तक आसान पहुंच प्रदान करता है, जो कई परिदृश्यों में बहुत उपयोगी हो सकता है।
साहिल गोधने

13
लगता है कि ElementTree में कुछ भेद्यता मुद्दे हैं, यह डॉक्स का एक उद्धरण है: Warning The xml.etree.ElementTree module is not secure against maliciously constructed data. If you need to parse untrusted or unauthenticated data see XML vulnerabilities.
Cristik

5
@ क्रिटिक ऐसा प्रतीत होता है कि अधिकांश xml पार्सर के साथ एक्सएमएल भेद्यता पृष्ठ देखें
गीताकार

427

minidom सबसे तेज और बहुत सीधा है।

एक्सएमएल:

<data>
    <items>
        <item name="item1"></item>
        <item name="item2"></item>
        <item name="item3"></item>
        <item name="item4"></item>
    </items>
</data>

अजगर:

from xml.dom import minidom
xmldoc = minidom.parse('items.xml')
itemlist = xmldoc.getElementsByTagName('item')
print(len(itemlist))
print(itemlist[0].attributes['name'].value)
for s in itemlist:
    print(s.attributes['name'].value)

आउटपुट:

4
item1
item1
item2
item3
item4

9
आपको "आइटम 1" का मूल्य कैसे मिलता है? उदाहरण के लिए: <item name = "item1"> Value1 </ item>
swmcdonnell

88
मुझे यह समझ में आया, अगर किसी के पास भी यही सवाल है। यह s.childNodes [0] .nodeValue
swmcdonnell

1
मुझे आपका उदाहरण पसंद है, मैं इसे लागू करना चाहता हूं लेकिन मैं मिनीडॉम कार्यों को कहां उपलब्ध कर सकता हूं। अजगर minidom वेबसाइट मेरी राय में बेकार है।
ड्रयूडिन

1
मैं भी भ्रमित हूं कि यह itemदस्तावेज़ के शीर्ष स्तर से सीधे क्यों मिल रहा है ? यदि आप इसे पथ ( data->items) की आपूर्ति करते हैं तो यह क्लीनर नहीं होगा ? क्योंकि, क्या होगा अगर आपके पास data->secondSetOfItemsभी नोड्स नाम था itemऔर आप केवल दो सेटों में से एक को सूचीबद्ध करना चाहते थे item?
उभयलिंगी

1
कृपया देखें stackoverflow.com/questions/21124018/…
उभयचर

240

आप ब्यूटीफुल का उपयोग कर सकते हैं :

from bs4 import BeautifulSoup

x="""<foo>
   <bar>
      <type foobar="1"/>
      <type foobar="2"/>
   </bar>
</foo>"""

y=BeautifulSoup(x)
>>> y.foo.bar.type["foobar"]
u'1'

>>> y.foo.bar.findAll("type")
[<type foobar="1"></type>, <type foobar="2"></type>]

>>> y.foo.bar.findAll("type")[0]["foobar"]
u'1'
>>> y.foo.bar.findAll("type")[1]["foobar"]
u'2'

@Ibz की जानकारी के लिए धन्यवाद, हाँ, वास्तव में, यदि स्रोत अच्छी तरह से नहीं बना है, तो पार्सर्स के लिए भी पार्स करना मुश्किल होगा।
आप

45
तीन साल बाद bs4 के साथ यह एक शानदार उपाय है, बहुत लचीला, खासकर अगर स्रोत अच्छी तरह से नहीं बना है
cedbeu

8
@YOU BeautifulStoneSoupमूल्यह्रास हुआ है। बस का उपयोग करेंBeautifulSoup(source_xml, features="xml")
andilabs

5
एक और 3 साल बाद, मैंने एक्सएमएल का उपयोग करके लोड करने की कोशिश की ElementTree, दुर्भाग्य से यह पार्स करने में असमर्थ है जब तक कि मैं स्थानों पर स्रोत को समायोजित नहीं करता हूं, लेकिन BeautifulSoupबिना किसी बदलाव के तुरंत काम किया!
विक्की

8
@ कंडी आपका मतलब है "पदावनत।" "मूल्यह्रास" का अर्थ है यह मूल्य में कमी, आमतौर पर उम्र या पहनने और सामान्य उपयोग से आंसू के कारण।
jpmc26

98

वहाँ कई विकल्प हैं। यदि गति और मेमोरी का उपयोग एक समस्या है तो cElementTree उत्कृष्ट दिखता है। यह बहुत कम ओवरहेड का उपयोग करके केवल फ़ाइल में पढ़ने की तुलना में है readlines

प्रासंगिक मेट्रिक्स नीचे दी गई तालिका में पाया जा सकता है, जिसे cElementTree वेबसाइट से कॉपी किया गया है:

library                         time    space
xml.dom.minidom (Python 2.1)    6.3 s   80000K
gnosis.objectify                2.0 s   22000k
xml.dom.minidom (Python 2.4)    1.4 s   53000k
ElementTree 1.2                 1.6 s   14500k  
ElementTree 1.2.4/1.3           1.1 s   14500k  
cDomlette (C extension)         0.540 s 20500k
PyRXPU (C extension)            0.175 s 10850k
libxml2 (C extension)           0.098 s 16000k
readlines (read as utf-8)       0.093 s 8850k
cElementTree (C extension)  --> 0.047 s 4900K <--
readlines (read as ascii)       0.032 s 5050k   

जैसा कि @jfs द्वारा बताया गया है , cElementTreeपायथन के साथ बंडल में आता है:

  • अजगर 2 from xml.etree import cElementTree as ElementTree:।
  • पायथन 3: from xml.etree import ElementTree(त्वरित सी संस्करण स्वचालित रूप से उपयोग किया जाता है)।

9
वहाँ cElementTree का उपयोग करने के लिए किसी भी downsides है? यह बिना दिमाग के लगता है।
मई

6
जाहिरा तौर पर वे ओएस एक्स पर लाइब्रेरी का उपयोग नहीं करना चाहते हैं क्योंकि मैंने 15 मिनट से अधिक समय बिताने की कोशिश की है कि इसे कहां से डाउनलोड करना है और कोई लिंक काम नहीं करता है। प्रलेखन की कमी अच्छी परियोजनाओं को पनपने से रोकती है, काश और अधिक लोगों को यह एहसास होता।
स्टनर

8
@ स्टनर: यह stdlib में है यानी, आपको कुछ भी डाउनलोड करने की आवश्यकता नहीं है। पायथन 2 पर from xml.etree import cElementTree as ElementTree:। अजगर 3 पर: from xml.etree import ElementTree(त्वरित सी संस्करण प्रयोग किया जाता है स्वचालित रूप से)
JFS

1
@mayhewsw यह पता लगाने का अधिक प्रयास है कि ElementTreeकिसी विशेष कार्य के लिए कुशलतापूर्वक उपयोग कैसे किया जाए । स्मृति में फिट होने वाले दस्तावेज़ों के लिए, इसका उपयोग करना बहुत आसान है minidom, और यह छोटे XML दस्तावेजों के लिए ठीक काम करता है।
एक्यूमेनस

44

मैं सुझाव देता हूं कि सादगी के लिए xmltodict

यह आपके XML को एक ऑर्डरडीड पर पार्स करता है;

>>> e = '<foo>
             <bar>
                 <type foobar="1"/>
                 <type foobar="2"/>
             </bar>
        </foo> '

>>> import xmltodict
>>> result = xmltodict.parse(e)
>>> result

OrderedDict([(u'foo', OrderedDict([(u'bar', OrderedDict([(u'type', [OrderedDict([(u'@foobar', u'1')]), OrderedDict([(u'@foobar', u'2')])])]))]))])

>>> result['foo']

OrderedDict([(u'bar', OrderedDict([(u'type', [OrderedDict([(u'@foobar', u'1')]), OrderedDict([(u'@foobar', u'2')])])]))])

>>> result['foo']['bar']

OrderedDict([(u'type', [OrderedDict([(u'@foobar', u'1')]), OrderedDict([(u'@foobar', u'2')])])])

3
माना। यदि आपको XPath या कुछ भी जटिल की आवश्यकता नहीं है, तो यह उपयोग करने के लिए बहुत सरल है (विशेषकर दुभाषिया में); REST एपीआई के लिए काम जो JSON के बजाय XML को प्रकाशित करता है
Dan Passaro

4
याद रखें कि OrderedDict डुप्लिकेट कुंजियों का समर्थन नहीं करता है। अधिकांश XML एक ही प्रकार के कई भाई-बहनों से भरा-पूरा होता है (जैसे, किसी खंड के सभी अनुच्छेद, या आपके बार के सभी प्रकार)। तो यह केवल बहुत सीमित विशेष मामलों के लिए काम करेगा।
TextGeek

2
@TextGeek इस मामले में, result["foo"]["bar"]["type"]सभी <type>तत्वों की एक सूची है , इसलिए यह अभी भी काम कर रहा है (भले ही संरचना शायद थोड़ी अप्रत्याशित हो)।
luator

38

lxml.objectify वास्तव में सरल है।

अपना नमूना पाठ लेना:

from lxml import objectify
from collections import defaultdict

count = defaultdict(int)

root = objectify.fromstring(text)

for item in root.bar.type:
    count[item.attrib.get("foobar")] += 1

print dict(count)

आउटपुट:

{'1': 1, '2': 1}

countडिफ़ॉल्ट कुंजियों के साथ एक शब्दकोश में प्रत्येक आइटम के मायने रखता है, ताकि आप सदस्यता के लिए जाँच नहीं है। आप भी देखने की कोशिश कर सकते हैं collections.Counter
रयान गिंस्ट्रोम

20

पाइथन में एक्सैट पार्सर के लिए एक इंटरफ़ेस है।

xml.parsers.expat

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

stringofxml = """<foo>
    <bar>
        <type arg="value" />
        <type arg="value" />
        <type arg="value" />
    </bar>
    <bar>
        <type arg="value" />
    </bar>
</foo>"""
count = 0
def start(name, attr):
    global count
    if name == 'type':
        count += 1

p = expat.ParserCreate()
p.StartElementHandler = start
p.Parse(stringofxml)

print count # prints 4

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

1
उदाहरण '09 में बनाया गया था और यह इसी तरह से किया गया था।
Tor Valamo

13

मैं सुझाव दे सकता हूं

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

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

पायथन डेटा संरचनाओं में पार्स करना सीधा है:

import declxml as xml

xml_string = """
<foo>
   <bar>
      <type foobar="1"/>
      <type foobar="2"/>
   </bar>
</foo>
"""

processor = xml.dictionary('foo', [
    xml.dictionary('bar', [
        xml.array(xml.integer('type', attribute='foobar'))
    ])
])

xml.parse_from_string(processor, xml_string)

जो उत्पादन का उत्पादन करता है:

{'bar': {'foobar': [1, 2]}}

एक्सएमएल में डेटा को अनुक्रमित करने के लिए आप उसी प्रोसेसर का भी उपयोग कर सकते हैं

data = {'bar': {
    'foobar': [7, 3, 21, 16, 11]
}}

xml.serialize_to_string(processor, data, indent='    ')

जो निम्न आउटपुट उत्पन्न करता है

<?xml version="1.0" ?>
<foo>
    <bar>
        <type foobar="7"/>
        <type foobar="3"/>
        <type foobar="21"/>
        <type foobar="16"/>
        <type foobar="11"/>
    </bar>
</foo>

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

import declxml as xml

class Bar:

    def __init__(self):
        self.foobars = []

    def __repr__(self):
        return 'Bar(foobars={})'.format(self.foobars)


xml_string = """
<foo>
   <bar>
      <type foobar="1"/>
      <type foobar="2"/>
   </bar>
</foo>
"""

processor = xml.dictionary('foo', [
    xml.user_object('bar', Bar, [
        xml.array(xml.integer('type', attribute='foobar'), alias='foobars')
    ])
])

xml.parse_from_string(processor, xml_string)

जो निम्न आउटपुट उत्पन्न करता है

{'bar': Bar(foobars=[1, 2])}

13

बस एक और संभावना जोड़ने के लिए, आप अनटंगल का उपयोग कर सकते हैं , क्योंकि यह एक साधारण xml-to-python-object लाइब्रेरी है। यहाँ आपके पास एक उदाहरण है:

स्थापना:

pip install untangle

उपयोग:

आपकी XML फ़ाइल (थोड़ा बदला हुआ):

<foo>
   <bar name="bar_name">
      <type foobar="1"/>
   </bar>
</foo>

के साथ विशेषताओं तक पहुँचना untangle:

import untangle

obj = untangle.parse('/path_to_xml_file/file.xml')

print obj.foo.bar['name']
print obj.foo.bar.type['foobar']

उत्पादन होगा:

bar_name
1

अनटंगल के बारे में अधिक जानकारी " अनटंगल " में मिल सकती है " ।

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


मिनिडोम से अलग क्या बनाता है?
एरोन मान

मैं आपको उन दोनों के बीच का अंतर नहीं बता सकता क्योंकि मैंने मिनीडोम के साथ काम नहीं किया है।
जेंगर

10

यहां एक बहुत ही सरल लेकिन प्रभावी कोड का उपयोग किया गया है cElementTree

try:
    import cElementTree as ET
except ImportError:
  try:
    # Python 2.5 need to import a different module
    import xml.etree.cElementTree as ET
  except ImportError:
    exit_err("Failed to import cElementTree from any known place")      

def find_in_tree(tree, node):
    found = tree.find(node)
    if found == None:
        print "No %s in file" % node
        found = []
    return found  

# Parse a xml file (specify the path)
def_file = "xml_file_name.xml"
try:
    dom = ET.parse(open(def_file, "r"))
    root = dom.getroot()
except:
    exit_err("Unable to open and parse input definition file: " + def_file)

# Parse to find the child nodes list of node 'myNode'
fwdefs = find_in_tree(root,"myNode")

यह " अजगर एक्सएमएल पार्स " से है।


7

एक्सएमएल:

<foo>
   <bar>
      <type foobar="1"/>
      <type foobar="2"/>
   </bar>
</foo>

पायथन कोड:

import xml.etree.cElementTree as ET

tree = ET.parse("foo.xml")
root = tree.getroot() 
root_tag = root.tag
print(root_tag) 

for form in root.findall("./bar/type"):
    x=(form.attrib)
    z=list(x)
    for i in z:
        print(x[i])

आउटपुट:

foo
1
2

6

xml.etree.ElementTree बनाम lxml

ये दो सबसे अधिक उपयोग किए जाने वाले पुस्तकालयों के कुछ नियम हैं, जिन्हें मुझे उनके बीच चयन करने से पहले जानना होगा।

xml.etree.ElementTree:

  1. से मानक पुस्तकालय : कोई किसी भी मॉड्यूल स्थापित करने की जरूरत है

lxml

  1. आसानी से XML घोषणा लिखें : उदाहरण के लिए आपको जोड़ने की आवश्यकता है standalone="no"?
  2. सुंदर मुद्रण : आपके पास अतिरिक्त कोड के बिना एक अच्छा इंडेंटेड एक्सएमएल हो सकता है।
  3. कार्यक्षमता को ऑब्जेक्ट करें: यह आपको XML का उपयोग करने की अनुमति देता है जैसे कि आप एक सामान्य पायथन ऑब्जेक्ट पदानुक्रम के साथ काम कर रहे थे .node

6
import xml.etree.ElementTree as ET
data = '''<foo>
           <bar>
               <type foobar="1"/>
               <type foobar="2"/>
          </bar>
       </foo>'''
tree = ET.fromstring(data)
lst = tree.findall('bar/type')
for item in lst:
    print item.get('foobar')

यह foobarविशेषता के मूल्य को प्रिंट करेगा ।


5

मुझे पायथन xml.dom और xml.dom.minidom काफी आसान लगता है। ध्यान रखें कि बड़ी मात्रा में XML के लिए DOM अच्छा नहीं है, लेकिन यदि आपका इनपुट काफी छोटा है तो यह ठीक काम करेगा।


2

यदि आप उपयोग करते हैं, तो एक विशिष्ट विशिष्ट एपीआई का उपयोग करने की कोई आवश्यकता नहीं हैpython-benedict । बस अपने एक्सएमएल से एक नया उदाहरण शुरू करें और इसे आसानी से प्रबंधित करें क्योंकि यह एक dictउपवर्ग है।

स्थापना आसान है: pip install python-benedict

from benedict import benedict as bdict

# data-source can be an url, a filepath or data-string (as in this example)
data_source = """
<foo>
   <bar>
      <type foobar="1"/>
      <type foobar="2"/>
   </bar>
</foo>"""

data = bdict.from_xml(data_source)
t_list = data['foo.bar'] # yes, keypath supported
for t in t_list:
   print(t['@foobar'])

यह समर्थन करता है और को सामान्य आई / ओ संचालन कई स्वरूपों के साथ: Base64, CSV, JSON, TOML, XML, YAMLऔर query-string

GitHub पर यह अच्छी तरह से परीक्षण और खुला स्रोत है


0
#If the xml is in the form of a string as shown below then
from lxml  import etree, objectify
'''sample xml as a string with a name space {http://xmlns.abc.com}'''
message =b'<?xml version="1.0" encoding="UTF-8"?>\r\n<pa:Process xmlns:pa="http://xmlns.abc.com">\r\n\t<pa:firsttag>SAMPLE</pa:firsttag></pa:Process>\r\n'  # this is a sample xml which is a string


print('************message coversion and parsing starts*************')

message=message.decode('utf-8') 
message=message.replace('<?xml version="1.0" encoding="UTF-8"?>\r\n','') #replace is used to remove unwanted strings from the 'message'
message=message.replace('pa:Process>\r\n','pa:Process>')
print (message)

print ('******Parsing starts*************')
parser = etree.XMLParser(remove_blank_text=True) #the name space is removed here
root = etree.fromstring(message, parser) #parsing of xml happens here
print ('******Parsing completed************')


dict={}
for child in root: # parsed xml is iterated using a for loop and values are stored in a dictionary
    print(child.tag,child.text)
    print('****Derving from xml tree*****')
    if child.tag =="{http://xmlns.abc.com}firsttag":
        dict["FIRST_TAG"]=child.text
        print(dict)


### output
'''************message coversion and parsing starts*************
<pa:Process xmlns:pa="http://xmlns.abc.com">

    <pa:firsttag>SAMPLE</pa:firsttag></pa:Process>
******Parsing starts*************
******Parsing completed************
{http://xmlns.abc.com}firsttag SAMPLE
****Derving from xml tree*****
{'FIRST_TAG': 'SAMPLE'}'''

कृपया यह भी बताएं कि आपके उत्तर से समस्या का हल कैसे निकलता है। कोड-केवल उत्तरों को प्रोत्साहित नहीं किया जाता है।
पैद्राम परसियन

-1

यदि स्रोत एक xml फ़ाइल है, तो इस नमूने की तरह कहें

<pa:Process xmlns:pa="http://sssss">
        <pa:firsttag>SAMPLE</pa:firsttag>
    </pa:Process>

आप निम्न कोड आज़मा सकते हैं

from lxml import etree, objectify
metadata = 'C:\\Users\\PROCS.xml' # this is sample xml file the contents are shown above
parser = etree.XMLParser(remove_blank_text=True) # this line removes the  name space from the xml in this sample the name space is --> http://sssss
tree = etree.parse(metadata, parser) # this line parses the xml file which is PROCS.xml
root = tree.getroot() # we get the root of xml which is process and iterate using a for loop
for elem in root.getiterator():
    if not hasattr(elem.tag, 'find'): continue  # (1)
    i = elem.tag.find('}')
    if i >= 0:
        elem.tag = elem.tag[i+1:]

dict={}  # a python dictionary is declared
for elem in tree.iter(): #iterating through the xml tree using a for loop
    if elem.tag =="firsttag": # if the tag name matches the name that is equated then the text in the tag is stored into the dictionary
        dict["FIRST_TAG"]=str(elem.text)
        print(dict)

आउटपुट होगा

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