1 """A quick DOM implementation.
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.
7 # Copyright (C) 2009, Thomas Leonard
8 # See the README file for details, or visit http://0install.net.
10 from xml
.parsers
import expat
12 class Element(object):
14 @ivar uri: the element's namespace
16 @ivar name: the element's localName
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
24 __slots__
= ['uri', 'name', 'attrs', 'childNodes', 'content']
25 def __init__(self
, uri
, name
, attrs
):
28 self
.attrs
= attrs
.copy()
33 attrs
= [n
+ '=' + self
.attrs
[n
] for n
in self
.attrs
]
34 start
= '<{%s}%s %s' % (self
.uri
, self
.name
, ' '.join(attrs
))
36 return start
+ '>' + '\n'.join(map(str, self
.childNodes
)) + ('</%s>' % (self
.name
))
38 return start
+ '>' + self
.content
+ ('</%s>' % (self
.name
))
42 def getAttribute(self
, name
):
43 return self
.attrs
.get(name
, None)
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
50 elem
= prefixes
.createElementNS(doc
, self
.uri
, self
.name
)
52 for fullname
, value
in self
.attrs
.iteritems():
54 ns
, localName
= fullname
.split(' ', 1)
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
))
61 elem
.appendChild(doc
.createTextNode(self
.content
))
65 """SAXHandler that builds a tree of L{Element}s"""
69 def startElementNS(self
, fullname
, attrs
):
70 split
= fullname
.split(' ', 1)
72 self
.stack
.append(Element(split
[0], split
[1], attrs
))
74 self
.stack
.append(Element(None, fullname
, attrs
))
77 def characters(self
, data
):
80 def endElementNS(self
, name
):
81 contents
= self
.contents
.strip()
82 self
.stack
[-1].content
= contents
84 new
= self
.stack
.pop()
86 self
.stack
[-1].childNodes
.append(new
)
91 """Parse an XML stream into a tree of L{Element}s.
92 @param source: data to parse
96 handler
= QSAXhandler()
97 parser
= expat
.ParserCreate(namespace_separator
= ' ')
99 parser
.StartElementHandler
= handler
.startElementNS
100 parser
.EndElementHandler
= handler
.endElementNS
101 parser
.CharacterDataHandler
= handler
.characters
103 parser
.ParseFile(source
)
107 """Keep track of namespace prefixes. Used when serialising a document.
110 def __init__(self
, default_ns
):
112 self
.default_ns
= default_ns
115 prefix
= self
.prefixes
.get(ns
, None)
118 prefix
= 'ns%d' % len(self
.prefixes
)
119 self
.prefixes
[ns
] = prefix
122 def setAttributeNS(self
, elem
, uri
, localName
, value
):
124 elem
.setAttributeNS(None, localName
, value
)
126 elem
.setAttributeNS(uri
, self
.get(uri
) + ':' + localName
, value
)
128 def createElementNS(self
, doc
, uri
, localName
):
129 if uri
== self
.default_ns
:
130 return doc
.createElementNS(uri
, localName
)
132 return doc
.createElementNS(uri
, self
.get(uri
) + ':' + localName
)