Mercurial > traipse_dev
comparison orpg/pulldom.py @ 0:4385a7d0efd1 grumpy-goblin
Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author | sirebral |
---|---|
date | Tue, 14 Jul 2009 16:41:58 -0500 |
parents | |
children | 551cd440acce |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4385a7d0efd1 |
---|---|
1 import minidom | |
2 import xml.sax,xml.sax.handler | |
3 import types | |
4 | |
5 try: | |
6 from cStringIO import StringIO | |
7 except ImportError: | |
8 from StringIO import StringIO | |
9 | |
10 try: | |
11 _StringTypes = [types.StringType, types.UnicodeType] | |
12 except AttributeError: | |
13 _StringTypes = [types.StringType] | |
14 | |
15 START_ELEMENT = "START_ELEMENT" | |
16 END_ELEMENT = "END_ELEMENT" | |
17 COMMENT = "COMMENT" | |
18 START_DOCUMENT = "START_DOCUMENT" | |
19 END_DOCUMENT = "END_DOCUMENT" | |
20 PROCESSING_INSTRUCTION = "PROCESSING_INSTRUCTION" | |
21 IGNORABLE_WHITESPACE = "IGNORABLE_WHITESPACE" | |
22 CHARACTERS = "CHARACTERS" | |
23 | |
24 class PullDOM(xml.sax.ContentHandler): | |
25 def __init__(self): | |
26 self.firstEvent = [None, None] | |
27 self.lastEvent = self.firstEvent | |
28 self._ns_contexts = [{}] # contains uri -> prefix dicts | |
29 self._current_context = self._ns_contexts[-1] | |
30 | |
31 def setDocumentLocator(self, locator): pass | |
32 | |
33 def startPrefixMapping(self, prefix, uri): | |
34 self._ns_contexts.append(self._current_context.copy()) | |
35 self._current_context[uri] = prefix | |
36 | |
37 def endPrefixMapping(self, prefix): | |
38 del self._ns_contexts[-1] | |
39 | |
40 def startElementNS(self, name, tagName , attrs): | |
41 uri,localname = name | |
42 if uri: | |
43 # When using namespaces, the reader may or may not | |
44 # provide us with the original name. If not, create | |
45 # *a* valid tagName from the current context. | |
46 if tagName is None: | |
47 tagName = self._current_context[uri] + ":" + localname | |
48 node = self.document.createElementNS(uri, tagName) | |
49 else: | |
50 # When the tagname is not prefixed, it just appears as | |
51 # localname | |
52 node = self.document.createElement(localname) | |
53 for aname,value in attrs.items(): | |
54 a_uri, a_localname = aname | |
55 if a_uri: | |
56 qname = self._current_context[a_uri] + ":" + a_localname | |
57 attr = self.document.createAttributeNS(a_uri, qname) | |
58 else: | |
59 attr = self.document.createAttribute(a_localname) | |
60 attr.value = value | |
61 node.setAttributeNode(attr) | |
62 parent = self.curNode | |
63 node.parentNode = parent | |
64 self.curNode = node | |
65 self.lastEvent[1] = [(START_ELEMENT, node), None] | |
66 self.lastEvent = self.lastEvent[1] | |
67 #self.events.append((START_ELEMENT, node)) | |
68 | |
69 def endElementNS(self, name, tagName): | |
70 node = self.curNode | |
71 self.lastEvent[1] = [(END_ELEMENT, node), None] | |
72 self.lastEvent = self.lastEvent[1] | |
73 #self.events.append((END_ELEMENT, node)) | |
74 self.curNode = node.parentNode | |
75 | |
76 def startElement(self, name, attrs): | |
77 node = self.document.createElement(name) | |
78 for aname,value in attrs.items(): | |
79 attr = self.document.createAttribute(aname) | |
80 attr.value = value | |
81 node.setAttributeNode(attr) | |
82 parent = self.curNode | |
83 node.parentNode = parent | |
84 self.curNode = node | |
85 self.lastEvent[1] = [(START_ELEMENT, node), None] | |
86 self.lastEvent = self.lastEvent[1] | |
87 #self.events.append((START_ELEMENT, node)) | |
88 | |
89 def endElement(self, name): | |
90 node = self.curNode | |
91 self.lastEvent[1] = [(END_ELEMENT, node), None] | |
92 self.lastEvent = self.lastEvent[1] | |
93 #self.events.append((END_ELEMENT, node)) | |
94 self.curNode = node.parentNode | |
95 | |
96 def comment(self, s): | |
97 node = self.document.createComment(s) | |
98 parent = self.curNode | |
99 node.parentNode = parent | |
100 self.lastEvent[1] = [(COMMENT, node), None] | |
101 self.lastEvent = self.lastEvent[1] | |
102 #self.events.append((COMMENT, node)) | |
103 | |
104 def processingInstruction(self, target, data): | |
105 node = self.document.createProcessingInstruction(target, data) | |
106 parent = self.curNode | |
107 node.parentNode = parent | |
108 self.lastEvent[1] = [(PROCESSING_INSTRUCTION, node), None] | |
109 self.lastEvent = self.lastEvent[1] | |
110 #self.events.append((PROCESSING_INSTRUCTION, node)) | |
111 | |
112 def ignorableWhitespace(self, chars): | |
113 node = self.document.createTextNode(chars[start:start + length]) | |
114 parent = self.curNode | |
115 node.parentNode = parent | |
116 self.lastEvent[1] = [(IGNORABLE_WHITESPACE, node), None] | |
117 self.lastEvent = self.lastEvent[1] | |
118 #self.events.append((IGNORABLE_WHITESPACE, node)) | |
119 | |
120 def characters(self, chars): | |
121 node = self.document.createTextNode(chars) | |
122 parent = self.curNode | |
123 node.parentNode = parent | |
124 self.lastEvent[1] = [(CHARACTERS, node), None] | |
125 self.lastEvent = self.lastEvent[1] | |
126 | |
127 def startDocument(self): | |
128 node = self.curNode = self.document = minidom.Document() | |
129 node.parentNode = None | |
130 self.lastEvent[1] = [(START_DOCUMENT, node), None] | |
131 self.lastEvent = self.lastEvent[1] | |
132 #self.events.append((START_DOCUMENT, node)) | |
133 | |
134 def endDocument(self): | |
135 assert not self.curNode.parentNode | |
136 for node in self.curNode.childNodes: | |
137 if node.nodeType == node.ELEMENT_NODE: | |
138 self.document.documentElement = node | |
139 #if not self.document.documentElement: | |
140 # raise Error, "No document element" | |
141 self.lastEvent[1] = [(END_DOCUMENT, node), None] | |
142 #self.events.append((END_DOCUMENT, self.curNode)) | |
143 | |
144 class ErrorHandler: | |
145 def warning(self, exception): | |
146 print exception | |
147 def error(self, exception): | |
148 raise exception | |
149 def fatalError(self, exception): | |
150 raise exception | |
151 | |
152 class DOMEventStream: | |
153 def __init__(self, stream, parser, bufsize): | |
154 self.stream = stream | |
155 self.parser = parser | |
156 self.bufsize = bufsize | |
157 self.reset() | |
158 | |
159 def reset(self): | |
160 self.pulldom = PullDOM() | |
161 # This content handler relies on namespace support | |
162 self.parser.setFeature(xml.sax.handler.feature_namespaces,1) | |
163 self.parser.setContentHandler(self.pulldom) | |
164 | |
165 def __getitem__(self, pos): | |
166 rc = self.getEvent() | |
167 if rc: | |
168 return rc | |
169 raise IndexError | |
170 | |
171 def expandNode(self, node): | |
172 event = self.getEvent() | |
173 while event: | |
174 token, cur_node = event | |
175 if cur_node is node: | |
176 return | |
177 if token != END_ELEMENT: | |
178 cur_node.parentNode.appendChild(cur_node) | |
179 event = self.getEvent() | |
180 | |
181 def getEvent(self): | |
182 if not self.pulldom.firstEvent[1]: | |
183 self.pulldom.lastEvent = self.pulldom.firstEvent | |
184 while not self.pulldom.firstEvent[1]: | |
185 buf=self.stream.read(self.bufsize) | |
186 if not buf: | |
187 #FIXME: why doesn't Expat close work? | |
188 #self.parser.close() | |
189 return None | |
190 self.parser.feed(buf) | |
191 rc = self.pulldom.firstEvent[1][0] | |
192 self.pulldom.firstEvent[1] = self.pulldom.firstEvent[1][1] | |
193 return rc | |
194 | |
195 class SAX2DOM(PullDOM): | |
196 | |
197 def startElementNS(self, name, tagName , attrs): | |
198 PullDOM.startElementNS(self, name, tagName, attrs) | |
199 self.curNode.parentNode.appendChild(self.curNode) | |
200 | |
201 def startElement(self, name, attrs): | |
202 PullDOM.startElement(self, name, attrs) | |
203 self.curNode.parentNode.appendChild(self.curNode) | |
204 | |
205 def processingInstruction(self, target, data): | |
206 PullDOM.processingInstruction(self, target, data) | |
207 node = self.lastEvent[0][1] | |
208 node.parentNode.appendChild(node) | |
209 | |
210 def ignorableWhitespace(self, chars): | |
211 PullDOM.ignorableWhitespace(self, chars) | |
212 node = self.lastEvent[0][1] | |
213 node.parentNode.appendChild(node) | |
214 | |
215 def characters(self, chars): | |
216 PullDOM.characters(self, chars) | |
217 node = self.lastEvent[0][1] | |
218 node.parentNode.appendChild(node) | |
219 | |
220 default_bufsize = (2 ** 14) - 20 | |
221 | |
222 def parse(stream_or_string, parser=None, bufsize=default_bufsize): | |
223 if type(stream_or_string) in _StringTypes: | |
224 stream = open(stream_or_string) | |
225 else: | |
226 stream = stream_or_string | |
227 if not parser: | |
228 parser = xml.sax.make_parser() | |
229 return DOMEventStream(stream, parser, bufsize) | |
230 | |
231 def parseString(string, parser=None): | |
232 bufsize = len(string) | |
233 buf = StringIO(string) | |
234 if not parser: | |
235 parser = xml.sax.make_parser() | |
236 return DOMEventStream(buf, parser, bufsize) |