1
# -*- test-case-name: twisted.web.test.test_domhelpers -*-
2
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
3
# See LICENSE for details.
6
A library for performing interesting tasks with DOM objects.
11
from twisted.web import microdom
12
from twisted.web.microdom import getElementsByTagName, escape, unescape
15
class NodeLookupError(Exception):
19
def substitute(request, node, subs):
21
Look through the given node's children for strings, and
22
attempt to do string substitution with the given parameter.
24
for child in node.childNodes:
25
if hasattr(child, 'nodeValue') and child.nodeValue:
26
child.replaceData(0, len(child.nodeValue), child.nodeValue % subs)
27
substitute(request, child, subs)
29
def _get(node, nodeId, nodeAttrs=('id','class','model','pattern')):
31
(internal) Get a node with the specified C{nodeId} as any of the C{class},
32
C{id} or C{pattern} attributes.
35
if hasattr(node, 'hasAttributes') and node.hasAttributes():
36
for nodeAttr in nodeAttrs:
37
if (str (node.getAttribute(nodeAttr)) == nodeId):
39
if node.hasChildNodes():
40
if hasattr(node.childNodes, 'length'):
41
length = node.childNodes.length
43
length = len(node.childNodes)
44
for childNum in range(length):
45
result = _get(node.childNodes[childNum], nodeId)
46
if result: return result
48
def get(node, nodeId):
50
Get a node with the specified C{nodeId} as any of the C{class},
51
C{id} or C{pattern} attributes. If there is no such node, raise
54
result = _get(node, nodeId)
55
if result: return result
56
raise NodeLookupError, nodeId
58
def getIfExists(node, nodeId):
60
Get a node with the specified C{nodeId} as any of the C{class},
61
C{id} or C{pattern} attributes. If there is no such node, return
64
return _get(node, nodeId)
66
def getAndClear(node, nodeId):
67
"""Get a node with the specified C{nodeId} as any of the C{class},
68
C{id} or C{pattern} attributes. If there is no such node, raise
69
L{NodeLookupError}. Remove all child nodes before returning.
71
result = get(node, nodeId)
78
Remove all children from the given node.
80
node.childNodes[:] = []
82
def locateNodes(nodeList, key, value, noNesting=1):
84
Find subnodes in the given node where the given attribute
88
if not isinstance(nodeList, type([])):
89
return locateNodes(nodeList.childNodes, key, value, noNesting)
90
for childNode in nodeList:
91
if not hasattr(childNode, 'getAttribute'):
93
if str(childNode.getAttribute(key)) == value:
94
returnList.append(childNode)
97
returnList.extend(locateNodes(childNode, key, value, noNesting))
100
def superSetAttribute(node, key, value):
101
if not hasattr(node, 'setAttribute'): return
102
node.setAttribute(key, value)
103
if node.hasChildNodes():
104
for child in node.childNodes:
105
superSetAttribute(child, key, value)
107
def superPrependAttribute(node, key, value):
108
if not hasattr(node, 'setAttribute'): return
109
old = node.getAttribute(key)
111
node.setAttribute(key, value+'/'+old)
113
node.setAttribute(key, value)
114
if node.hasChildNodes():
115
for child in node.childNodes:
116
superPrependAttribute(child, key, value)
118
def superAppendAttribute(node, key, value):
119
if not hasattr(node, 'setAttribute'): return
120
old = node.getAttribute(key)
122
node.setAttribute(key, old + '/' + value)
124
node.setAttribute(key, value)
125
if node.hasChildNodes():
126
for child in node.childNodes:
127
superAppendAttribute(child, key, value)
129
def gatherTextNodes(iNode, dounescape=0, joinWith=""):
130
"""Visit each child node and collect its text data, if any, into a string.
132
>>> doc=microdom.parseString('<a>1<b>2<c>3</c>4</b></a>')
133
>>> gatherTextNodes(doc.documentElement)
135
With dounescape=1, also convert entities back into normal characters.
136
@return: the gathered nodes as a single string
140
gathered_append=gathered.append
144
if hasattr(c, 'nodeValue') and c.nodeValue is not None:
146
val=unescape(c.nodeValue)
150
slice[:0]=c.childNodes
151
return joinWith.join(gathered)
153
class RawText(microdom.Text):
154
"""This is an evil and horrible speed hack. Basically, if you have a big
155
chunk of XML that you want to insert into the DOM, but you don't want to
156
incur the cost of parsing it, you can construct one of these and insert it
157
into the DOM. This will most certainly only work with microdom as the API
158
for converting nodes to xml is different in every DOM implementation.
160
This could be improved by making this class a Lazy parser, so if you
161
inserted this into the DOM and then later actually tried to mutate this
162
node, it would be parsed then.
165
def writexml(self, writer, indent="", addindent="", newl="", strip=0, nsprefixes=None, namespace=None):
166
writer.write("%s%s%s" % (indent, self.data, newl))
168
def findNodes(parent, matcher, accum=None):
171
if not parent.hasChildNodes():
173
for child in parent.childNodes:
174
# print child, child.nodeType, child.nodeName
177
findNodes(child, matcher, accum)
181
def findNodesShallowOnMatch(parent, matcher, recurseMatcher, accum=None):
184
if not parent.hasChildNodes():
186
for child in parent.childNodes:
187
# print child, child.nodeType, child.nodeName
190
if recurseMatcher(child):
191
findNodesShallowOnMatch(child, matcher, recurseMatcher, accum)
194
def findNodesShallow(parent, matcher, accum=None):
197
if not parent.hasChildNodes():
199
for child in parent.childNodes:
203
findNodes(child, matcher, accum)
207
def findElementsWithAttributeShallow(parent, attribute):
209
Return an iterable of the elements which are direct children of C{parent}
210
and which have the C{attribute} attribute.
212
return findNodesShallow(parent,
213
lambda n: getattr(n, 'tagName', None) is not None and
214
n.hasAttribute(attribute))
217
def findElements(parent, matcher):
219
Return an iterable of the elements which are children of C{parent} for
220
which the predicate C{matcher} returns true.
224
lambda n, matcher=matcher: getattr(n, 'tagName', None) is not None and
227
def findElementsWithAttribute(parent, attribute, value=None):
231
lambda n, attribute=attribute, value=value:
232
n.hasAttribute(attribute) and n.getAttribute(attribute) == value)
236
lambda n, attribute=attribute: n.hasAttribute(attribute))
239
def findNodesNamed(parent, name):
240
return findNodes(parent, lambda n, name=name: n.nodeName == name)
243
def writeNodeData(node, oldio):
244
for subnode in node.childNodes:
245
if hasattr(subnode, 'data'):
246
oldio.write(subnode.data)
248
writeNodeData(subnode, oldio)
251
def getNodeText(node):
252
oldio = StringIO.StringIO()
253
writeNodeData(node, oldio)
254
return oldio.getvalue()
257
def getParents(node):
261
node = node.parentNode
264
def namedChildren(parent, nodeName):
265
"""namedChildren(parent, nodeName) -> children (not descendants) of parent
266
that have tagName == nodeName
268
return [n for n in parent.childNodes if getattr(n, 'tagName', '')==nodeName]