Package ndg :: Package soap :: Package utils :: Module etree
[hide private]

Source Code for Module ndg.soap.utils.etree

  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: 
18 - def makeEtreeElement(tag, ns_prefix, ns_uri, attrib={}, **extra):
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:
25 - def makeEtreeElement(tag, ns_prefix, ns_uri, attrib={}, **extra):
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 # ElementTree tag is of the form {namespace}localPart. getNs extracts the 39 # namespace from within the brackets but if not found returns '' 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):
47 """Initialise a qualified name 48 49 @param namespaceURI: element namespace URI 50 @type namespaceURI: basestring 51 @param tag: element local name 52 @type tag: basestring 53 @param prefix: XML namespace prefix 54 @type prefix: basestring 55 """ 56 ElementTree.QName.__init__(self, namespaceURI, tag=tag) 57 58 if tag: 59 self.namespaceURI = namespaceURI 60 self.localPart = tag 61 else: 62 self.namespaceURI = QName.getNs(namespaceURI) 63 self.localPart = QName.getLocalPart(namespaceURI) 64 65 self.prefix = prefix
66
67 - def __eq__(self, qname):
68 """Enable equality check for QName 69 @type qname: ndg.security.common.utils.etree.QName 70 @param qname: Qualified Name to compare with self 71 @return: True if names are equal 72 @rtype: bool 73 """ 74 if not isinstance(qname, QName): 75 raise TypeError('Expecting %r; got %r' % (QName, type(qname))) 76 77 return (self.prefix, self.namespaceURI, self.localPart) == \ 78 (qname.prefix, qname.namespaceURI, qname.localPart)
79
80 - def __ne__(self, qname):
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
89 - def _getPrefix(self):
90 return self.__prefix
91
92 - def _setPrefix(self, value):
93 self.__prefix = value
94 95 prefix = property(_getPrefix, _setPrefix, None, "Prefix") 96
97 - def _getLocalPart(self):
98 return self.__localPart
99
100 - def _setLocalPart(self, value):
101 self.__localPart = value
102 103 localPart = property(_getLocalPart, _setLocalPart, None, "LocalPart") 104
105 - def _getNamespaceURI(self):
106 return self.__namespaceURI
107
108 - def _setNamespaceURI(self, value):
109 self.__namespaceURI = value
110 111 namespaceURI = property(_getNamespaceURI, _setNamespaceURI, None, 112 "Namespace URI'")
113
114 115 -def prettyPrint(*arg, **kw):
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 # Keep track of namespace declarations made so they're not repeated 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
141 142 -class _PrettyPrint(object):
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
156 - def estrip(elem):
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 # just in case the elem is another simple type - e.g. int - 167 # wrapper it as a string 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 # Put in namespace declaration if one doesn't already exist 208 # FIXME: namespace declaration handling is wrong for handling child 209 # element scope 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:
235 - def _getNamespacePrefix(self, elem, namespace):
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:
242 - def _getNamespacePrefix(self, elem, namespace):
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
249 - def _allocNsPrefix(self, nsURI):
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