Package zeroinstall :: Package injector :: Module qdom
[frames] | no frames]

Source Code for Module zeroinstall.injector.qdom

  1  """A quick DOM implementation. 
  2   
  3  Python's xml.dom is very slow. The xml.sax module is also slow (as it imports urllib2). 
  4  This is our light-weight version. 
  5  """ 
  6   
  7  # Copyright (C) 2009, Thomas Leonard 
  8  # See the README file for details, or visit http://0install.net. 
  9   
 10  from xml.parsers import expat 
 11   
12 -class Element(object):
13 """An XML element. 14 @ivar uri: the element's namespace 15 @type uri: str 16 @ivar name: the element's localName 17 @type name: str 18 @ivar attrs: the element's attributes (key is in the form [namespace " "] localName) 19 @type attrs: {str: str} 20 @ivar childNodes: children 21 @type childNodes: [L{Element}] 22 @ivar content: the text content 23 @type content: str""" 24 __slots__ = ['uri', 'name', 'attrs', 'childNodes', 'content']
25 - def __init__(self, uri, name, attrs):
26 self.uri = uri 27 self.name = name 28 self.attrs = attrs.copy() 29 self.content = None 30 self.childNodes = []
31
32 - def __str__(self):
33 attrs = [n + '=' + self.attrs[n] for n in self.attrs] 34 start = '<{%s}%s %s' % (self.uri, self.name, ' '.join(attrs)) 35 if self.childNodes: 36 return start + '>' + '\n'.join(map(str, self.childNodes)) + ('</%s>' % (self.name)) 37 elif self.content: 38 return start + '>' + self.content + ('</%s>' % (self.name)) 39 else: 40 return start + '/>'
41
42 - def getAttribute(self, name):
43 return self.attrs.get(name, None)
44
45 - def toDOM(self, doc, prefixes):
46 """Create a DOM Element for this qdom.Element. 47 @param doc: document to use to create the element 48 @return: the new element 49 """ 50 elem = prefixes.createElementNS(doc, self.uri, self.name) 51 52 for fullname, value in self.attrs.iteritems(): 53 if ' ' in fullname: 54 ns, localName = fullname.split(' ', 1) 55 else: 56 ns, localName = None, fullname 57 prefixes.setAttributeNS(elem, ns, localName, value) 58 for child in self.childNodes: 59 elem.appendChild(child.toDOM(doc, prefixes)) 60 if self.content: 61 elem.appendChild(doc.createTextNode(self.content)) 62 return elem
63
64 -class QSAXhandler:
65 """SAXHandler that builds a tree of L{Element}s"""
66 - def __init__(self):
67 self.stack = []
68
69 - def startElementNS(self, fullname, attrs):
70 split = fullname.split(' ', 1) 71 if len(split) == 2: 72 self.stack.append(Element(split[0], split[1], attrs)) 73 else: 74 self.stack.append(Element(None, fullname, attrs)) 75 self.contents = ''
76
77 - def characters(self, data):
78 self.contents += data
79
80 - def endElementNS(self, name):
81 contents = self.contents.strip() 82 self.stack[-1].content = contents 83 self.contents = '' 84 new = self.stack.pop() 85 if self.stack: 86 self.stack[-1].childNodes.append(new) 87 else: 88 self.doc = new
89
90 -def parse(source):
91 """Parse an XML stream into a tree of L{Element}s. 92 @param source: data to parse 93 @type source: file 94 @return: the root 95 @rtype: L{Element}""" 96 handler = QSAXhandler() 97 parser = expat.ParserCreate(namespace_separator = ' ') 98 99 parser.StartElementHandler = handler.startElementNS 100 parser.EndElementHandler = handler.endElementNS 101 parser.CharacterDataHandler = handler.characters 102 103 parser.ParseFile(source) 104 return handler.doc
105
106 -class Prefixes:
107 """Keep track of namespace prefixes. Used when serialising a document. 108 @since: 0.54 109 """
110 - def __init__(self, default_ns):
111 self.prefixes = {} 112 self.default_ns = default_ns
113
114 - def get(self, ns):
115 prefix = self.prefixes.get(ns, None) 116 if prefix: 117 return prefix 118 prefix = 'ns%d' % len(self.prefixes) 119 self.prefixes[ns] = prefix 120 return prefix
121
122 - def setAttributeNS(self, elem, uri, localName, value):
123 if uri is None: 124 elem.setAttributeNS(None, localName, value) 125 else: 126 elem.setAttributeNS(uri, self.get(uri) + ':' + localName, value)
127
128 - def createElementNS(self, doc, uri, localName):
129 if uri == self.default_ns: 130 return doc.createElementNS(uri, localName) 131 else: 132 return doc.createElementNS(uri, self.get(uri) + ':' + localName)
133