开发者

django parse xml with template

I'm looking to create a dynamic way to parse xml files and convert them into a different format as easy as possible..

Here is my fixture.xml

<Orders>
      <Order number="" queue="true" getTax="true">
            <Customer>
                  <Email><![CDATA[mike@domain.com]]></Email>
            </Customer&开发者_Python百科gt;
      </Order>
</Orders>

I'm using the following code

try:
    import xml.etree.cElementTree as ET
except ImportError:
    import xml.etree.ElementTree  as ET



class XMLTree(object):
    def __init__(self, node):
        self.nodes = {}
        self.node = node
        for n in node:
            if len(n.getchildren()):
                xmlnode = XMLTree(n)
            else:
                xmlnode = XMLNode(n)
            if n.tag in self.nodes:
                if isinstance(self.nodes[n.tag], (XMLTree, XMLNode)):
                    self.nodes[n.tag] = [self.nodes[n.tag], xmlnode]
                else:
                    self.nodes[n.tag].append(xmlnode)
            else:
                self.nodes[n.tag] = xmlnode

    def __unicode__(self):
        return unicode(dict((k, str(v)) for k, v in self.nodes.iteritems()))

    def __str__(self):
        return unicode(self).encode('utf-8')

    def __getattr__(self, attr):
        return self.nodes[attr]

    def __getitem__(self, key):
        return self.node.attrib.get(key)

    def __len__(self):
        return len(self.nodes)

    def items(self):
        return self.nodes

class XMLNode(object):
    def __init__(self, node):
        self.node = node

    def __getitem__(self, key):
        return self.node.attrib.get(key)

    def __unicode__(self):
        return self.node.text or ''

    def __str__(self):
        return unicode(self).encode('utf-8')

    def __repr__(self):
        return self.__unicode__()

    def __len__(self):
        return 1


def order_taxcalc(request):
    tree = ET.parse("/tmp/fixture.xml")
    xml = XMLTree(tree.getroot())


    print "Email: ", xml.Order.Customer.Email
    omxXML = render_to_string("endpoints/order.html", {'xml': xml})
    return HttpResponse(omxXML)

Now I get the correct email in console.. but here is my order.html stripped down

<Email>{{xml.Order.Customer.Email}}</Email>

Nothing is displayed. I hope it makes since with what I am trying to do.

Thanks!


The problem lies in how Django tries to evaluate context variables:

  1. dictionary lookup,
  2. attribute lookup,
  3. list-index lookup,
  4. function call.

Firstly a dictionary lookup is tried. Your XMLTree class implements __getitem__ method, so it can be accessed like a dictionary. The problem is that your class raises no KeyError if non-existing key is requested. Instead it returns None.

In the template {{ xml.Order(...) }} is evaluated to xml['Order'], which executes __getitem__('Order') which returns None, which is why there is nothing displayed in your template.

So either:

  • self.node.attrib.get(key) is not returning what is should (None instead of 'Order')
  • __getitem__ is not raising the KeyError.

I've added a simple check and it fixes the issue, so template gets rendered with correct value:

def __getitem__(self, key):
    out = self.node.attrib.get(key)
    if out is not None:
        return out
    else:
        raise KeyError
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