More encodign fixes, xml does not know how to encode \x00
[nepi.git] / src / nepi / util / parser / _xml.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from nepi.core.attributes import Attribute
5 from nepi.util.parser.base import ExperimentData, ExperimentParser
6 from xml.dom import minidom
7
8 import sys
9
10 def xmlencode(s):
11     if isinstance(s, str):
12         rv = s.decode("latin1")
13     elif not isinstance(s, unicode):
14         rv = unicode(s)
15     else:
16         rv = s
17     return rv.replace(u'\x00',u'�')
18
19 def xmldecode(s):
20     return s.replace(u'&#0000',u'\x00').encode("utf8")
21
22 class XmlExperimentParser(ExperimentParser):
23     def to_xml(self, experiment_description=None, data=None):
24         if experiment_description is not None:
25             data = self.to_data(experiment_description)
26         elif data is None:
27             raise TypeError, "XmlExperimentParser.to_xml needs either 'experiment_description' or 'data' arguments"
28         doc = minidom.Document()        
29         exp_tag = doc.createElement("experiment")
30         testbeds_tag = doc.createElement("testbeds")
31         exp_tag.appendChild(testbeds_tag)
32
33         elements_tags = dict()
34         for guid in sorted(data.guids):
35             if data.is_testbed_data(guid):
36                 elements_tag = self.testbed_data_to_xml(doc, testbeds_tag, guid, data)
37                 elements_tags[guid] = elements_tag
38             else:
39                 self.box_data_to_xml(doc, elements_tags, guid, data)
40         doc.appendChild(exp_tag)
41         
42         try:
43             xml = doc.toprettyxml(indent="    ", encoding="UTF-8")
44         except:
45             print >>sys.stderr, "Oops: generating XML from %s" % (data,)
46             raise
47         
48         return xml
49
50     def testbed_data_to_xml(self, doc, parent_tag, guid, data):
51         testbed_tag = doc.createElement("testbed") 
52         testbed_tag.setAttribute("guid", xmlencode(guid))
53         (testbed_id, testbed_version) = data.get_testbed_data(guid)
54         testbed_tag.setAttribute("testbed_id", xmlencode(testbed_id))
55         testbed_tag.setAttribute("testbed_version", xmlencode(testbed_version))
56         parent_tag.appendChild(testbed_tag)
57         self.graphical_info_data_to_xml(doc, testbed_tag, guid, data)
58         self.attributes_data_to_xml(doc, testbed_tag, guid, data)
59         elements_tag = doc.createElement("elements")
60         testbed_tag.appendChild(elements_tag)
61         return elements_tag
62
63     def box_data_to_xml(self, doc, elements_tags, guid, data):
64         (testbed_guid, factory_id) = data.get_box_data(guid)
65         element_tag = doc.createElement("element")
66         parent_tag = elements_tags[testbed_guid]
67         parent_tag.appendChild(element_tag)
68         element_tag.setAttribute("factory_id", factory_id)
69         element_tag.setAttribute("guid", xmlencode(guid))
70         self.graphical_info_data_to_xml(doc, element_tag, guid, data)
71         self.factory_attributes_data_to_xml(doc, element_tag, guid, data)
72         self.attributes_data_to_xml(doc, element_tag, guid, data)
73         self.traces_data_to_xml(doc, element_tag, guid, data)
74         self.addresses_data_to_xml(doc, element_tag, guid, data)
75         self.routes_data_to_xml(doc, element_tag, guid, data)
76         self.connections_data_to_xml(doc, element_tag, guid, data)
77
78     def graphical_info_data_to_xml(self, doc, parent_tag, guid, data):
79         graphical_info_tag = doc.createElement("graphical_info") 
80         parent_tag.appendChild(graphical_info_tag)
81         (x, y, width, height) = data.get_graphical_info_data(guid)
82         graphical_info_tag.setAttribute("x", xmlencode(x))
83         graphical_info_tag.setAttribute("y", xmlencode(y))
84         graphical_info_tag.setAttribute("width", xmlencode(width))
85         graphical_info_tag.setAttribute("height", xmlencode(height))
86
87     def factory_attributes_data_to_xml(self, doc, parent_tag, guid, data):
88         factory_attributes_tag = doc.createElement("factory_attributes")
89         for (name, value) in data.get_factory_attribute_data(guid):
90             if value is not None:
91                 factory_attribute_tag = doc.createElement("factory_attribute") 
92                 factory_attributes_tag.appendChild(factory_attribute_tag)
93                 factory_attribute_tag.setAttribute("name", name)
94                 factory_attribute_tag.setAttribute("value", xmlencode(value))
95                 factory_attribute_tag.setAttribute("type", self.type_to_standard(value))
96         if factory_attributes_tag.hasChildNodes():
97             parent_tag.appendChild(factory_attributes_tag)
98
99     def attributes_data_to_xml(self, doc, parent_tag, guid, data):
100         attributes_tag = doc.createElement("attributes") 
101         for name, value in data.get_attribute_data(guid):
102             if value is not None:
103                 attribute_tag = doc.createElement("attribute") 
104                 attributes_tag.appendChild(attribute_tag)
105                 attribute_tag.setAttribute("name", name)
106                 attribute_tag.setAttribute("value", xmlencode(value))
107                 attribute_tag.setAttribute("type", self.type_to_standard(value))
108         if attributes_tag.hasChildNodes():
109             parent_tag.appendChild(attributes_tag)
110
111     def traces_data_to_xml(self, doc, parent_tag, guid, data):
112         traces_tag = doc.createElement("traces") 
113         for name in data.get_trace_data(guid):
114             trace_tag = doc.createElement("trace") 
115             traces_tag.appendChild(trace_tag)
116             trace_tag.setAttribute("name", name)
117         if traces_tag.hasChildNodes():
118             parent_tag.appendChild(traces_tag)
119
120     def addresses_data_to_xml(self, doc, parent_tag, guid, data):
121         addresses_tag = doc.createElement("addresses") 
122         for (address, netprefix, broadcast) in data.get_address_data(guid):
123             address_tag = doc.createElement("address") 
124             addresses_tag.appendChild(address_tag)
125             if address:
126                 address_tag.setAttribute("Address", xmlencode(address))
127             address_tag.setAttribute("NetPrefix", xmlencode(netprefix))
128             if broadcast:
129                 address_tag.setAttribute("Broadcast", xmlencode(broadcast))
130         if addresses_tag.hasChildNodes():
131             parent_tag.appendChild(addresses_tag)
132
133     def routes_data_to_xml(self, doc, parent_tag, guid, data):
134         routes_tag = doc.createElement("routes") 
135         for (destination, netprefix, nexthop, metric) \
136                 in data.get_route_data(guid):
137             route_tag = doc.createElement("route") 
138             routes_tag.appendChild(route_tag)
139             route_tag.setAttribute("Destination", xmlencode(destination))
140             route_tag.setAttribute("NetPrefix", xmlencode(netprefix))
141             route_tag.setAttribute("NextHop", xmlencode(nexthop))
142             route_tag.setAttribute("Metric", xmlencode(metric))
143         if routes_tag.hasChildNodes():
144             parent_tag.appendChild(routes_tag)
145
146     def connections_data_to_xml(self, doc, parent_tag, guid, data):
147         connections_tag = doc.createElement("connections") 
148         for (connector_type_name, other_guid, other_connector_type_name) \
149                 in data.get_connection_data(guid):
150                 connection_tag = doc.createElement("connection") 
151                 connections_tag.appendChild(connection_tag)
152                 connection_tag.setAttribute("connector", connector_type_name)
153                 connection_tag.setAttribute("other_guid", xmlencode(other_guid))
154                 connection_tag.setAttribute("other_connector",
155                         other_connector_type_name)
156         if connections_tag.hasChildNodes():
157             parent_tag.appendChild(connections_tag)
158
159     def from_xml_to_data(self, xml):
160         data = ExperimentData()
161         doc = minidom.parseString(xml)
162         testbeds_tag = doc.getElementsByTagName("testbeds")[0] 
163         testbed_tag_list = testbeds_tag.getElementsByTagName("testbed")
164         for testbed_tag in testbed_tag_list:
165             if testbed_tag.nodeType == doc.ELEMENT_NODE:
166                 testbed_guid = int(testbed_tag.getAttribute("guid"))
167                 elements_tag = testbed_tag.getElementsByTagName("elements")[0] 
168                 elements_tag = testbed_tag.removeChild(elements_tag)
169                 self.testbed_data_from_xml(testbed_tag, data)
170                 element_tag_list = elements_tag.getElementsByTagName("element")
171                 for element_tag in element_tag_list:
172                     if element_tag.nodeType == doc.ELEMENT_NODE:
173                         self.box_data_from_xml(element_tag, testbed_guid, data)
174         return data
175
176     def from_xml(self, experiment_description, xml):
177         data = self.from_xml_to_data(xml)
178         self.from_data(experiment_description, data)
179
180     def testbed_data_from_xml(self, tag, data):
181         testbed_guid = int(tag.getAttribute("guid"))
182         testbed_id = xmldecode(tag.getAttribute("testbed_id"))
183         testbed_version = xmldecode(tag.getAttribute("testbed_version"))
184         data.add_testbed_data(testbed_guid, testbed_id, testbed_version)
185         self.graphical_info_data_from_xml(tag, testbed_guid, data)
186         self.attributes_data_from_xml(tag, testbed_guid, data)
187
188     def box_data_from_xml(self, tag, testbed_guid, data):
189         guid = int(tag.getAttribute("guid"))
190         factory_id = xmldecode(tag.getAttribute("factory_id"))
191         data.add_box_data(guid, testbed_guid, factory_id)
192         self.graphical_info_data_from_xml(tag, guid, data)
193         self.factory_attributes_data_from_xml(tag, guid, data)
194         self.attributes_data_from_xml(tag, guid, data)
195         self.traces_data_from_xml(tag, guid, data)
196         self.addresses_data_from_xml(tag, guid, data)
197         self.routes_data_from_xml(tag, guid, data)
198         self.connections_data_from_xml(tag, guid, data)
199
200     def graphical_info_data_from_xml(self, tag, guid, data):
201         graphical_info_tag_list = tag.getElementsByTagName(
202                 "graphical_info")
203         if len(graphical_info_tag_list) == 0:
204             return
205
206         graphical_info_tag = graphical_info_tag_list[0]
207         if graphical_info_tag.nodeType == tag.ELEMENT_NODE:
208             x = float(graphical_info_tag.getAttribute("x"))
209             y = float(graphical_info_tag.getAttribute("y"))
210             width = float(graphical_info_tag.getAttribute("width"))
211             height = float(graphical_info_tag.getAttribute("height"))
212             data.add_graphical_info_data(guid, x, y, width, height)
213
214     def factory_attributes_data_from_xml(self, tag, guid, data):
215         factory_attributes_tag_list = tag.getElementsByTagName(
216                 "factory_attributes")
217         if len(factory_attributes_tag_list) == 0:
218             return
219
220         factory_attribute_tag_list = factory_attributes_tag_list[0].\
221                 getElementsByTagName("factory_attribute")
222         for factory_attribute_tag in factory_attribute_tag_list:
223              if factory_attribute_tag.nodeType == tag.ELEMENT_NODE:
224                 name = xmldecode(factory_attribute_tag.getAttribute("name"))
225                 value = xmldecode(factory_attribute_tag.getAttribute("value"))
226                 std_type = xmldecode(factory_attribute_tag.getAttribute("type"))
227                 value = self.type_from_standard(std_type, value)
228                 data.add_factory_attribute_data(guid, name, value)
229
230     def attributes_data_from_xml(self, tag, guid, data):
231         attributes_tag_list= tag.getElementsByTagName("attributes")
232         if len(attributes_tag_list) == 0:
233             return
234
235         attribute_tag_list = attributes_tag_list[0].\
236                 getElementsByTagName("attribute")
237         for attribute_tag in attribute_tag_list:
238              if attribute_tag.nodeType == tag.ELEMENT_NODE:
239                 name = xmldecode(attribute_tag.getAttribute("name"))
240                 value = xmldecode(attribute_tag.getAttribute("value"))
241                 std_type = xmldecode(attribute_tag.getAttribute("type"))
242                 value = self.type_from_standard(std_type, value)
243                 data.add_attribute_data(guid, name, value)
244
245     def traces_data_from_xml(self, tag, guid, data):
246         traces_tag_list = tag.getElementsByTagName("traces")
247         if len(traces_tag_list) == 0:
248             return
249
250         trace_tag_list = traces_tag_list[0].getElementsByTagName(
251                 "trace")
252         for trace_tag in trace_tag_list:
253              if trace_tag.nodeType == tag.ELEMENT_NODE:
254                 name = xmldecode(trace_tag.getAttribute("name"))
255                 data.add_trace_data(guid, name)
256
257     def addresses_data_from_xml(self, tag, guid, data):
258         addresses_tag_list = tag.getElementsByTagName("addresses")
259         if len(addresses_tag_list) == 0:
260             return
261
262         address_tag_list = addresses_tag_list[0].\
263                 getElementsByTagName("address")
264         for address_tag in address_tag_list:
265             if address_tag.nodeType == tag.ELEMENT_NODE:
266                 address = xmldecode(address_tag.getAttribute("Address")) \
267                        if address_tag.hasAttribute("Address") else None
268                 netprefix = int(address_tag.getAttribute("NetPrefix")) \
269                        if address_tag.hasAttribute("NetPrefix") else None
270                 broadcast = xmldecode(address_tag.getAttribute("Broadcast")) \
271                        if address_tag.hasAttribute("Broadcast") else None
272                 data.add_address_data(guid, address, netprefix, broadcast)
273
274     def routes_data_from_xml(self, tag, guid, data):
275         routes_tag_list = tag.getElementsByTagName("routes")
276         if len(routes_tag_list) == 0:
277             return
278
279         route_tag_list = routes_tag_list[0].getElementsByTagName("route")
280         for route_tag in route_tag_list:
281             if route_tag.nodeType == tag.ELEMENT_NODE:
282                 destination = xmldecode(route_tag.getAttribute("Destination"))
283                 netprefix = int(route_tag.getAttribute("NetPrefix"))
284                 nexthop = xmldecode(route_tag.getAttribute("NextHop"))
285                 metric = int(route_tag.getAttribute("Metric")) \
286                         if route_tag.hasAttribute("Metric") else 0
287                 data.add_route_data(guid, destination, netprefix, 
288                         nexthop, metric)
289
290     def connections_data_from_xml(self, tag, guid, data):
291         connections_tag_list = tag.getElementsByTagName("connections")
292         if len(connections_tag_list) == 0:
293             return
294
295         connection_tag_list = connections_tag_list[0].getElementsByTagName(
296                 "connection")
297         for connection_tag in connection_tag_list:
298              if connection_tag.nodeType == tag.ELEMENT_NODE:
299                  connector_type_name = xmldecode(connection_tag.getAttribute(
300                      "connector"))
301                  other_connector_type_name = xmldecode(connection_tag.getAttribute(
302                          "other_connector"))
303                  other_guid = int(connection_tag.getAttribute("other_guid"))
304                  data.add_connection_data(guid, connector_type_name, 
305                          other_guid, other_connector_type_name)
306
307     def type_to_standard(self, value):
308         if isinstance(value, str):
309             return Attribute.STRING
310         if isinstance(value, bool):
311             return Attribute.BOOL
312         if isinstance(value, int):
313             return Attribute.INTEGER
314         if isinstance(value, float):
315             return Attribute.DOUBLE
316     
317     def type_from_standard(self, type, value):
318         if type == Attribute.STRING:
319             return str(value)
320         if type == Attribute.BOOL:
321             return value == "True"
322         if type == Attribute.INTEGER:
323             return int(value)
324         if type == Attribute.DOUBLE:
325             return float(value)
326