initial commit
[ebuildfind.git] / commands / lib / layman / utils.py
blob178ad110d1f888270849cf01315690ab95921046
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 #################################################################################
4 # POLYMERAZE XML UTILITIES
5 #################################################################################
6 # File: xml.py
8 # Utilities to deal with xml nodes.
10 # Copyright:
11 # (c) 2005 - 2008 Gunnar Wrobel
12 # Distributed under the terms of the GNU General Public License v2
14 # Author(s):
15 # Gunnar Wrobel <wrobel@gentoo.org>
18 '''Utility functions to deal with xml nodes. '''
20 __version__ = '$Id: utils.py 236 2006-09-05 20:39:37Z wrobel $'
22 #===============================================================================
24 # Dependencies
26 #-------------------------------------------------------------------------------
28 import types, re
30 #===============================================================================
32 # Helper functions
34 #-------------------------------------------------------------------------------
36 def node_to_text(node):
37 '''
38 Reduces an xml node to its text elements. The function does not
39 collect the text nodes recursively.
41 >>> import xml.dom.minidom
42 >>> imp = xml.dom.minidom.getDOMImplementation()
43 >>> doc = imp.createDocument('test', 'root', None)
44 >>> root = doc.childNodes[0]
45 >>> node = doc.createTextNode('text')
46 >>> a = root.appendChild(node)
47 >>> node = doc.createElement('text')
48 >>> node2 = doc.createTextNode('text')
49 >>> a = node.appendChild(node2)
50 >>> a = root.appendChild(node)
51 >>> node = doc.createTextNode('text')
52 >>> a = root.appendChild(node)
53 >>> doc.toprettyxml('', '') #doctest: +ELLIPSIS
54 '<?xml version="1.0" ?>...<root>text<text>text</text>text</root>'
56 >>> node_to_text(root)
57 'texttext'
59 '''
60 text = ''
62 for child in node.childNodes:
63 if child.nodeType == child.TEXT_NODE:
64 text = text + child.data
66 return text
68 def node_to_dict(node):
69 ''' Converts a xml node to a dictionary. The function collects the
70 nodes recursively. Attributes will be prepended with '&', child
71 nodes will be surrounded with tags. An index will be appended
72 since several child nodes with the same tag may exist. Text
73 elements will be collapsed and stored in a n entry prepended with
74 '@'. Comments will be ignored.
76 >>> import xml.dom.minidom
77 >>> imp = xml.dom.minidom.getDOMImplementation()
78 >>> doc = imp.createDocument('test', 'root', None)
79 >>> root = doc.childNodes[0]
80 >>> node = doc.createTextNode('text')
81 >>> a = root.appendChild(node)
82 >>> node = doc.createElement('text')
83 >>> node2 = doc.createTextNode('text')
84 >>> comm = doc.createComment('comment')
85 >>> attr = doc.createAttribute('&attr')
86 >>> a = node.appendChild(node2)
87 >>> a = root.appendChild(comm)
88 >>> node.setAttributeNode(attr)
89 >>> node.setAttribute('&attr','test')
90 >>> a = root.appendChild(node)
91 >>> node3 = doc.createElement('text')
92 >>> a = root.appendChild(node3)
93 >>> node = doc.createTextNode('text')
94 >>> a = root.appendChild(node)
95 >>> doc.toprettyxml('', '') #doctest: +ELLIPSIS
96 '<?xml version="1.0" ?>...<root>text<!--comment--><text &attr="test">text</text><text/>text</root>'
98 >>> node_to_dict(root)
99 {'<text>1': {'@': 'text', '&&attr': 'test'}, '<text>2': {'@': ''}, '@': 'texttext'}
102 result = {}
104 # Map the attributes
105 for index in range(0, node.attributes.length):
106 attr = node.attributes.item(index)
107 result['&' + attr.name] = attr.nodeValue
109 text = ''
111 # Map the nodes
112 for child in node.childNodes:
113 if child.nodeType == child.TEXT_NODE:
114 text = text + child.data
115 if child.nodeType == child.ELEMENT_NODE:
116 index = 1
117 while ('<' + child.tagName + '>' + str(index)) in result.keys():
118 index += 1
119 result['<' + child.tagName + '>' + str(index)] = node_to_dict(child)
121 result['@'] = text
123 return result
125 def dict_to_node(data, document, root_name):
126 ''' Reverts the node_to_dict operation.
128 >>> import xml.dom.minidom
129 >>> imp = xml.dom.minidom.getDOMImplementation()
130 >>> doc = imp.createDocument('test', 'root', None)
131 >>> a = {'<text>1': {'@': 'text', '&&attr': 'test'}, '<text>2': {'@': ''}, '@': 'texttext'}
132 >>> doc.childNodes[0] = dict_to_node(a, doc, 'root')
133 >>> doc.toprettyxml('', '') #doctest: +ELLIPSIS
134 '<?xml version="1.0" ?>...<root><text &attr="test">text</text><text></text>texttext</root>'
137 node = document.createElement(root_name)
139 for i, j in data.items():
141 if i[0] == '&':
142 attr = document.createAttribute(i[1:])
143 node.setAttributeNode(attr)
144 node.setAttribute(i[1:], j)
145 if i[0] == '<':
146 k = i[1:]
147 while k[-1] in '0123456789':
148 k = k[:-1]
149 child = dict_to_node(data[i],
150 document,
151 k[:-1])
152 node.appendChild(child)
153 if i[0] == '@':
154 child = document.createTextNode(j)
155 node.appendChild(child)
157 return node
159 def path(path_elements):
161 Concatenate a path from several elements.
163 >>> path([])
165 >>> path(['a'])
167 >>> path(['a','b'])
168 'a/b'
169 >>> path(['a/','b'])
170 'a/b'
171 >>> path(['/a/','b'])
172 '/a/b'
173 >>> path(['/a/','b/'])
174 '/a/b'
175 >>> path(['/a/','b/'])
176 '/a/b'
177 >>> path(['/a/','/b/'])
178 '/a/b'
179 >>> path(['/a/','/b','c/'])
180 '/a/b/c'
182 pathname = ''
184 if type(path_elements) in types.StringTypes:
185 path_elements = [path_elements]
187 # Concatenate elements and seperate with /
188 for i in path_elements:
189 pathname += i + '/'
191 # Replace multiple consecutive slashes
192 pathname = re.compile('/+').sub('/', pathname)
194 # Remove the final / if there is one
195 if pathname and pathname[-1] == '/':
196 pathname = pathname[:-1]
198 return pathname
200 #===============================================================================
202 # Testing
204 #-------------------------------------------------------------------------------
206 if __name__ == '__main__':
207 import doctest, sys
208 doctest.testmod(sys.modules[__name__])