42716

How to copy multiple XML nodes to another file in Python

Bare in mind I am very new to Python. I'm trying to copy few XML nodes from sample1.xml to out.xml if it doesn't exist in sample2.xml.

<strong>this is how far I got before I'm stuck</strong>

import xml.etree.ElementTree as ET tree = ET.ElementTree(file='sample1.xml') addtree = ET.ElementTree(file='sample2.xml') root = tree.getroot() addroot = addtree.getroot() for adel in addroot.findall('.//cars/car'): for el in root.findall('cars/car'): with open('out.xml', 'w+') as f: f.write("BEFORE\n") f.write(el.tag) f.write("\n") f.write(adel.tag) f.write("\n") f.write("\n") f.write("AFTER\n") el = adel f.write(el.tag) f.write("\n") f.write(adel.tag)

I have no idea what I'm missing, but it's only copying the actual "tag" itself.

<strong>outputs this:</strong>

BEFORE car car AFTER car car

So I'm missing the children nodes, and also the <, >, </, > tags. Expected result is below.

<strong>sample1.xml:</strong>

<cars> <car> <use-car>0</use-car> <use-gas>0</use-gas> <car-name /> <car-key /> <car-location>hawaii</car-location> <car-port>5</car-port> </car> </cars>

<strong>sample2.xml:</strong>

<cars> <old> 1 </old> <new> 8 </new> <car /> </cars>

<strong>expected result in out.xml (final product)</strong>

<cars> <old> 1 </old> <new> 8 </old> <car> <use-car>0</use-car> <use-gas>0</use-gas> <car-name /> <car-key /> <car-location>hawaii</car-location> <car-port>5</car-port> </car> </cars>

All the other nodes old and new must remain untouched. I'm just trying to replace <car /> with all its children and grandchildren (if existed) nodes.

Answer1:

<strong>First</strong>, a couple of trivial issues with your XML:

    <li><strong>sample1</strong>: The closing cars tag is missing a /</li> <li><strong>sample2</strong>: The closing new tag incorrectly reads old, should read new</li> </ul>

    <strong>Second</strong>, a disclaimer: my solution below has its limitations - in particular, it wouldn't handle repeatedly substituting the car node from <strong>sample1</strong> into multiple spots in <strong>sample2</strong>. But it works fine for the sample files you've supplied.

    <strong>Third</strong>: thanks to the top couple of answers on access ElementTree node parent node - they informed the implementation of get_node_parent_info below.

    <strong>Finally</strong>, the code:

    import xml.etree.ElementTree as ET def find_child(node, with_name): """Recursively find node with given name""" for element in list(node): if element.tag == with_name: return element elif list(element): sub_result = find_child(element, with_name) if sub_result is not None: return sub_result return None def replace_node(from_tree, to_tree, node_name): """ Replace node with given node_name in to_tree with the same-named node from the from_tree """ # Find nodes of given name ('car' in the example) in each tree from_node = find_child(from_tree.getroot(), node_name) to_node = find_child(to_tree.getroot(), node_name) # Find where to substitute the from_node into the to_tree to_parent, to_index = get_node_parent_info(to_tree, to_node) # Replace to_node with from_node to_parent.remove(to_node) to_parent.insert(to_index, from_node) def get_node_parent_info(tree, node): """ Return tuple of (parent, index) where: parent = node's parent within tree index = index of node under parent """ parent_map = {c:p for p in tree.iter() for c in p} parent = parent_map[node] return parent, list(parent).index(node) from_tree = ET.ElementTree(file='sample1.xml') to_tree = ET.ElementTree(file='sample2.xml') replace_node(from_tree, to_tree, 'car') # ET.dump(to_tree) to_tree.write('output.xml')

    <strong>UPDATE</strong>: It was recently brought to my attention that the implementation of find_child() in the solution I originally supplied would fail if the "child" in question was not in the first branch of the XML tree that was traversed. I've updated the implementation above to rectify this.

Recommend

  • Rails time zone from URL params
  • Angular 2 - Bootstrap (Ng2-Bootstrap) typeahead implementation
  • Pull to refresh in Angular Js
  • Layout with 'maps' package
  • dplyr idiom for “select A, B, max(C) from D group by C”
  • When is it better for an assembler to use sign extended relocation like R_X86_64_32S instead of zero
  • ARM MOV and MVN operand
  • PHP Handling Namespace with SimpleXML
  • Angular2 emit event up to the DOM tree
  • Firebase, only get new children
  • Excel VBA How to populate a multi-dimensional (3d) array with values from multiple excel ranges?
  • CORS with socket.io
  • Magento get URL before current
  • Prevent Tomcat from caching request during starup
  • How to disable all widgets inside Panel or inside Composite?
  • Zoom in and out of jPanel
  • presentShareDialogWithParams posts to FB wall, but callback handler results say error
  • Access Android Market through SSH tunnel
  • Firefox Extension - Monitor refresh and change of tab
  • Saving Changes After In-App Purchase Has Been Purchased
  • How to run “Deployd” on port 80 instead of port 5000 in webserver.
  • PHP buffered output depending on server setting?
  • Functions in global context
  • how to adjust image in a panel in Java swing?
  • MongoDB in PHP using aggregate to group by _id is null not working
  • Why value captured by reference in lambda is broken? [duplicate]
  • Is possible to count alias result on mysql
  • Possible to stop flickering java tooltip in heavyweight mode?
  • Check if a string to interpolate provides expected placeholders
  • To display the title for the current loaction in map in iphone
  • XCode can't find symbols for a specific iOS library/framework project
  • JTable with a ScrollPane misbehaving
  • Why joiner is not used after Sequence generator or Update statergy
  • Getting Messege Twice Using IMvxMessenger
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • Recursive/Hierarchical Query Using Postgres
  • costura.fody for a dll that references another dll
  • Observable and ngFor in Angular 2
  • UserPrincipal.Current returns apppool on IIS
  • java string with new operator and a literal