2013-02-14 10 views
11

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

नमूना फ़ाइल 1:

<root> 
    <element1>textA</element1> 
    <elements> 
    <nested1>text now</nested1> 
    </elements> 
</root> 

नमूना फ़ाइल 2:

<root> 
    <element2>textB</element2> 
    <elements> 
    <nested1>text after</nested1> 
    <nested2>new text</nested2> 
    </elements> 
</root> 

मैं क्या चाहते हैं:

<root> 
    <element1>textA</element1>  
    <element2>textB</element2> 
    <elements> 
    <nested1>text after</nested1> 
    <nested2>new text</nested2> 
    </elements> 
</root> 

मैंने जो कोशिश की है:

this answer से।

from xml.etree import ElementTree as et 
def combine_xml(files): 
    first = None 
    for filename in files: 
     data = et.parse(filename).getroot() 
     if first is None: 
      first = data 
     else: 
      first.extend(data) 
    if first is not None: 
     return et.tostring(first) 

मुझे क्या मिलेगा:

<root> 
    <element1>textA</element1> 
    <elements> 
    <nested1>text now</nested1> 
    </elements> 
    <element2>textB</element2> 
    <elements> 
    <nested1>text after</nested1> 
    <nested2>new text</nested2> 
    </elements> 
</root> 

मुझे आशा है कि आप देख सकते हैं और अपनी समस्या समझ सकते हैं। मैं एक उचित समाधान की तलाश में हूं, कोई मार्गदर्शन अद्भुत होगा।

समस्या को स्पष्ट करने के लिए, मेरे पास मौजूद वर्तमान समाधान का उपयोग करके, नेस्टेड तत्व विलय नहीं किए जाते हैं।

उत्तर

18

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

from xml.etree import ElementTree as et 

class XMLCombiner(object): 
    def __init__(self, filenames): 
     assert len(filenames) > 0, 'No filenames!' 
     # save all the roots, in order, to be processed later 
     self.roots = [et.parse(f).getroot() for f in filenames] 

    def combine(self): 
     for r in self.roots[1:]: 
      # combine each element with the first one, and update that 
      self.combine_element(self.roots[0], r) 
     # return the string representation 
     return et.tostring(self.roots[0]) 

    def combine_element(self, one, other): 
     """ 
     This function recursively updates either the text or the children 
     of an element if another element is found in `one`, or adds it 
     from `other` if not found. 
     """ 
     # Create a mapping from tag name to element, as that's what we are fltering with 
     mapping = {el.tag: el for el in one} 
     for el in other: 
      if len(el) == 0: 
       # Not nested 
       try: 
        # Update the text 
        mapping[el.tag].text = el.text 
       except KeyError: 
        # An element with this name is not in the mapping 
        mapping[el.tag] = el 
        # Add it 
        one.append(el) 
      else: 
       try: 
        # Recursively process the element, and update it in the same way 
        self.combine_element(mapping[el.tag], el) 
       except KeyError: 
        # Not in the mapping 
        mapping[el.tag] = el 
        # Just add it 
        one.append(el) 

if __name__ == '__main__': 
    r = XMLCombiner(('sample1.xml', 'sample2.xml')).combine() 
    print '-'*20 
    print r 
+0

पूरी तरह से काम करता है, धन्यवाद, मैंने अभी अपना कोड लिखना शुरू कर दिया था। :) –

+0

अच्छा, धन्यवाद। हमें विशेषताओं को मर्ज करने की भी आवश्यकता है। तत्व टेक्स्ट को बदलने के बाद 'combine_element' और 'मैपिंग [el.tag] .attrib.update (el.attrib)' की भिखारी पर' one.attrib.update (other.attrib) 'जोड़कर किया जा सकता है। –

+0

ओह ठीक है, मैं विशेषताओं के बारे में भूल गया था। अच्छी पकड़। – jadkik94

2

धन्यवाद, लेकिन मेरी समस्या गुण भी विचार करके विलय करने के लिए किया गया था। मेरे पैच के बाद कोड यहां है:

import sys 
    from xml.etree import ElementTree as et 


    class hashabledict(dict): 
     def __hash__(self): 
      return hash(tuple(sorted(self.items()))) 


    class XMLCombiner(object): 
     def __init__(self, filenames): 
      assert len(filenames) > 0, 'No filenames!' 
      # save all the roots, in order, to be processed later 
      self.roots = [et.parse(f).getroot() for f in filenames] 

    def combine(self): 
     for r in self.roots[1:]: 
      # combine each element with the first one, and update that 
      self.combine_element(self.roots[0], r) 
     # return the string representation 
     return et.ElementTree(self.roots[0]) 

    def combine_element(self, one, other): 
     """ 
     This function recursively updates either the text or the children 
     of an element if another element is found in `one`, or adds it 
     from `other` if not found. 
     """ 
     # Create a mapping from tag name to element, as that's what we are fltering with 
     mapping = {(el.tag, hashabledict(el.attrib)): el for el in one} 
     for el in other: 
      if len(el) == 0: 
       # Not nested 
       try: 
        # Update the text 
        mapping[(el.tag, hashabledict(el.attrib))].text = el.text 
       except KeyError: 
        # An element with this name is not in the mapping 
        mapping[(el.tag, hashabledict(el.attrib))] = el 
        # Add it 
        one.append(el) 
      else: 
       try: 
        # Recursively process the element, and update it in the same way 
        self.combine_element(mapping[(el.tag, hashabledict(el.attrib))], el) 
       except KeyError: 
        # Not in the mapping 
        mapping[(el.tag, hashabledict(el.attrib))] = el 
        # Just add it 
        one.append(el) 

if __name__ == '__main__': 

    r = XMLCombiner(sys.argv[1:-1]).combine() 
    print '-'*20 
    print et.tostring(r.getroot()) 
    r.write(sys.argv[-1], encoding="iso-8859-1", xml_declaration=True) 
संबंधित मुद्दे