Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / web / domhelpers.py
1 # -*- test-case-name: twisted.web.test.test_domhelpers -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 A library for performing interesting tasks with DOM objects.
7 """
8
9 import StringIO
10
11 from twisted.web import microdom
12 from twisted.web.microdom import getElementsByTagName, escape, unescape
13
14
15 class NodeLookupError(Exception):
16     pass
17
18
19 def substitute(request, node, subs):
20     """
21     Look through the given node's children for strings, and
22     attempt to do string substitution with the given parameter.
23     """
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)
28
29 def _get(node, nodeId, nodeAttrs=('id','class','model','pattern')):
30     """
31     (internal) Get a node with the specified C{nodeId} as any of the C{class},
32     C{id} or C{pattern} attributes.
33     """
34
35     if hasattr(node, 'hasAttributes') and node.hasAttributes():
36         for nodeAttr in nodeAttrs:
37             if (str (node.getAttribute(nodeAttr)) == nodeId):
38                 return node
39     if node.hasChildNodes():
40         if hasattr(node.childNodes, 'length'):
41             length = node.childNodes.length
42         else:
43             length = len(node.childNodes)
44         for childNum in range(length):
45             result = _get(node.childNodes[childNum], nodeId)
46             if result: return result
47
48 def get(node, nodeId):
49     """
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
52     L{NodeLookupError}.
53     """
54     result = _get(node, nodeId)
55     if result: return result
56     raise NodeLookupError, nodeId
57
58 def getIfExists(node, nodeId):
59     """
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
62     C{None}.
63     """
64     return _get(node, nodeId)
65
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.
70     """
71     result = get(node, nodeId)
72     if result:
73         clearNode(result)
74     return result
75
76 def clearNode(node):
77     """
78     Remove all children from the given node.
79     """
80     node.childNodes[:] = []
81
82 def locateNodes(nodeList, key, value, noNesting=1):
83     """
84     Find subnodes in the given node where the given attribute
85     has the given value.
86     """
87     returnList = []
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'):
92             continue
93         if str(childNode.getAttribute(key)) == value:
94             returnList.append(childNode)
95             if noNesting:
96                 continue
97         returnList.extend(locateNodes(childNode, key, value, noNesting))
98     return returnList
99
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)
106
107 def superPrependAttribute(node, key, value):
108     if not hasattr(node, 'setAttribute'): return
109     old = node.getAttribute(key)
110     if old:
111         node.setAttribute(key, value+'/'+old)
112     else:
113         node.setAttribute(key, value)
114     if node.hasChildNodes():
115         for child in node.childNodes:
116             superPrependAttribute(child, key, value)
117
118 def superAppendAttribute(node, key, value):
119     if not hasattr(node, 'setAttribute'): return
120     old = node.getAttribute(key)
121     if old:
122         node.setAttribute(key, old + '/' + value)
123     else:
124         node.setAttribute(key, value)
125     if node.hasChildNodes():
126         for child in node.childNodes:
127             superAppendAttribute(child, key, value)
128
129 def gatherTextNodes(iNode, dounescape=0, joinWith=""):
130     """Visit each child node and collect its text data, if any, into a string.
131 For example::
132     >>> doc=microdom.parseString('<a>1<b>2<c>3</c>4</b></a>')
133     >>> gatherTextNodes(doc.documentElement)
134     '1234'
135 With dounescape=1, also convert entities back into normal characters.
136 @return: the gathered nodes as a single string
137 @rtype: str
138 """
139     gathered=[]
140     gathered_append=gathered.append
141     slice=[iNode]
142     while len(slice)>0:
143         c=slice.pop(0)
144         if hasattr(c, 'nodeValue') and c.nodeValue is not None:
145             if dounescape:
146                 val=unescape(c.nodeValue)
147             else:
148                 val=c.nodeValue
149             gathered_append(val)
150         slice[:0]=c.childNodes
151     return joinWith.join(gathered)
152
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.
159
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.
163     """
164
165     def writexml(self, writer, indent="", addindent="", newl="", strip=0, nsprefixes=None, namespace=None):
166         writer.write("%s%s%s" % (indent, self.data, newl))
167
168 def findNodes(parent, matcher, accum=None):
169     if accum is None:
170         accum = []
171     if not parent.hasChildNodes():
172         return accum
173     for child in parent.childNodes:
174         # print child, child.nodeType, child.nodeName
175         if matcher(child):
176             accum.append(child)
177         findNodes(child, matcher, accum)
178     return accum
179
180
181 def findNodesShallowOnMatch(parent, matcher, recurseMatcher, accum=None):
182     if accum is None:
183         accum = []
184     if not parent.hasChildNodes():
185         return accum
186     for child in parent.childNodes:
187         # print child, child.nodeType, child.nodeName
188         if matcher(child):
189             accum.append(child)
190         if recurseMatcher(child):
191             findNodesShallowOnMatch(child, matcher, recurseMatcher, accum)
192     return accum
193
194 def findNodesShallow(parent, matcher, accum=None):
195     if accum is None:
196         accum = []
197     if not parent.hasChildNodes():
198         return accum
199     for child in parent.childNodes:
200         if matcher(child):
201             accum.append(child)
202         else:
203             findNodes(child, matcher, accum)
204     return accum
205
206
207 def findElementsWithAttributeShallow(parent, attribute):
208     """
209     Return an iterable of the elements which are direct children of C{parent}
210     and which have the C{attribute} attribute.
211     """
212     return findNodesShallow(parent,
213         lambda n: getattr(n, 'tagName', None) is not None and
214             n.hasAttribute(attribute))
215
216
217 def findElements(parent, matcher):
218     """
219     Return an iterable of the elements which are children of C{parent} for
220     which the predicate C{matcher} returns true.
221     """
222     return findNodes(
223         parent,
224         lambda n, matcher=matcher: getattr(n, 'tagName', None) is not None and
225                                    matcher(n))
226
227 def findElementsWithAttribute(parent, attribute, value=None):
228     if value:
229         return findElements(
230             parent,
231             lambda n, attribute=attribute, value=value:
232               n.hasAttribute(attribute) and n.getAttribute(attribute) == value)
233     else:
234         return findElements(
235             parent,
236             lambda n, attribute=attribute: n.hasAttribute(attribute))
237
238
239 def findNodesNamed(parent, name):
240     return findNodes(parent, lambda n, name=name: n.nodeName == name)
241
242
243 def writeNodeData(node, oldio):
244     for subnode in node.childNodes:
245         if hasattr(subnode, 'data'):
246             oldio.write(subnode.data)
247         else:
248             writeNodeData(subnode, oldio)
249
250
251 def getNodeText(node):
252     oldio = StringIO.StringIO()
253     writeNodeData(node, oldio)
254     return oldio.getvalue()
255
256
257 def getParents(node):
258     l = []
259     while node:
260         l.append(node)
261         node = node.parentNode
262     return l
263
264 def namedChildren(parent, nodeName):
265     """namedChildren(parent, nodeName) -> children (not descendants) of parent
266     that have tagName == nodeName
267     """
268     return [n for n in parent.childNodes if getattr(n, 'tagName', '')==nodeName]