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

Source Code for Module ndg.xacml.utils.etree

  1  """ElementTree Utilities package for NDG Security 
  2   
  3  NERC DataGrid 
  4  """ 
  5  __author__ = "P J Kershaw" 
  6  __date__ = "02/04/09" 
  7  __copyright__ = "" 
  8  __license__ = "BSD - see LICENSE file in top-level directory" 
  9  __contact__ = "Philip.Kershaw@stfc.ac.uk" 
 10  __revision__ = '$Id: etree.py 8010 2012-01-30 16:24:06Z rwilkinson $' 
 11   
 12  from ndg.xacml import Config, importElementTree 
 13  ElementTree = importElementTree() 
 14   
 15  from ndg.xacml.parsers.etree import QName 
 16   
 17  # Fred Lundh's customisation for C14N functionality - egg available from 
 18  # http://ndg.nerc.ac.uk/dist site 
 19  c14nWarning = ("Custom ElementC14N package is not installed, canonicalize " 
 20                 "function is disabled") 
 21  try: 
 22      from elementtree import ElementC14N 
 23      elementC14nNotInstalled = False 
 24  except ImportError: 
 25      elementC14nNotInstalled = True 
 26      import warnings 
 27      warnings.warn(c14nWarning) 
 28       
 29  from cStringIO import StringIO 
