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
18
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
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
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
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
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
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
100
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
141
142
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:
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:
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
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