root/branch/UMPA/umpa/extensions/XML.py @ 4538

Revision 4538, 7.2 kB (checked in by getxsick, 4 years ago)

typo

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright (C) 2008 Adriano Monteiro Marques.
5#
6# Author: Bartosz SKOWRON <getxsick at gmail dot com>
7#
8# This library is free software; you can redistribute it and/or modify
9# it under the terms of the GNU Lesser General Public License as published
10# by the Free Software Foundation; either version 2.1 of the License, or
11# (at your option) any later version.
12#
13# This library is distributed in the hope that it will be useful, but
14# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16# License for more details.
17#
18# You should have received a copy of the GNU Lesser General Public License
19# along with this library; if not, write to the Free Software Foundation,
20# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
22"""
23XML features
24
25Packets can be loaded/saved from/to XML files.
26
272 functions are provided:
28 1. save()
29 2. load()
30
31Also, Packet objects get 2 extra methods:
32 1. Packet.save_xml()
33 2. Packet.load_xml()
34"""
35
36import re
37import xml.dom.minidom
38
39import umpa
40from umpa.protocols._fields import Flags
41
42# TODO: refactoring with SAX usage
43
44def save(filename, packets):
45    """
46    Save the list of Packet's objects into XML file.
47
48    @type filename: C{str}
49    @param filename: name of the XML file.
50
51    @type packets: C{list}
52    @param packets: list of packets which will be saved.
53    """
54
55    # for parsing python-object strings like <.... 'xxxx'>
56    parse_str = re.compile(r"^.*'([\w\.]+)'>$")
57
58    doc = xml.dom.minidom.Document()
59    root = doc.createElement('UMPA')
60    doc.appendChild(root)
61    for i, packet in enumerate(packets):
62        pa = doc.createElement('packet')
63        pa.setAttribute("id", str(i))
64        pa.setAttribute("strict", str(packet.strict))
65        root.appendChild(pa)
66
67        for proto in packet.protos:
68            pr = doc.createElement('protocol')
69            classname = parse_str.match(str(proto.__class__)).group(1)
70            pr.setAttribute("class", classname)
71            pa.appendChild(pr)
72
73            for field in proto.get_fields_keys():
74                f = doc.createElement(field)
75                pr.appendChild(f)
76                # if Flags...we need care about BitFlags objects
77                if isinstance(proto.get_field(field), Flags):
78                    f.setAttribute("type", "bits")
79                    for flag in proto.get_field(field).get():
80                        b = doc.createElement(flag)
81                        f.appendChild(b)
82                        value = proto.get_field(field)._value[flag].get()
83                        b.appendChild(doc.createTextNode(str(value)))
84                        b.setAttribute("type",
85                            parse_str.match(str(type(value))).group(1))
86                else:
87                    f.appendChild(doc.createTextNode(
88                        str(proto.get_field(field).get())))
89                    f.setAttribute("type", parse_str.match(
90                        str(type(proto.get_field(field).get()))).group(1))
91
92    # check if filename is not already opened
93    try:
94        filename.write(doc.toprettyxml())
95    except AttributeError:
96        open(filename, "w").write(doc.toprettyxml())
97
98def load(filename, proto_only=False):
99    """
100    Load Packet's objects from the XML file.
101
102    Normally, return list of objects' packets but if proto_only is True,
103    just return list of protocols from the first loaded packet.
104    It's usefull if in some cases.
105    I{Example}:
106
107        >>> import umpa
108        >>> import umpa.extensions.XML
109        >>> packet = umpa.Packet()
110        >>> packet.load_xml('packets.xml') # proto_only by default in this case
111   
112    In this case, don't create new objects of Packet. Return list of protocols
113    intead.
114
115    @type filename: C{str}
116    @param filename: name of the XML file.
117
118    @type proto_only: C{bool}
119    @param proto_only: if True, return list of protocols from the first loaded
120    packet (default: I{False}).
121
122    @rtype: C{list}
123    @return: loaded Packet's objects or list of protocols from the first
124    loaded packet (if proto_only is True).
125    """
126
127    doc = xml.dom.minidom.parse(filename)
128
129    # useful if you have type in string and need to cast it
130    typemap = dict(float=float, int=int, str=str, bool=bool)
131
132    packets = []
133    for pa in doc.getElementsByTagName("packet"):
134        is_true = (pa.getAttribute("strict") != "False")
135        packet = umpa.Packet(strict=is_true)
136        for pr in pa.getElementsByTagName("protocol"):
137            # dealing with class of protocol
138            protocol_name = pr.getAttribute("class").split(".")
139            # we need to import proper class
140            mname = '.'.join(protocol_name[:-1])
141            cname = protocol_name[-1]
142            mod = __import__(mname, fromlist=[None])
143            # and create an instance
144            clss = getattr(mod, cname)
145            protocol = clss()
146           
147            for node in pr.childNodes:
148                # because of pretty-style of XML files
149                # we need to check if nodes are necessary
150                if node.nodeType == node.ELEMENT_NODE:
151                    field_name = node.localName
152
153                    # checking if not Flags
154                    type_node = node.getAttribute("type")
155                    if type_node != "bits":
156                        value = node.childNodes[0].nodeValue.strip()
157                        if type_node == "NoneType":
158                            value = None
159                        else:
160                            value = typemap[type_node](value)
161                        protocol.get_field(field_name).set(value)
162                    # Flags
163                    else:
164                        for bit in node.childNodes:
165                            if bit.nodeType == node.ELEMENT_NODE:
166                                bit_name = bit.localName
167                                bit_value = bit.childNodes[0].nodeValue.strip()
168                                is_true = (bit_value == "True")
169                                if is_true:
170                                    protocol.get_field(field_name).set(
171                                                                    bit_name)
172                                else:
173                                    protocol.get_field(field_name).unset(
174                                                                    bit_name)
175            packet.include(protocol)
176
177        # we only load first packet in the file and return list of protocols..
178        if proto_only:
179            return packet.protos
180    packets.append(packet)
181    return packets
182
183def _save_xml(self, filename):
184    """
185    Save the Packet's object into XML file.
186
187    @type filename: C{str}
188    @param filename: name of the XML file.
189    """
190
191    save(filename, [self, ])
192
193def _load_xml(self, filename):
194    """
195    Load defined protocols from the XML file.
196
197    Overwrite current list of the protocols in the Packet's object by
198    loaded protocols.
199   
200    Internally, call umpa.extensions.XML.load() function with proto_only=True
201    attribute.
202    @type filename: C{str}
203    @param filename: name of the XML file.
204    """
205
206    self.protos = load(filename, proto_only=True)
207
208umpa.Packet.save_xml = _save_xml
209umpa.Packet.load_xml = _load_xml
Note: See TracBrowser for help on using the browser.