30 31 32 -def canonicalize(elem, **kw):
33 '''ElementTree based Canonicalization - See ElementC14N for keyword 34 info. Also useful for pretty printing XML 35 @type elem: ElementTree.Element 36 @param elem: element to be canonicalized 37 @rtype: basestring 38 @return: canonicalised output 39 ''' 40 if elementC14nNotInstalled: 41 raise NotImplementedError(c14nWarning) 42 43 f = StringIO() 44 ElementC14N.write(ElementC14N.build_scoped_tree(elem), f, **kw) 45 return f.getvalue()
46
47 48 -def prettyPrint(*arg, **kw):
49 '''Lightweight pretty printing of ElementTree elements. This function 50 wraps the PrettyPrint class 51 52 @param arg: arguments to pretty print function 53 @type arg: tuple 54 @param kw: keyword arguments to pretty print function 55 @type kw: dict 56 ''' 57 58 # Keep track of namespace declarations made so they're not repeated 59 declaredNss = [] 60 if not Config.use_lxml: 61 mappedPrefixes = dict.fromkeys(ElementTree._namespace_map.values(), True) 62 namespace_map_backup = ElementTree._namespace_map.copy() 63 else: 64 mappedPrefixes = {} 65 66 _prettyPrint = _PrettyPrint(declaredNss, mappedPrefixes) 67 result = _prettyPrint(*arg, **kw) 68 69 if not Config.use_lxml: 70 ElementTree._namespace_map = namespace_map_backup 71 72 return result
73
74 75 -class _PrettyPrint(object):
76 '''Class for lightweight pretty printing of ElementTree elements''' 77 MAX_NS_TRIES = 256
78 - def __init__(self, declaredNss, mappedPrefixes):
79 """ 80 @param declaredNss: declared namespaces 81 @type declaredNss: iterable of string elements 82 @param mappedPrefixes: map of namespace URIs to prefixes 83 @type mappedPrefixes: map of string to string 84 """ 85 self.declaredNss = declaredNss 86 self.mappedPrefixes = mappedPrefixes
87 88 @staticmethod
89 - def estrip(elem):
90 '''Utility to remove unwanted leading and trailing whitespace 91 92 @param elem: ElementTree element 93 @type elem: ElementTree.Element 94 @return: element content with whitespace removed 95 @rtype: basestring''' 96 if elem is None: 97 return '' 98 else: 99 # just in case the elem is another simple type - e.g. int - 100 # wrapper it as a string 101 return str(elem).strip()
102
103 - def __call__(self, elem, indent='', html=0, space=' '*4):
104 '''Most of the work done in this wrapped function - wrapped so that 105 state can be maintained for declared namespace declarations during 106 recursive calls using "declaredNss" above 107 108 @param elem: ElementTree element 109 @type elem: ElementTree.Element 110 @param indent: set indent for output 111 @type indent: basestring 112 @param space: set output spacing 113 @type space: basestring 114 @return: pretty print format for doc 115 @rtype: basestring 116 ''' 117 strAttribs = [] 118 for attr, attrVal in elem.attrib.items(): 119 nsDeclaration = '' 120 121 attrNamespace = QName.getNs(attr) 122 if attrNamespace: 123 nsPrefix = self._getNamespacePrefix(elem, attrNamespace) 124 125 attr = "%s:%s" % (nsPrefix, QName.getLocalPart(attr)) 126 127 if attrNamespace not in self.declaredNss: 128 nsDeclaration = ' xmlns:%s="%s"' % (nsPrefix,attrNamespace) 129 self.declaredNss.append(attrNamespace) 130 131 strAttribs.append('%s %s="%s"' % (nsDeclaration, attr, attrVal)) 132 133 strAttrib = ''.join(strAttribs) 134 135 namespace = QName.getNs(elem.tag) 136 nsPrefix = self._getNamespacePrefix(elem, namespace) 137 138 tag = "%s:%s" % (nsPrefix, QName.getLocalPart(elem.tag)) 139 140 # Put in namespace declaration if one doesn't already exist 141 # FIXME: namespace declaration handling is wrong for handling child 142 # element scope 143 if namespace in self.declaredNss: 144 nsDeclaration = '' 145 else: 146 nsDeclaration = ' xmlns:%s="%s"' % (nsPrefix, namespace) 147 self.declaredNss.append(namespace) 148 149 result = '%s<%s%s%s>%s' % (indent, tag, nsDeclaration, strAttrib, 150 _PrettyPrint.estrip(elem.text)) 151 152 children = len(elem) 153 if children: 154 for child in elem: 155 declaredNss = self.declaredNss[:] 156 _prettyPrint = _PrettyPrint(declaredNss, self.mappedPrefixes) 157 result += '\n'+ _prettyPrint(child, indent=indent+space) 158 159 result += '\n%s%s</%s>' % (indent, 160 _PrettyPrint.estrip(child.tail), 161 tag) 162 else: 163 result += '</%s>' % tag 164 165 return result
166 167 if Config.use_lxml:
168 - def _getNamespacePrefix(self, elem, namespace):
169 for nsPrefix, ns in elem.nsmap.iteritems(): 170 if ns == namespace: 171 return nsPrefix 172 raise KeyError('prettyPrint: missing namespace "%s" for ' 173 'elem.nsmap' % namespace)
174 else:
175 - def _getNamespacePrefix(self, elem, namespace):
176 nsPrefix = self._allocNsPrefix(namespace) 177 if nsPrefix is None: 178 raise KeyError('prettyPrint: missing namespace "%s" for ' 179 'ElementTree._namespace_map' % namespace) 180 return nsPrefix
181
182 - def _allocNsPrefix(self, nsURI):
183 """Allocate a namespace prefix if one is not already set for the given 184 Namespace URI 185 """ 186 nsPrefix = ElementTree._namespace_map.get(nsURI) 187 if nsPrefix is not None: 188 return nsPrefix 189 190 for i in range(self.__class__.MAX_NS_TRIES): 191 nsPrefix = "ns%d" % i 192 if nsPrefix not in self.mappedPrefixes: 193 ElementTree._namespace_map[nsURI] = nsPrefix 194 self.mappedPrefixes[nsPrefix] = True 195 break 196 197 if nsURI not in ElementTree._namespace_map: 198 raise KeyError('prettyPrint: error adding namespace ' 199 '"%s" to ElementTree._namespace_map' % 200 nsURI) 201 202 return nsPrefix
203