source: TI12-security/trunk/ndg_saml/ndg/soap/utils/etree.py @ 7560

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/ndg_saml/ndg/soap/utils/etree.py@7560
Revision 7560, 6.5 KB checked in by pjkersha, 9 years ago (diff)

Merged ndg.soap back into ndg_saml package - simpler to keep it together.

Line 
1"""ElementTree Utilities package for NDG SOAP Package
2
3NERC 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 $'
11try: # python 2.5
12    from xml.etree import ElementTree
13except ImportError:
14    # if you've installed it yourself it comes this way
15    import ElementTree
16
17import re
18
19
20class QName(ElementTree.QName):
21    """XML Qualified Name for ElementTree
22   
23    Extends ElementTree implementation for improved attribute access support
24    """ 
25    # ElementTree tag is of the form {namespace}localPart.  getNs extracts the
26    # namespace from within the brackets but if not found returns ''
27    getNs = staticmethod(lambda tag: getattr(re.search('(?<=\{).+(?=\})', tag),
28                                             'group', 
29                                             str)())
30                                             
31    getLocalPart = staticmethod(lambda tag: tag.rsplit('}', 1)[-1])
32   
33    def __init__(self, namespaceURI, tag=None, prefix=None):
34        """Initialise a qualified name
35       
36        @param namespaceURI: element namespace URI
37        @type namespaceURI: basestring
38        @param tag: element local name
39        @type tag: basestring
40        @param prefix: XML namespace prefix
41        @type prefix: basestring
42        """
43        ElementTree.QName.__init__(self, namespaceURI, tag=tag)
44       
45        if tag:
46            self.namespaceURI = namespaceURI
47            self.localPart = tag
48        else:
49            self.namespaceURI = QName.getNs(namespaceURI)
50            self.localPart = QName.getLocalPart(namespaceURI)
51           
52        self.prefix = prefix
53
54    def __eq__(self, qname):
55        """Enable equality check for QName
56        @type qname: ndg.security.common.utils.etree.QName
57        @param qname: Qualified Name to compare with self
58        @return: True if names are equal
59        @rtype: bool
60        """
61        if not isinstance(qname, QName):
62            raise TypeError('Expecting %r; got %r' % (QName, type(qname)))
63                           
64        return (self.prefix, self.namespaceURI, self.localPart) == \
65               (qname.prefix, qname.namespaceURI, qname.localPart)
66
67    def __ne__(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 not equal
72        @rtype: bool
73        """
74        return not self.__eq__(qname)
75               
76    def _getPrefix(self):
77        return self.__prefix
78
79    def _setPrefix(self, value):
80        self.__prefix = value
81   
82    prefix = property(_getPrefix, _setPrefix, None, "Prefix")
83
84    def _getLocalPart(self):
85        return self.__localPart
86   
87    def _setLocalPart(self, value):
88        self.__localPart = value
89       
90    localPart = property(_getLocalPart, _setLocalPart, None, "LocalPart")
91
92    def _getNamespaceURI(self):
93        return self.__namespaceURI
94
95    def _setNamespaceURI(self, value):
96        self.__namespaceURI = value
97 
98    namespaceURI = property(_getNamespaceURI, _setNamespaceURI, None, 
99                            "Namespace URI'")
100
101
102def prettyPrint(*arg, **kw):
103    '''Lightweight pretty printing of ElementTree elements'''
104   
105    # Keep track of namespace declarations made so they're not repeated
106    declaredNss = []
107   
108    _prettyPrint = _PrettyPrint(declaredNss)
109    return _prettyPrint(*arg, **kw)
110
111
112class _PrettyPrint(object):
113    def __init__(self, declaredNss):
114        self.declaredNss = declaredNss
115   
116    @staticmethod
117    def estrip(elem):
118        ''' Just want to get rid of unwanted whitespace '''
119        if elem is None:
120            return ''
121        else:
122            # just in case the elem is another simple type - e.g. int -
123            # wrapper it as a string
124            return str(elem).strip()
125       
126    def __call__(self, elem, indent='', html=0, space=' '*4):
127        '''Most of the work done in this wrapped function - wrapped so that
128        state can be maintained for declared namespace declarations during
129        recursive calls using "declaredNss" above''' 
130        strAttribs = []
131        for attr, attrVal in elem.attrib.items():
132            nsDeclaration = ''
133           
134            attrNamespace = QName.getNs(attr)
135            if attrNamespace:
136                nsPrefix = ElementTree._namespace_map.get(attrNamespace)
137                if nsPrefix is None:
138                    raise KeyError('prettyPrint: missing namespace "%s" for ' 
139                                   'ElementTree._namespace_map'%attrNamespace)
140               
141                attr = "%s:%s" % (nsPrefix, QName.getLocalPart(attr))
142               
143                if attrNamespace not in self.declaredNss:
144                    nsDeclaration = ' xmlns:%s="%s"' % (nsPrefix,attrNamespace)
145                    self.declaredNss.append(attrNamespace)
146               
147            strAttribs.append('%s %s="%s"' % (nsDeclaration, attr, attrVal))
148           
149        strAttrib = ''.join(strAttribs)
150       
151        namespace = QName.getNs(elem.tag)
152        nsPrefix = ElementTree._namespace_map.get(namespace)
153        if nsPrefix is None:
154            raise KeyError('prettyPrint: missing namespace "%s" for ' 
155                           'ElementTree._namespace_map' % namespace)
156           
157        tag = "%s:%s" % (nsPrefix, QName.getLocalPart(elem.tag))
158       
159        # Put in namespace declaration if one doesn't already exist
160        # FIXME: namespace declaration handling is wrong for handling child
161        # element scope
162        if namespace in self.declaredNss:
163            nsDeclaration = ''
164        else:
165            nsDeclaration = ' xmlns:%s="%s"' % (nsPrefix, namespace)
166            self.declaredNss.append(namespace)
167           
168        result = '%s<%s%s%s>%s' % (indent, tag, nsDeclaration, strAttrib, 
169                                   _PrettyPrint.estrip(elem.text))
170       
171        children = len(elem)
172        if children:
173            for child in elem:
174                declaredNss = self.declaredNss[:]
175                _prettyPrint = _PrettyPrint(declaredNss)
176                result += '\n'+ _prettyPrint(child, indent=indent+space) 
177               
178            result += '\n%s%s</%s>' % (indent,
179                                     _PrettyPrint.estrip(child.tail),
180                                     tag)
181        else:
182            result += '</%s>' % tag
183           
184        return result
185
Note: See TracBrowser for help on using the repository browser.