Atlas 0.7.0
Networking protocol for the Worldforge system.
parse_xml.py
1# parse XML into objects
2
3# Copyright 2000, 2001 by Aloril
4# Copyright 2002 by AIR-IX SUUNNITTELU/Ahiplan Oy
5
6# This library is free software; you can redistribute it and/or
7# modify it under the terms of the GNU Lesser General Public
8# License as published by the Free Software Foundation; either
9# version 2.1 of the License, or (at your option) any later version.
10
11# This library is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14# Lesser General Public License for more details.
15
16import string
17# You should have received a copy of the GNU Lesser General Public
18# License along with this library; if not, write to the Free Software
19# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20import xml
21import xml.sax
22
23import atlas
24from . import decoder
25
26"""
27usage:
28parseXML=get_parser()
29atlas_objects=parseXML("input XML string here")
30
31resulting atlas_objects has 0 or more atlas objects
32
33
34NOTE: you need to make separate parser for each stream (for example
35when several clients connect)
36"""
37
38
39class XmlException(Exception): pass
40
41
42class AtlasParser(xml.sax.ContentHandler, decoder.BaseDecoder):
43
44 def __init__(self):
45 super().__init__()
46 self.datadata = ""
47 self.root_obj = []
48 self.name_stack = []
49 self.obj_stack = [self.root_obj]
50 self.seen_atlas_tag = 0
51 self.msgListmsgList = []
52
53 def setup(self, stream_flag=None):
54 """uses tree that start from root_obj, current route to leave
55 is kept in obj_stack"""
56 # Root object is never removed or visible for parser users,
57 # incoming objects are added to its value
58 self.root_obj = []
59 self.name_stack = []
60 self.obj_stack = [self.root_obj]
61
62 # resulting complete atlas 'messages' are added here
63 decoder.BaseDecoder.setup(self, stream_flag)
64
65 def set_stream_mode(self, mode=1):
66 decoder.BaseDecoder.set_stream_mode(self, mode)
67 self.seen_atlas_tag = 0
68
69 def parse_init(self):
70 if not self.stream_flag and not self.seen_atlas_tag:
71 self.feed("<atlas>")
72
73
90
91 def eos(self):
92 """end of stream"""
93 return not [_f for _f in [ch not in string.whitespace for ch in self.datadata] if _f] and self.obj_stack == [[]]
94
95 def unknown_starttag(self, tag, attributes):
96 raise XmlException("Unknown tag: " + tag)
97
98 def characters(self, data):
99 """#PCDATA (actual string,int,float,uri content)"""
100 self.datadata = self.datadata + data
101
102 def startElement(self, tag, attributes):
103 if tag == "atlas":
104 self.start_atlas()
105 elif tag == "int":
106 self.start_int(attributes)
107 elif tag == "float":
108 self.start_float(attributes)
109 elif tag == "string":
110 self.start_string(attributes)
111 elif tag == "map":
112 self.start_map(attributes)
113 elif tag == "list":
114 self.start_list(attributes)
115
116 def endElement(self, tag):
117 if tag == "atlas":
118 self.end_atlas()
119 elif tag == "int":
120 self.end_int()
121 elif tag == "float":
122 self.end_float()
123 elif tag == "string":
124 self.end_string()
125 elif tag == "map":
126 self.end_map()
127 elif tag == "list":
128 self.end_list()
129 pass
130
131 def start_atlas(self):
132 self.seen_atlas_tag = 1
133
134 def end_atlas(self):
135 self.seen_atlas_tag = 0
136
137 def start_value(self, attributes):
138 """for int/float/string: save name if have one"""
139 self.name_stack.append(attributes.get("name", ""))
140 self.datadata = ""
141
142 def end_value(self, value):
143 """put value into mapping/list"""
144 self.datadata = ""
145 obj = self.obj_stack[-1]
146 name = self.name_stack[-1]
147 del self.name_stack[-1]
148 if name:
149 if not isinstance(obj, atlas.Object):
150 raise XmlException("attribute outside mapping (%s:%s)!" % \
151 (name, value))
152 setattr(obj, name, value)
153 else:
154 if not isinstance(obj, list):
155 raise XmlException("value mapping list (%s)!" % value)
156 obj.append(value)
157
158 def push_value(self, attributes, initial_value):
159 """for list/map: add to stack"""
160 self.start_value(attributes)
161 self.obj_stack.append(initial_value)
162
163 def pop_value(self):
164 """for list/map: remove from stack"""
165 obj = self.obj_stack[-1]
166 del self.obj_stack[-1]
167 self.end_value(obj)
168 # check top level
169 if len(self.obj_stack) == 1:
170 obj = self.obj_stack[0][0]
171 self.msgListmsgList.append(obj)
172 del self.obj_stack[0][0]
173
174 # all single type methods make object with optional name and type
175 # and clear data and at the end tag then parse content
176 def start_int(self, attributes):
177 self.start_value(attributes)
178
179 def end_int(self):
180 try:
181 value = int(self.datadata)
182 except ValueError:
183 value = int(self.datadata)
184 self.end_value(value)
185
186 def start_float(self, attributes):
187 self.start_value(attributes)
188
189 def end_float(self):
190 self.end_value(float(self.datadata))
191
192 def start_string(self, attributes):
193 self.start_value(attributes)
194
195 def end_string(self):
196 self.end_value(self.datadata)
197
198 def start_list(self, attributes):
199 self.push_value(attributes, [])
200
201 def end_list(self):
202 self.pop_value()
203
204 def start_map(self, attributes):
205 self.push_value(attributes, atlas.Object())
206
207 def end_map(self):
208 self.pop_value()
209
210
211def string2object(string):
212 """convert a string of one entity into an object"""
213 # make a parser
214 parse = get_parser()
215
216 parse("<atlas>")
217 return parse(string)[0]
218
219
220def parse_string_to_dict(string, full_stream=0):
221 """convert a string of entities into a dict of entites"""
222 # make a parser
223 parse = get_decoder(full_stream)
224
225
228
229 # parse the input file that is xml and put it in all_objects
230 all_objects = parse(string)
231
232 # make a blank dictionary
233 objects = {}
234
235 # cut all_object apart and insert it into object
236 for obj in all_objects:
237 objects[obj.id] = obj
238
239 # return a dict of the parsed item
240 return objects
241
242
243def read_file_to_dict(file):
244 fp = open(file)
245 objects = parse_string_to_dict(fp.read(), full_stream=1)
246 fp.close()
247 return objects
248
249
250def get_decoder(stream_flag=None):
251 xml_msg_parser = AtlasParser()
252 xml_msg_parser.setup(stream_flag)
253 return xml_msg_parser
254
255def parse_stream(data):
256 handler = AtlasParser()
257 xml.sax.parseString(data, handler)
258 res=atlas.Messages(*tuple(handler.msgList))
259 return res
260
def start_string(self, attributes)
Definition: parse_xml.py:192
def start_map(self, attributes)
Definition: parse_xml.py:204
def start_list(self, attributes)
Definition: parse_xml.py:198
def start_value(self, attributes)
Definition: parse_xml.py:137
def start_float(self, attributes)
Definition: parse_xml.py:186
def eos(self)
def parse_stream(self, msg): """parse incoming data and return all complete messages""" #print msg se...
Definition: parse_xml.py:91
def setup(self, stream_flag=None)
Definition: parse_xml.py:53
def push_value(self, attributes, initial_value)
Definition: parse_xml.py:158
def start_int(self, attributes)
Definition: parse_xml.py:176