I'm integrating with the google checkout api and all of their attributes include hyphens in their attribute values. So to create a request to charge an order I need to send an xml post that looks like:
<?xml version="1.0" encoding="UTF-8"?>
<charge-and-ship-order xmlns="http://checkout.google.com/schema/2" google-order-number="6014423719">
<amount currency="USD">335.55</amount>
</charge-and-ship-order>
I'm having trouble building that xml with the attribute "google-order-number". The following code works if I want to create an empty node:
>>> xml=XMLBuilder()
>>> xml << ('charge-and-ship-order, {'xmlns':'xxx','google-order-number':'3433'})
>>> str(xml)
>>> <charge-and-ship-order google-order-number="3433" xmlns="xxx" />
But If I try to child node for the amount using the documented way:
>>> xml=XMLBuilder()
>>> with xml('charge-and-ship-order', xmlns='xxx', google-order-number='3433'}):
>>> with xml('amount', currency="USD"):
>>> xml << '4.54'
I get an error saying:
SyntaxError: keyword can't be an expression
I've also tried:
>>> xml=XMLBuilder()
>>> with xml('charge-and-ship-order', {'xmlns':'xxx', 'google-order-number':'3433'}):
>>> with xml << 'test'
and I get a traceback in the XMLBuilder library saying
File "/xmlbuilder/xmlbuilder/__init__.py", line 102, in __call__
x(*dt,**mp)
File "/xmlbuilder/xmlbuilder/__init__.py", line 36, in __call__
text = "".join(dt)
TypeError: sequence item 0: expected string, dict found
Any Ideas how to use an attribute like that? I'm using the XMLBuilder library located at
http://pypi.python.org/pypi/xmlbuilder
You can pass the attributes in a dictionary like this:
function_call(**{'weird-named-key': 'value'})
Related
I'm trying to do something I thought should be very simple in ElementTree: find elements with specific tag content. The docs give the example:
*[tag='text']* Selects all elements that have a child named *tag* whose complete text content, including descendants, equals the given *text*.
Which seems straightforward enough. However, it does not work as I expect. Suppose I want to find all examples of <note>NEW</note>. The following complete example:
#!/usr/bin/env python
import xml.etree.ElementTree as ET
xml = """<?xml version="1.0"?>
<entry>
<foo>blah</foo>
<foo>bblic</foo>
<foo>fjdks<note>NEW</note></foo>
<foo>fdfsd</foo>
<foo>ljklj<note>NEW</note></foo>
</entry>
"""
root = ET.fromstring(xml)
print("Number of 'foo' elements: %d" % len(root.findall('.//foo')))
print("Number of new 'foo' elements: %d" % len(root.findall('.//[note="NEW"]')))
Yields:
$ python foo.py
Number of 'foo' elements: 5
Traceback (most recent call last):
File "/usr/lib/python3.10/xml/etree/ElementPath.py", line 370, in iterfind
selector = _cache[cache_key]
KeyError: ('.//[note="NEW"]',)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/foo.py", line 17, in <module>
print("Number of new 'foo' elements: %d" % len(root.findall('.//[note="NEW"]')))
File "/usr/lib/python3.10/xml/etree/ElementPath.py", line 411, in findall
return list(iterfind(elem, path, namespaces))
File "/usr/lib/python3.10/xml/etree/ElementPath.py", line 384, in iterfind
selector.append(ops[token[0]](next, token))
File "/usr/lib/python3.10/xml/etree/ElementPath.py", line 193, in prepare_descendant
raise SyntaxError("invalid descendant")
SyntaxError: invalid descendant
How am I meant to do this simple task?
docs says also that
Predicates (expressions within square brackets) must be preceded by a
tag name, an asterisk, or another predicate.
taking this is account
root.findall('.//[note="NEW"]')
is illegal, you should add * before [ to denote any tag i.e.
root.findall('.//*[note="NEW"]')
xor use tag name before [ to denote certain tag i.e.
root.findall('.//foo[note="NEW"]')
The main problem seems an expected dependency from first to second search, which does not exist.
This works (but used syntax requires Python >=3.10):
for foo in root.findall('.//foo[note="NEW"]'):
print(foo.text)
I'm trying to create an XML file that needs to be sent to a server, with this format:
<x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:sen2="http://www.some_url.com">
<x:Header>
I'm working with Python 3 and the lxml library, but when trying to create the element I get an error.
Test code:
def authSendDataExtraccion():
envelope = etree.Element("x:Envelope")
debug_XML(envelope)
Result:
ValueError: Invalid tag name 'x:Envelope'
How can I use the ":" character in the element and attribute names?
Use an nsmap to create an element in a namespace:
envelope = etree.Element("Envelope", nsmap={'x': 'http://schemas.xmlsoap.org/soap/envelope/'})
May not be strange, but I have never used xml, or PHP, which is two of the things I am using for an upcoming project.
Anyway, I am parsing this XML feed. Each <item> contains an <enclosure url=...>
Where ... = URLs & image types etc
In Python 3 using feedparser I can use
feed = feedparser.parse("http://www.huffingtonpost.com/feeds/verticals/good-news/index.xml")
l = feed.entries[12]['title']`
just fine, but when I try to get the URL of an image using
p = feed.entries[12]['enclosure']
I get an error
Traceback (most recent call last):
File "<pyshell#28>", line 1, in <module>
p = feed.entries[12]['enclosure']
File "C:\Python34\lib\site-packages\feedparser-5.1.3-py3.4.egg\feedparser.py", line 375, in __getitem__
return dict.__getitem__(self, key)
KeyError: 'enclosure'
So obviously enclosure isn't coming back with anything, I suspect this is because in the XML it does not use
<name of object>Text</name of object>
Instead it uses
<enclosure url=... blah blah blah />
How do I get the value of URL? It is equal to a string (url="url is here")
Looking at the feedparse docs try using the entries[i].enclosures[j].href reference which returns the URL of the linked file:
feed = feedparser.parse("http://www.huffingtonpost.com/feeds/verticals/good-news/index.xml")
l = feed.entries[12].enclosures[1].href
Sorry, trying to understand and get used to dictionary and list objects.
I'm calling eBay's API through their ebaysdk, and want to store the items from it to a collection as documents in Mongo. Simple.
Here's a sample of the schema that will be returned:
<timestamp>2009-09-04T00:47:12.456Z</timestamp>
<searchResult count="2">
<item>
<itemId>230371938681</itemId>
<title>Harry Potter and the Order of the Phoenix HD-DVD</title>
<globalId>EBAY-US</globalId>
<primaryCategory>
<categoryId>617</categoryId>
<categoryName>DVD, HD DVD & Blu-ray</categoryName>
</primaryCategory>
I've tried 500 iterations of this code, stripped down to the most basic here's what I have.
from ebaysdk import finding
from pymongo import MongoClient
api = finding(appid="billy-40d0a7e49d87")
api.execute('findItemsByKeywords', {'keywords': 'potter'})
listings = api.response_dict()
client = MongoClient('mongodb://user:pass#billy.mongohq.com:10099/ebaystuff')
db = client['ebaycollection']
ebay_collection = db.ebaysearch
for key in listings:
print key
ebay_collection.insert(key)
Will get this error:
Traceback (most recent call last):
File "ebay_search.py", line 34, in <module>
ebay_collection.insert(key)
File "/Library/Python/2.7/site-packages/pymongo/collection.py", line 408, in insert
self.uuid_subtype, client)
File "/Library/Python/2.7/site-packages/pymongo/collection.py", line 378, in gen
doc['_id'] = ObjectId()
TypeError: 'str' object does not support item assignment
Simple stuff. All I want to do is add each item as a document.
An immutable type like a string cannot be used as a document because it doesn't allow adding additional fields, like the _id field Mongo requires. You can instead wrap the string in a dictionary to serve as a wrapper document:
key_doc = {'key': key}
ebay_collection.insert(key_doc)
This question already has answers here:
Write xml file using lxml library in Python
(5 answers)
Closed 9 years ago.
from lxml import etree
root = etree.Element('root1')
element = etree.SubElement(root, 'element1')
root.write( 'xmltree.xml' )
Error:
AttributeError: 'lxml.etree._Element' object has no attribute 'write'
how can I fix this?
Elements (like root) do not have a write method, but ElementTrees do:
from lxml import etree
root = etree.Element('root1')
element = etree.SubElement(root, 'element1')
tree = root.getroottree()
print(type(tree))
# <type 'lxml.etree._ElementTree'>
tree.write('xmltree.xml')
The documentation on tree.write is a little hard to find on the web. Here is the method's doc string:
In [7]: tree.write?
Type: builtin_function_or_method
Base Class: <type 'builtin_function_or_method'>
String Form: <built-in method write of lxml.etree._ElementTree object at 0x95c48cc>
Namespace: Interactive
Docstring:
write(self, file, encoding=None, method="xml",
pretty_print=False, xml_declaration=None, with_tail=True,
standalone=None, compression=0,
exclusive=False, with_comments=True)
Write the tree to a filename, file or file-like object.
Defaults to ASCII encoding and writing a declaration as needed.
The keyword argument 'method' selects the output method:
'xml', 'html', 'text' or 'c14n'. Default is 'xml'.
The ``exclusive`` and ``with_comments`` arguments are only
used with C14N output, where they request exclusive and
uncommented C14N serialisation respectively.
Passing a boolean value to the ``standalone`` option will
output an XML declaration with the corresponding
``standalone`` flag.
The ``compression`` option enables GZip compression level 1-9.
If you are wanting to save your new xml to a file then etree.tostring is the method to use.
E.g.
>>> from lxml import etree
>>> root = etree.Element('root1')
>>> element = etree.SubElement(root, 'element1')
>>> print etree.tostring(root,pretty_print=True) ## Print document
<root1>
<element1/>
</root1>
>>> with open('xmltree.xml','w') as f: ## Write document to file
... f.write(etree.tostring(root,pretty_print=True))
...
>>>