1 """ElementTree Utilities package for NDG SOAP Package
2
3 NERC DataGrid Project
4 """
5 __author__ = "P J Kershaw"
6 __date__ = "02/04/09"
7 __copyright__ = "(C) 2010 Science and Technology Facilities Council"
8 __license__ = "http://www.apache.org/licenses/LICENSE-2.0"
9 __contact__ = "Philip.Kershaw@stfc.ac.uk"
10 __revision__ = '$Id: etree.py 7131 2010-06-30 13:37:48Z pjkersha $'
11 from ndg.saml import Config, importElementTree
12 ElementTree = importElementTree()
13
14 import re
15
16
17 if Config.use_lxml:
19 """Makes an ElementTree element handling namespaces in the way
20 appropriate for the ElementTree implementation in use.
21 """
22 elem = ElementTree.Element(tag, {ns_prefix: ns_uri}, attrib, **extra)
23 return elem
24 else:
26 """Makes an ElementTree element handling namespaces in the way
27 appropriate for the ElementTree implementation in use.
28 """
29 elem = ElementTree.Element(tag, attrib, **extra)
30 ElementTree._namespace_map[ns_uri] = ns_prefix
31 return elem
32
33 -class QName(ElementTree.QName):
34 """XML Qualified Name for ElementTree
35
36 Extends ElementTree implementation for improved attribute access support
37 """
38
39
40 getNs = staticmethod(lambda tag: getattr(re.search('(?<=\{).+(?=\})', tag),
41 'group',
42 str)())
43
44 getLocalPart = staticmethod(lambda tag: tag.rsplit('}', 1)[-1])
45
46 - def __init__(self, namespaceURI, tag=None, prefix=None):
66
79
81 """Enable equality check for QName
82 @type qname: ndg.security.common.utils.etree.QName
83 @param qname: Qualified Name to compare with self
84 @return: True if names are not equal
85 @rtype: bool
86 """
87 return not self.__eq__(qname)
88
91
94
95 prefix = property(_getPrefix, _setPrefix, None, "Prefix")
96
98 return self.__localPart
99
101 self.__localPart = value
102
103 localPart = property(_getLocalPart, _setLocalPart, None, "LocalPart")
104
106 return self.__namespaceURI
107
109 self.__namespaceURI = value
110
111 namespaceURI = property(_getNamespaceURI, _setNamespaceURI, None,
112 "Namespace URI'")
113
116 '''Lightweight pretty printing of ElementTree elements. This function
117 wraps the PrettyPrint class
118
119 @param arg: arguments to pretty print function
120 @type arg: tuple
121 @param kw: keyword arguments to pretty print function
122 @type kw: dict
123 '''
124
125
126 declaredNss = []
127 if not Config.use_lxml:
128 mappedPrefixes = dict.fromkeys(ElementTree._namespace_map.values(), True)
129 namespace_map_backup = ElementTree._namespace_map.copy()
130 else:
131 mappedPrefixes = {}
132
133 _prettyPrint = _PrettyPrint(declaredNss, mappedPrefixes)
134 result = _prettyPrint(*arg, **kw)
135
136 if not Config.use_lxml:
137 ElementTree._namespace_map = namespace_map_backup
138
139 return result
140
143 '''Class for lightweight pretty printing of ElementTree elements'''
144 MAX_NS_TRIES = 256
145 - def __init__(self, declaredNss, mappedPrefixes):
146 """
147 @param declaredNss: declared namespaces
148 @type declaredNss: iterable of string elements
149 @param mappedPrefixes: map of namespace URIs to prefixes
150 @type mappedPrefixes: map of string to string
151 """
152 self.declaredNss = declaredNss
153 self.mappedPrefixes = mappedPrefixes
154
155 @staticmethod
157 '''Utility to remove unwanted leading and trailing whitespace
158
159 @param elem: ElementTree element
160 @type elem: ElementTree.Element
161 @return: element content with whitespace removed
162 @rtype: basestring'''
163 if elem is None:
164 return ''
165 else:
166
167
168 return str(elem).strip()
169
170 - def __call__(self, elem, indent='', html=0, space=' '*4):
171 '''Most of the work done in this wrapped function - wrapped so that
172 state can be maintained for declared namespace declarations during
173 recursive calls using "declaredNss" above
174
175 @param elem: ElementTree element
176 @type elem: ElementTree.Element
177 @param indent: set indent for output
178 @type indent: basestring
179 @param space: set output spacing
180 @type space: basestring
181 @return: pretty print format for doc
182 @rtype: basestring
183 '''
184 strAttribs = []
185 for attr, attrVal in elem.attrib.items():
186 nsDeclaration = ''
187
188 attrNamespace = QName.getNs(attr)
189 if attrNamespace:
190 nsPrefix = self._getNamespacePrefix(elem, attrNamespace)
191
192 attr = "%s:%s" % (nsPrefix, QName.getLocalPart(attr))
193
194 if attrNamespace not in self.declaredNss:
195 nsDeclaration = ' xmlns:%s="%s"' % (nsPrefix,attrNamespace)
196 self.declaredNss.append(attrNamespace)
197
198 strAttribs.append('%s %s="%s"' % (nsDeclaration, attr, attrVal))
199
200 strAttrib = ''.join(strAttribs)
201
202 namespace = QName.getNs(elem.tag)
203 nsPrefix = self._getNamespacePrefix(elem, namespace)
204
205 tag = "%s:%s" % (nsPrefix, QName.getLocalPart(elem.tag))
206
207
208
209
210 if namespace in self.declaredNss:
211 nsDeclaration = ''
212 else:
213 nsDeclaration = ' xmlns:%s="%s"' % (nsPrefix, namespace)
214 self.declaredNss.append(namespace)
215
216 result = '%s<%s%s%s>%s' % (indent, tag, nsDeclaration, strAttrib,
217 _PrettyPrint.estrip(elem.text))
218
219 children = len(elem)
220 if children:
221 for child in elem:
222 declaredNss = self.declaredNss[:]
223 _prettyPrint = _PrettyPrint(declaredNss, self.mappedPrefixes)
224 result += '\n'+ _prettyPrint(child, indent=indent+space)
225
226 result += '\n%s%s</%s>' % (indent,
227 _PrettyPrint.estrip(child.tail),
228 tag)
229 else:
230 result += '</%s>' % tag
231
232 return result
233
234 if Config.use_lxml:
236 for nsPrefix, ns in elem.nsmap.iteritems():
237 if ns == namespace:
238 return nsPrefix
239 raise KeyError('prettyPrint: missing namespace "%s" for '
240 'elem.nsmap' % namespace)
241 else:
243 nsPrefix = self._allocNsPrefix(namespace)
244 if nsPrefix is None:
245 raise KeyError('prettyPrint: missing namespace "%s" for '
246 'ElementTree._namespace_map' % namespace)
247 return nsPrefix
248
250 """Allocate a namespace prefix if one is not already set for the given
251 Namespace URI
252 """
253 nsPrefix = ElementTree._namespace_map.get(nsURI)
254 if nsPrefix is not None:
255 return nsPrefix
256
257 for i in range(self.__class__.MAX_NS_TRIES):
258 nsPrefix = "ns%d" % i
259 if nsPrefix not in self.mappedPrefixes:
260 ElementTree._namespace_map[nsURI] = nsPrefix
261 self.mappedPrefixes[nsPrefix] = True
262 break
263
264 if nsURI not in ElementTree._namespace_map:
265 raise KeyError('prettyPrint: error adding namespace '
266 '"%s" to ElementTree._namespace_map' %
267 nsURI)
268
269 return nsPrefix
270