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 
16 import 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
20 import xml
21 import xml.sax
22 
23 import atlas
24 from . import decoder
25 
26 """
27 usage:
28 parseXML=get_parser()
29 atlas_objects=parseXML("input XML string here")
30 
31 resulting atlas_objects has 0 or more atlas objects
32 
33 
34 NOTE: you need to make separate parser for each stream (for example
35 when several clients connect)
36 """
37 
38 
39 class XmlException(Exception): pass
40 
41 
42 class AtlasParser(xml.sax.ContentHandler, decoder.BaseDecoder):
43 
44  def __init__(self):
45  super().__init__()
46  self.data = ""
47  self.root_obj = []
48  self.name_stack = []
49  self.obj_stack = [self.root_obj]
50  self.seen_atlas_tag = 0
51  self.msgList = []
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  ## def parse_stream(self, msg):
74  ## """parse incoming data and return all complete messages"""
75  ## #print msg
76  ## self.msg=msg
77  ## self.feed(msg) #inherited from XMLParser
78  ## if self.stream_flag:
79  ## res=apply(atlas.Messages,tuple(self.msgList))
80  ## self.msgList=[]
81  ## return res
82  ## else:
83  ## if self.msgList:
84  ## res = self.msgList.pop(0)
85  ## else:
86  ## res = None
87  ## return res
88  ## __call__=parse_stream #this makes possible to call instance like
89  ## #it was function
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.data] 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.data = self.data + 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.data = ""
141 
142  def end_value(self, value):
143  """put value into mapping/list"""
144  self.data = ""
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.msgList.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.data)
182  except ValueError:
183  value = int(self.data)
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.data))
191 
192  def start_string(self, attributes):
193  self.start_value(attributes)
194 
195  def end_string(self):
196  self.end_value(self.data)
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 
211 def 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 
220 def 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  ## if not full_stream:
226  ## #set parser to atlas mode
227  ## parse("<atlas>")
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 
243 def 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 
250 def get_decoder(stream_flag=None):
251  xml_msg_parser = AtlasParser()
252  xml_msg_parser.setup(stream_flag)
253  return xml_msg_parser
254 
255 def 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_list(self, attributes)
Definition: parse_xml.py:198
def start_float(self, attributes)
Definition: parse_xml.py:186
def start_int(self, attributes)
Definition: parse_xml.py:176
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 start_map(self, attributes)
Definition: parse_xml.py:204
def setup(self, stream_flag=None)
Definition: parse_xml.py:53
def start_value(self, attributes)
Definition: parse_xml.py:137
def start_string(self, attributes)
Definition: parse_xml.py:192
def push_value(self, attributes, initial_value)
Definition: parse_xml.py:158