If you want to be able to parse the returned XML before doing stuff with it, the xml tree is your friend.
import requests
import xml.etree.ElementTree as ET
r = requests.get('url', auth=('user', 'pass'))
tree = ET.parse(r.text)
root = tree.getroot()
Otherwise, as jordanm has commented, you could just save it to a file and be done with it.
with open('data.xml', 'w') as f:
f.write(r.text)
Answer from enigma on Stack OverflowIf you want to be able to parse the returned XML before doing stuff with it, the xml tree is your friend.
import requests
import xml.etree.ElementTree as ET
r = requests.get('url', auth=('user', 'pass'))
tree = ET.parse(r.text)
root = tree.getroot()
Otherwise, as jordanm has commented, you could just save it to a file and be done with it.
with open('data.xml', 'w') as f:
f.write(r.text)
Few notes related to Python3 (at least 3.6 versions):
1) when using xml.etree.ElementTree with requests, you use fromstring not parse. r.text returns a string, and xml.etree.ElementTree.parse is for files
import requests
import xml.etree.ElementTree as ET
r = requests.get("https://xml.returning.uri")
root = ET.fromstring(r.text)
2) This creates an element object as the root (no more tree). So to write it back out, you'll need to make it a tree:
tree = ET.ElementTree(root)
tree.write("file.xml")
From the docs
xml.etree.ElementTree.parse(source, parser=None) Parses an XML section into an element tree. source is a filename or file object containing XML data.
xml.etree.ElementTree.fromstring(text) Parses an XML section from a string constant. Same as XML(). text is a string containing XML data. Returns an Element instance
Videos
if you use Elementtree
import xml.etree.cElementTree as ET
root = ET.Element("root")
doc = ET.SubElement(root, "doc")
ET.SubElement(doc, "field1", name="blah").text = "some value1"
ET.SubElement(doc, "field2", name="asdfasd").text = "some vlaue2"
tree = ET.ElementTree(root)
tree.write("filename.xml")
Assuming you have a string variable containing the xml data, you can do the following:
with open("output.xml", "w") as f:
f.write(xmlstr)
These days, the most popular (and very simple) option is the ElementTree API, which has been included in the standard library since Python 2.5.
The available options for that are:
- ElementTree (Basic, pure-Python implementation of ElementTree. Part of the standard library since 2.5)
- cElementTree (Optimized C implementation of ElementTree. Also offered in the standard library since 2.5. Deprecated and folded into the regular ElementTree as an automatic thing as of 3.3.)
- LXML (Based on libxml2. Offers a rich superset of the ElementTree API as well XPath, CSS Selectors, and more)
Here's an example of how to generate your example document using the in-stdlib cElementTree:
import xml.etree.cElementTree as ET
root = ET.Element("root")
doc = ET.SubElement(root, "doc")
ET.SubElement(doc, "field1", name="blah").text = "some value1"
ET.SubElement(doc, "field2", name="asdfasd").text = "some vlaue2"
tree = ET.ElementTree(root)
tree.write("filename.xml")
I've tested it and it works, but I'm assuming whitespace isn't significant. If you need "prettyprint" indentation, let me know and I'll look up how to do that. (It may be an LXML-specific option. I don't use the stdlib implementation much)
For further reading, here are some useful links:
- API docs for the implementation in the Python standard library
- Introductory Tutorial (From the original author's site)
- LXML etree tutorial. (With example code for loading the best available option from all major ElementTree implementations)
As a final note, either cElementTree or LXML should be fast enough for all your needs (both are optimized C code), but in the event you're in a situation where you need to squeeze out every last bit of performance, the benchmarks on the LXML site indicate that:
- LXML clearly wins for serializing (generating) XML
- As a side-effect of implementing proper parent traversal, LXML is a bit slower than cElementTree for parsing.
The lxml library includes a very convenient syntax for XML generation, called the E-factory. Here's how I'd make the example you give:
#!/usr/bin/python
import lxml.etree
import lxml.builder
E = lxml.builder.ElementMaker()
ROOT = E.root
DOC = E.doc
FIELD1 = E.field1
FIELD2 = E.field2
the_doc = ROOT(
DOC(
FIELD1('some value1', name='blah'),
FIELD2('some value2', name='asdfasd'),
)
)
print lxml.etree.tostring(the_doc, pretty_print=True)
Output:
<root>
<doc>
<field1 name="blah">some value1</field1>
<field2 name="asdfasd">some value2</field2>
</doc>
</root>
It also supports adding to an already-made node, e.g. after the above you could say
the_doc.append(FIELD2('another value again', name='hithere'))
tostring() returns a bytes object unless encoding="unicode" is used.
The code can be simplified quite a bit. There is no need to use open(), fromstring() or tostring(). Just parse the XML file into an ElementTree object, do your changes, and save using ElementTree.write().
from xml.etree import ElementTree as ET
tree = ET.parse("prices.xml")
root = tree.getroot()
for price_table in root.findall('price-table'):
amount = price_table.find('amount')
if float(amount.text) != 0:
root.remove(price_table)
tree.write('xmlwrite.txt')
If you print the type(xmltowrite) you will see it's a <class 'bytes'>. You can decode it with ET.tostring(root).decode("Utf-8"), than you get <class 'str'>.
With ET.tostring(tree) you get a non-formatted string representation of the XML. To save it to a file:
with open("filename", "w") as f:
f.write(ET.tostring(tree))
In python 3.x
The proposed solution won't work unless you specify with open("filename", "wb") as f: instead of with open("filename", "w") as f: