OLD | NEW |
| (Empty) |
1 # -*- test-case-name: twisted.web.test.test_woven -*- | |
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
3 # See LICENSE for details. | |
4 | |
5 # | |
6 | |
7 from __future__ import nested_scopes | |
8 | |
9 from twisted.web import microdom | |
10 from microdom import getElementsByTagName, escape, unescape | |
11 | |
12 try: | |
13 import cStringIO as StringIO | |
14 except ImportError: | |
15 import StringIO | |
16 | |
17 class NodeLookupError(Exception): pass | |
18 | |
19 | |
20 def substitute(request, node, subs): | |
21 """ | |
22 Look through the given node's children for strings, and | |
23 attempt to do string substitution with the given parameter. | |
24 """ | |
25 for child in node.childNodes: | |
26 if hasattr(child, 'nodeValue') and child.nodeValue: | |
27 child.replaceData(0, len(child.nodeValue), child.nodeValue % subs) | |
28 substitute(request, child, subs) | |
29 | |
30 def _get(node, nodeId, nodeAttrs=('id','class','model','pattern')): | |
31 """ | |
32 (internal) Get a node with the specified C{nodeId} as any of the C{class}, | |
33 C{id} or C{pattern} attributes. | |
34 """ | |
35 | |
36 if hasattr(node, 'hasAttributes') and node.hasAttributes(): | |
37 for nodeAttr in nodeAttrs: | |
38 if (str (node.getAttribute(nodeAttr)) == nodeId): | |
39 return node | |
40 if node.hasChildNodes(): | |
41 if hasattr(node.childNodes, 'length'): | |
42 length = node.childNodes.length | |
43 else: | |
44 length = len(node.childNodes) | |
45 for childNum in range(length): | |
46 result = _get(node.childNodes[childNum], nodeId) | |
47 if result: return result | |
48 | |
49 def get(node, nodeId): | |
50 """ | |
51 Get a node with the specified C{nodeId} as any of the C{class}, | |
52 C{id} or C{pattern} attributes. If there is no such node, raise | |
53 L{NodeLookupError}. | |
54 """ | |
55 result = _get(node, nodeId) | |
56 if result: return result | |
57 raise NodeLookupError, nodeId | |
58 | |
59 def getIfExists(node, nodeId): | |
60 """ | |
61 Get a node with the specified C{nodeId} as any of the C{class}, | |
62 C{id} or C{pattern} attributes. If there is no such node, return | |
63 C{None}. | |
64 """ | |
65 return _get(node, nodeId) | |
66 | |
67 def getAndClear(node, nodeId): | |
68 """Get a node with the specified C{nodeId} as any of the C{class}, | |
69 C{id} or C{pattern} attributes. If there is no such node, raise | |
70 L{NodeLookupError}. Remove all child nodes before returning. | |
71 """ | |
72 result = get(node, nodeId) | |
73 if result: | |
74 clearNode(result) | |
75 return result | |
76 | |
77 def clearNode(node): | |
78 """ | |
79 Remove all children from the given node. | |
80 """ | |
81 node.childNodes[:] = [] | |
82 | |
83 def locateNodes(nodeList, key, value, noNesting=1): | |
84 """ | |
85 Find subnodes in the given node where the given attribute | |
86 has the given value. | |
87 """ | |
88 returnList = [] | |
89 if not isinstance(nodeList, type([])): | |
90 return locateNodes(nodeList.childNodes, key, value, noNesting) | |
91 for childNode in nodeList: | |
92 if not hasattr(childNode, 'getAttribute'): | |
93 continue | |
94 if str(childNode.getAttribute(key)) == value: | |
95 returnList.append(childNode) | |
96 if noNesting: | |
97 continue | |
98 returnList.extend(locateNodes(childNode, key, value, noNesting)) | |
99 return returnList | |
100 | |
101 def superSetAttribute(node, key, value): | |
102 if not hasattr(node, 'setAttribute'): return | |
103 node.setAttribute(key, value) | |
104 if node.hasChildNodes(): | |
105 for child in node.childNodes: | |
106 superSetAttribute(child, key, value) | |
107 | |
108 def superPrependAttribute(node, key, value): | |
109 if not hasattr(node, 'setAttribute'): return | |
110 old = node.getAttribute(key) | |
111 if old: | |
112 node.setAttribute(key, value+'/'+old) | |
113 else: | |
114 node.setAttribute(key, value) | |
115 if node.hasChildNodes(): | |
116 for child in node.childNodes: | |
117 superPrependAttribute(child, key, value) | |
118 | |
119 def superAppendAttribute(node, key, value): | |
120 if not hasattr(node, 'setAttribute'): return | |
121 old = node.getAttribute(key) | |
122 if old: | |
123 node.setAttribute(key, old + '/' + value) | |
124 else: | |
125 node.setAttribute(key, value) | |
126 if node.hasChildNodes(): | |
127 for child in node.childNodes: | |
128 superAppendAttribute(child, key, value) | |
129 | |
130 def gatherTextNodes(iNode, dounescape=0, joinWith=""): | |
131 """Visit each child node and collect its text data, if any, into a string. | |
132 For example:: | |
133 >>> doc=microdom.parseString('<a>1<b>2<c>3</c>4</b></a>') | |
134 >>> gatherTextNodes(doc.documentElement) | |
135 '1234' | |
136 With dounescape=1, also convert entities back into normal characters. | |
137 @return: the gathered nodes as a single string | |
138 @rtype: str | |
139 """ | |
140 gathered=[] | |
141 gathered_append=gathered.append | |
142 slice=[iNode] | |
143 while len(slice)>0: | |
144 c=slice.pop(0) | |
145 if hasattr(c, 'nodeValue') and c.nodeValue is not None: | |
146 if dounescape: | |
147 val=unescape(c.nodeValue) | |
148 else: | |
149 val=c.nodeValue | |
150 gathered_append(val) | |
151 slice[:0]=c.childNodes | |
152 return joinWith.join(gathered) | |
153 | |
154 class RawText(microdom.Text): | |
155 """This is an evil and horrible speed hack. Basically, if you have a big | |
156 chunk of XML that you want to insert into the DOM, but you don't want to | |
157 incur the cost of parsing it, you can construct one of these and insert it | |
158 into the DOM. This will most certainly only work with microdom as the API | |
159 for converting nodes to xml is different in every DOM implementation. | |
160 | |
161 This could be improved by making this class a Lazy parser, so if you | |
162 inserted this into the DOM and then later actually tried to mutate this | |
163 node, it would be parsed then. | |
164 """ | |
165 | |
166 def writexml(self, writer, indent="", addindent="", newl="", strip=0, nspref
ixes=None, namespace=None): | |
167 writer.write("%s%s%s" % (indent, self.data, newl)) | |
168 | |
169 def findNodes(parent, matcher, accum=None): | |
170 if accum is None: | |
171 accum = [] | |
172 if not parent.hasChildNodes(): | |
173 return accum | |
174 for child in parent.childNodes: | |
175 # print child, child.nodeType, child.nodeName | |
176 if matcher(child): | |
177 accum.append(child) | |
178 findNodes(child, matcher, accum) | |
179 return accum | |
180 | |
181 | |
182 def findNodesShallowOnMatch(parent, matcher, recurseMatcher, accum=None): | |
183 if accum is None: | |
184 accum = [] | |
185 if not parent.hasChildNodes(): | |
186 return accum | |
187 for child in parent.childNodes: | |
188 # print child, child.nodeType, child.nodeName | |
189 if matcher(child): | |
190 accum.append(child) | |
191 if recurseMatcher(child): | |
192 findNodesShallowOnMatch(child, matcher, recurseMatcher, accum) | |
193 return accum | |
194 | |
195 def findNodesShallow(parent, matcher, accum=None): | |
196 if accum is None: | |
197 accum = [] | |
198 if not parent.hasChildNodes(): | |
199 return accum | |
200 for child in parent.childNodes: | |
201 if matcher(child): | |
202 accum.append(child) | |
203 else: | |
204 findNodes(child, matcher, accum) | |
205 return accum | |
206 | |
207 | |
208 def findElementsWithAttributeShallow(parent, attribute): | |
209 return findNodesShallow(parent, | |
210 lambda n: isinstance(n, microdom.Element) and | |
211 n.hasAttribute(attribute)) | |
212 | |
213 | |
214 def findElements(parent, matcher): | |
215 return findNodes( | |
216 parent, | |
217 lambda n, matcher=matcher: isinstance(n, microdom.Element) and | |
218 matcher(n)) | |
219 | |
220 def findElementsWithAttribute(parent, attribute, value=None): | |
221 if value: | |
222 return findElements( | |
223 parent, | |
224 lambda n, attribute=attribute, value=value: | |
225 n.hasAttribute(attribute) and n.getAttribute(attribute) == value) | |
226 else: | |
227 return findElements( | |
228 parent, | |
229 lambda n, attribute=attribute: n.hasAttribute(attribute)) | |
230 | |
231 | |
232 def findNodesNamed(parent, name): | |
233 return findNodes(parent, lambda n, name=name: n.nodeName == name) | |
234 | |
235 | |
236 def writeNodeData(node, oldio): | |
237 for subnode in node.childNodes: | |
238 if hasattr(subnode, 'data'): | |
239 oldio.write(str(subnode.data)) | |
240 else: | |
241 writeNodeData(subnode, oldio) | |
242 | |
243 | |
244 def getNodeText(node): | |
245 oldio = StringIO.StringIO() | |
246 writeNodeData(node, oldio) | |
247 return oldio.getvalue() | |
248 | |
249 def getParents(node): | |
250 l = [] | |
251 while node: | |
252 l.append(node) | |
253 node = node.parentNode | |
254 return l | |
255 | |
256 def namedChildren(parent, nodeName): | |
257 """namedChildren(parent, nodeName) -> children (not descendants) of parent | |
258 that have tagName == nodeName | |
259 """ | |
260 return [n for n in parent.childNodes if getattr(n, 'tagName', '')==nodeName] | |
OLD | NEW |