4

I'm trying to use the uClassify API to categorize objects based on a text. To interact with the API, I need to make XML POST requests, such as:

<?xml version="1.0" encoding="utf-8" ?>
<uclassify xmlns="http://api.uclassify.com/1/RequestSchema" version="1.01">
  <writeCalls writeApiKey="YOUR_WRITE_API_KEY_HERE" classifierName="ManOrWoman">
    <create id="CreateManOrWoman"/>
  </writeCalls>
</uclassify>

I tried to do this using the HTTP Requests module as well as xml.etree.ElementTree to create an XML tree, but I am getting errors left and right. Here's some code I tried:

>>> import elementtree.ElementTree as ET
>>> from xml.etree.cElementTree import Element, ElementTree
>>> import requests
>>>
>>> root = ET.Element("uclassify", xlms="http://api.uclassify.com/1/RequestSchema", version="1.01")
>>> head = ET.SubElement(root, "writeCalls", writeApiKey="*************", classifierName="test")
>>> action = ET.SubElement(head, "create", id="CreateTest")
>>> tree = ElementTree(root)
>>>
>>> r = requests.post('http://api.uclassify.com/', tree)
>>> 
>>> ........
>>> TypeError: must be convertible to a buffer, not ElementTree
bmay2
  • 382
  • 2
  • 4
  • 17
  • Possible duplicate of [How can I send an xml body using requests library?](https://stackoverflow.com/questions/12509888/how-can-i-send-an-xml-body-using-requests-library) – Stevoisiak Oct 27 '17 at 17:59

3 Answers3

5

Once, when I had to do a similar thing, I did like this:

requests.post(url, data=xml_string, headers={'Content-Type':'application/xml; charset=UTF-8'})
JOHN_16
  • 616
  • 6
  • 12
4

Not a requests method, but here's a real simple recipe using urllib2 from my codebase:

import urllib2

from elementtree import ElementTree

def post(url, data, contenttype):
    request = urllib2.Request(url, data)
    request.add_header('Content-Type', contenttype)
    response = urllib2.urlopen(request)
    return response.read()

def postxml(url, elem):
    data = ElementTree.tostring(elem, encoding='UTF-8')
    return post(url, data, 'text/xml')

I suspect what you're missing is the use of tostring to convert the ElementTree Element that you named root.

Mattie
  • 20,280
  • 7
  • 36
  • 54
  • I tried `ElementTree.tostring(tree, encoding='UTF-8')` but got an error: `AttributeError: type object 'ElementTree' has no attribute 'tostring'` so I tried `xml.etree.ElementTree.tostring(tree, encoding='UTF-8')` and got `AttributeError: _ElementInterface instance has no attribute 'iter'`. – bmay2 Aug 03 '12 at 19:47
  • With the imports you're using, I think you need `ET.tostring`. Be sure to call it on `root`, not `tree`; it works on elements, not trees. See http://effbot.org/zone/pythondoc-elementtree-ElementTree.htm#elementtree.ElementTree.tostring-function – Mattie Aug 03 '12 at 19:58
  • Okay, so now it seems like I have a bunch of UTF-8 encoded XML elements. Do I still do `tree = ElementTree(root)`? Because I just tried posting with that tree and got another `TypeError: must be convertible to a buffer, not ElementTree`. – bmay2 Aug 03 '12 at 20:50
  • I don't believe you need `tree` for anything, unless there's some other code not in your question that uses it. Incidentally, if you ever need to get an `Element` from a `ElementTree`, use `getroot`: http://effbot.org/zone/pythondoc-elementtree-ElementTree.htm#elementtree.ElementTree.ElementTree.getroot-method – Mattie Aug 03 '12 at 20:52
  • Ok, I tried posting with just the `root` element and got this exception for r.content: ... – bmay2 Aug 03 '12 at 20:56
  • `'\n\n\tCaught an HttpRequestValidationException due to some bad characters in the request. Make sure your post request is encoded as xml, preferable as UTF-8 (\'Content-Type: text/xml; charset=utf-8\'). Exception: A potentially dangerous Request.Form value was detected from the client (&lt;?xml version=&quot;...\'UTF-8\'?&gt;\n&lt;uclassify version=&quot;...&quot;).\n\n'` – bmay2 Aug 03 '12 at 20:56
  • I don't know what the API you're POSTing to requires, but it appears that you've got some entity escaping going on somewhere in your chain. `tostring` does not swap `<` for `&lt`, and your API seems to be claiming it received `<?xml`... instead of ` – Mattie Aug 05 '12 at 22:12
1

It's waiting for a string XML, try something like this (using requests):

input_string_xml = ElementTree.tostring(tree, encoding='utf8', method='xml')
param_data = {'xml': input_xml}
output_xml = requests.post("http://api.uclassify.com/", data=param_data)
Oswaldo Ferreira
  • 1,339
  • 16
  • 15