/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/load.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/Model/load.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 744 by jonathan, Fri Apr 25 10:26:35 2003 UTC revision 1282 by bh, Mon Jun 23 09:47:18 2003 UTC
# Line 20  import xml.sax.handler Line 20  import xml.sax.handler
20  from xml.sax import make_parser, ErrorHandler, SAXNotRecognizedException  from xml.sax import make_parser, ErrorHandler, SAXNotRecognizedException
21    
22  from Thuban import _  from Thuban import _
 from Thuban.common import *  
23    
24  from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \  from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
25       FIELDTYPE_STRING       FIELDTYPE_STRING
26    
27  from Thuban.Model.session import Session  from Thuban.Model.session import Session
28  from Thuban.Model.map import Map  from Thuban.Model.map import Map
29  from Thuban.Model.layer import Layer  from Thuban.Model.layer import Layer, RasterLayer
30  from Thuban.Model.color import Color  from Thuban.Model.color import Color
31  from Thuban.Model.proj import Projection  from Thuban.Model.proj import Projection
32    from Thuban.Model.range import Range
33  from Thuban.Model.classification import Classification, \  from Thuban.Model.classification import Classification, \
34      ClassGroupDefault, ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \      ClassGroupDefault, ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \
35      ClassGroupProperties      ClassGroupProperties
36    from Thuban.Model.data import DerivedShapeStore, ShapefileStore
37    from Thuban.Model.table import DBFTable
38    from Thuban.Model.transientdb import TransientJoinedTable
39    
40    class LoadError(Exception):
41        pass
42    
43    from Thuban.Model.xmlreader import XMLReader
44    import resource
45    
46  def parse_color(color):  def parse_color(color):
47      """Return the color object for the string color.      """Return the color object for the string color.
# Line 57  def parse_color(color): Line 65  def parse_color(color):
65          raise ValueError(_("Invalid color specification %s") % color)          raise ValueError(_("Invalid color specification %s") % color)
66      return result      return result
67    
68    class AttrDesc:
69    
70  class XMLReader(xml.sax.handler.ContentHandler):      def __init__(self, name, required = False, default = "",
71                     conversion = None):
72      # Dictionary mapping element names (or (URI, element name) pairs for          if not isinstance(name, tuple):
73      # documents using namespaces) to method names. The methods should              fullname = (None, name)
     # accept the same parameters as the startElement (or startElementNS)  
     # methods. The start_dispatcher is used by the default startElement  
     # and startElementNS methods to call a method for the open tag of an  
     # element.  
     start_dispatcher = {}  
   
     # end_dispatcher works just like start_dispatcher but it's used by  
     # endElement and endElementNS. The method whose names it maps to  
     # should accept the same parameters as endElement and endElementNS.  
     end_dispatcher = {}  
   
   
     def __init__(self):  
         self.chars = ''  
         self.__parser = None  
         self.__directory = ""  
         self.__dispatchers = {}  
   
     def read(self, file_or_filename):  
   
         if hasattr(file_or_filename, "read"):  
             # it's a file object  
             self.__directory = ""  
             self.__file = file_or_filename  
74          else:          else:
75              filename = file_or_filename              fullname = name
76              self.__directory = os.path.dirname(filename)              name = name[1]
77              self.__file = open(filename)          self.name = name
78            self.fullname = fullname
79          if self.__parser is None:          self.required = required
80              self.__parser = make_parser()          self.default = default
81              self.__parser.setContentHandler(self)          self.conversion = conversion
             self.__parser.setErrorHandler(ErrorHandler())  
             self.__parser.setFeature(xml.sax.handler.feature_namespaces, 1)  
   
             #  
             # Well, this isn't pretty, but it appears that if you  
             # use Python 2.2 without the site-package _xmlplus then  
             # the following will fail, and without them it will work.  
             # However, if you do have the site-package and you don't  
             # call these functions, the reader raises an exception  
             #  
             # The reason we set these to 0 in the first place is  
             # because there is an unresolved issue with external  
             # entities causing an exception in the reader  
             #  
             try:  
                 self.__parser.setFeature(xml.sax.handler.feature_validation,0)  
                 self.__parser.setFeature(xml.sax.handler.feature_external_ges,0)  
                 self.__parser.setFeature(xml.sax.handler.feature_external_pes,0)  
             except SAXNotRecognizedException:  
                 pass  
   
         self.__parser.parse(self.__file)  
82    
83          self.close()          # set by the SessionLoader's check_attrs method
84            self.value = None
85    
     def close(self):  
         self.__file.close()  
           
     def GetFilename(self):  
         if hasattr(self.__file, "name"):  
             return self.__file.name  
   
         return ""  
   
     def GetDirectory(self):  
         return self.__directory  
   
   
     def AddDispatchers(self, dict):  
         """Add the function names that should be used to process XML tags.  
   
         dict -- a dictionary whose keys are XML tag strings and whose values  
                 are pairs of strings such that the first string is  
                 the name of the function that should be called when the  
                 XML tag opens and the second string is the name of the  
                 function that should be called when the XML tag closes.  
                 If a pair element is None, no function is called.  
         """  
   
         self.__dispatchers.update(dict)  
   
     def startElementNS(self, name, qname, attrs):  
         """Call the method given for name in self.start_dispatcher  
         """  
         if name[0] is None:  
             method_name = self.__dispatchers.get(name[1])  
         else:  
             # Dispatch with namespace  
             method_name = self.__dispatchers.get(name)  
         if method_name is not None and method_name[0] is not None:  
             getattr(self, method_name[0])(name, qname, attrs)  
   
     def endElementNS(self, name, qname):  
         """Call the method given for name in self.end_dispatcher  
         """  
         if name[0] is None:  
             method_name = self.__dispatchers.get(name[1])  
         else:  
             # Dispatch with namespace  
             method_name = self.__dispatchers.get(name)  
         if method_name is not None and method_name[1] is not None:  
             getattr(self, method_name[1])(name, qname)  
86    
87  class SessionLoader(XMLReader):  class SessionLoader(XMLReader):
88    
# Line 177  class SessionLoader(XMLReader): Line 94  class SessionLoader(XMLReader):
94          self.aMap = None          self.aMap = None
95          self.aLayer = None          self.aLayer = None
96    
97          XMLReader.AddDispatchers(self,          # Map ids used in the thuban file to the corresponding objects
98              {'session'       : ("start_session",        "end_session"),          # in the session
99               'map'           : ("start_map",            "end_map"),          self.idmap = {}
100               'projection'    : ("start_projection",     "end_projection"),  
101               'parameter'     : ("start_parameter",      None),          dispatchers = {
102               'layer'         : ("start_layer",          "end_layer"),              'session'       : ("start_session",        "end_session"),
103               'classification': ("start_classification", "end_classification"),              'fileshapesource': ("start_fileshapesource", None),
104               'clnull'        : ("start_clnull",         "end_clnull"),              'derivedshapesource': ("start_derivedshapesource", None),
105               'clpoint'       : ("start_clpoint",        "end_clpoint"),              'filetable': ("start_filetable", None),
106               'clrange'       : ("start_clrange",        "end_clrange"),              'jointable': ("start_jointable", None),
107               'cldata'        : ("start_cldata",         "end_cldata"),  
108               'table'         : ("start_table",          "end_table"),              'map'           : ("start_map",            "end_map"),
109               'labellayer'    : ("start_labellayer",     None),              'projection'    : ("start_projection",     "end_projection"),
110               'label'         : ("start_label",          None)})              'parameter'     : ("start_parameter",      None),
111                'layer'         : ("start_layer",          "end_layer"),
112                'rasterlayer'   : ("start_rasterlayer",    "end_rasterlayer"),
113                'classification': ("start_classification", "end_classification"),
114                'clnull'        : ("start_clnull",         "end_clnull"),
115                'clpoint'       : ("start_clpoint",        "end_clpoint"),
116                'clrange'       : ("start_clrange",        "end_clrange"),
117                'cldata'        : ("start_cldata",         "end_cldata"),
118                'table'         : ("start_table",          "end_table"),
119                'labellayer'    : ("start_labellayer",     None),
120                'label'         : ("start_label",          None)}
121    
122            # all dispatchers should be used for the 0.8 namespace
123            xmlns = "http://thuban.intevation.org/dtds/thuban-0.8.dtd"
124            for key, value in dispatchers.items():
125                dispatchers[(xmlns, key)] = value
126    
127            XMLReader.AddDispatchers(self, dispatchers)
128    
129      def start_session(self, name, qname, attrs):      def start_session(self, name, qname, attrs):
130          self.theSession = Session(attrs.get((None, 'title'), None))          self.theSession = Session(self.encode(attrs.get((None, 'title'),
131                                                            None)))
132    
133      def end_session(self, name, qname):      def end_session(self, name, qname):
134          pass          pass
135    
136        def check_attrs(self, element, attrs, descr):
137            """Check and convert some of the attributes of an element
138    
139            Parameters:
140               element -- The element name
141               attrs -- The attrs mapping as passed to the start_* methods
142               descr -- Sequence of attribute descriptions (AttrDesc instances)
143    
144            Return a dictionary containig normalized versions of the
145            attributes described in descr. The keys of that dictionary are
146            the name attributes of the attribute descriptions. The attrs
147            dictionary will not be modified.
148    
149            If the attribute is required, i.e. the 'required' attribute of
150            the descrtiption is true, but it is not in attrs, raise a
151            LoadError.
152    
153            If the attribute has a default value and it is not present in
154            attrs, use that default value as the value in the returned dict.
155    
156            If a conversion is specified, convert the value before putting
157            it into the returned dict. The following conversions are
158            available:
159    
160               'filename' -- The attribute is a filename.
161    
162                             If the filename is a relative name, interpret
163                             it relative to the directory containing the
164                             .thuban file and make it an absolute name
165    
166               'shapestore' -- The attribute is the ID of a shapestore
167                               defined earlier in the .thuban file. Look it
168                               up self.idmap
169    
170               'table' -- The attribute is the ID of a table or shapestore
171                          defined earlier in the .thuban file. Look it up
172                          self.idmap. If it's the ID of a shapestore the
173                          value will be the table of the shapestore.
174            """
175            normalized = {}
176    
177            for d in descr:
178                if d.required and not attrs.has_key(d.fullname):
179                    pass
180                #raise LoadError("Element %s requires an attribute %r"
181                #                    % (element, d.name))
182                value = attrs.get(d.fullname, d.default)
183    
184                if d.conversion == "shapesource":
185                    if value in self.idmap:
186                        value = self.idmap[value]
187                    else:
188                        raise LoadError("Element %s requires an already defined ID"
189                                        " in attribute %r"
190                                        % (element, d.name))
191                elif d.conversion == "table":
192                    if value in self.idmap:
193                        value = self.idmap[value]
194                        if isinstance(value, ShapefileStore):
195                            value = value.Table()
196                    else:
197                        raise LoadError("Element %s requires an already defined ID"
198                                        " in attribute %r"
199                                        % (element, d.name))
200                elif d.conversion == "filename":
201                    value = os.path.abspath(os.path.join(self.GetDirectory(),
202                                                         value))
203    
204                normalized[d.name] = value
205            return normalized
206    
207        def start_fileshapesource(self, name, qname, attrs):
208            attrs = self.check_attrs(name, attrs,
209                                      [AttrDesc("id", True),
210                                       AttrDesc("filename", True,
211                                                conversion = "filename"),
212                                       AttrDesc("filetype", True)])
213            ID = attrs["id"]
214            filename = attrs["filename"]
215            filetype = attrs["filetype"]
216            if filetype != "shapefile":
217                raise LoadError("shapesource filetype %r not supported" % filetype)
218            self.idmap[ID] = self.theSession.OpenShapefile(filename)
219    
220        def start_derivedshapesource(self, name, qname, attrs):
221            attrs = self.check_attrs(name, attrs,
222                                     [AttrDesc("id", True),
223                                      AttrDesc("shapesource", True,
224                                               conversion = "shapesource"),
225                                      AttrDesc("table", True, conversion="table")])
226            store = DerivedShapeStore(attrs["shapesource"], attrs["table"])
227            self.theSession.AddShapeStore(store)
228            self.idmap[attrs["id"]] = store
229    
230        def start_filetable(self, name, qname, attrs):
231            attrs = self.check_attrs(name, attrs,
232                                     [AttrDesc("id", True),
233                                      AttrDesc("title", True),
234                                      AttrDesc("filename", True,
235                                               conversion = "filename"),
236                                      AttrDesc("filetype")])
237            filetype = attrs["filetype"]
238            if filetype != "DBF":
239                raise LoadError("shapesource filetype %r not supported" % filetype)
240            table = DBFTable(attrs["filename"])
241            table.SetTitle(attrs["title"])
242            self.idmap[attrs["id"]] = self.theSession.AddTable(table)
243    
244        def start_jointable(self, name, qname, attrs):
245            attrs = self.check_attrs(name, attrs,
246                                     [AttrDesc("id", True),
247                                      AttrDesc("title", True),
248                                      AttrDesc("left", True, conversion="table"),
249                                      AttrDesc("leftcolumn", True),
250                                      AttrDesc("right", True, conversion="table"),
251                                      AttrDesc("rightcolumn")])
252            table = TransientJoinedTable(self.theSession.TransientDB(),
253                                         attrs["left"], attrs["leftcolumn"],
254                                         attrs["right"], attrs["rightcolumn"])
255            table.SetTitle(attrs["title"])
256            self.idmap[attrs["id"]] = self.theSession.AddTable(table)
257    
258      def start_map(self, name, qname, attrs):      def start_map(self, name, qname, attrs):
259          """Start a map."""          """Start a map."""
260          self.aMap = Map(attrs.get((None, 'title'), None))          self.aMap = Map(attrs.get((None, 'title'), None))
         self.__projReceiver = self.aMap  
261    
262      def end_map(self, name, qname):      def end_map(self, name, qname):
263          self.theSession.AddMap(self.aMap)          self.theSession.AddMap(self.aMap)
264          self.__projReceiver = None          self.aMap = None
265    
266      def start_projection(self, name, qname, attrs):      def start_projection(self, name, qname, attrs):
267          self.ProjectionName = attrs.get((None, 'name'), None)          self.ProjectionName = self.encode(attrs.get((None, 'name'), None))
268          self.ProjectionParams = [ ]          self.ProjectionParams = [ ]
269    
270      def end_projection(self, name, qname):      def end_projection(self, name, qname):
271          self.__projReceiver.SetProjection(          if self.aLayer is not None:
272                obj = self.aLayer
273            elif self.aMap is not None:
274                obj = self.aMap
275            else:
276                assert False, "projection tag out of context"
277                pass
278    
279            obj.SetProjection(
280              Projection(self.ProjectionParams, self.ProjectionName))              Projection(self.ProjectionParams, self.ProjectionName))
281    
282      def start_parameter(self, name, qname, attrs):      def start_parameter(self, name, qname, attrs):
# Line 227  class SessionLoader(XMLReader): Line 291  class SessionLoader(XMLReader):
291          attrs which may be a dictionary as well as the normal SAX attrs          attrs which may be a dictionary as well as the normal SAX attrs
292          object and bind it to self.aLayer.          object and bind it to self.aLayer.
293          """          """
294          title = attrs.get((None, 'title'), "")          title = self.encode(attrs.get((None, 'title'), ""))
295          filename = attrs.get((None, 'filename'), "")          filename = attrs.get((None, 'filename'), "")
296          filename = os.path.join(self.GetDirectory(), filename)          filename = os.path.join(self.GetDirectory(), filename)
297            filename = self.encode(filename)
298            visible  = self.encode(attrs.get((None, 'visible'), "true")) != "false"
299          fill = parse_color(attrs.get((None, 'fill'), "None"))          fill = parse_color(attrs.get((None, 'fill'), "None"))
300          stroke = parse_color(attrs.get((None, 'stroke'), "#000000"))          stroke = parse_color(attrs.get((None, 'stroke'), "#000000"))
301          stroke_width = int(attrs.get((None, 'stroke_width'), "1"))          stroke_width = int(attrs.get((None, 'stroke_width'), "1"))
302          self.aLayer = layer_class(title,          if attrs.has_key((None, "shapestore")):
303                                    self.theSession.OpenShapefile(filename),              store = self.idmap[attrs[(None, "shapestore")]]
304            else:
305                store = self.theSession.OpenShapefile(filename)
306            self.aLayer = layer_class(title, store,
307                                    fill = fill, stroke = stroke,                                    fill = fill, stroke = stroke,
308                                    lineWidth = stroke_width)                                    lineWidth = stroke_width,
309                                      visible = visible)
         self.__projReceiver = self.aLayer  
310    
311      def end_layer(self, name, qname):      def end_layer(self, name, qname):
312          self.aMap.AddLayer(self.aLayer)          self.aMap.AddLayer(self.aLayer)
313          self.__projReceiver = None          self.aLayer = None
314    
315        def start_rasterlayer(self, name, qname, attrs, layer_class = RasterLayer):
316            title = self.encode(attrs.get((None, 'title'), ""))
317            filename = attrs.get((None, 'filename'), "")
318            filename = os.path.join(self.GetDirectory(), filename)
319            filename = self.encode(filename)
320            visible  = self.encode(attrs.get((None, 'visible'), "true")) != "false"
321    
322            self.aLayer = layer_class(title, filename, visible = visible)
323    
324        def end_rasterlayer(self, name, qname):
325            self.aMap.AddLayer(self.aLayer)
326            self.aLayer = None
327    
328      def start_classification(self, name, qname, attrs):      def start_classification(self, name, qname, attrs):
329          field = attrs.get((None, 'field'), None)          field = attrs.get((None, 'field'), None)
# Line 264  class SessionLoader(XMLReader): Line 345  class SessionLoader(XMLReader):
345    
346          self.aLayer.GetClassification().SetField(field)          self.aLayer.GetClassification().SetField(field)
347    
   
348      def end_classification(self, name, qname):      def end_classification(self, name, qname):
349          pass          pass
350    
351      def start_clnull(self, name, qname, attrs):      def start_clnull(self, name, qname, attrs):
352          self.cl_group = ClassGroupDefault()          self.cl_group = ClassGroupDefault()
353          self.cl_group.SetLabel(attrs.get((None, 'label'), ""))          self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
354          self.cl_prop = ClassGroupProperties()          self.cl_prop = ClassGroupProperties()
355    
356      def end_clnull(self, name, qname):      def end_clnull(self, name, qname):
# Line 281  class SessionLoader(XMLReader): Line 361  class SessionLoader(XMLReader):
361      def start_clpoint(self, name, qname, attrs):      def start_clpoint(self, name, qname, attrs):
362          attrib_value = attrs.get((None, 'value'), "0")          attrib_value = attrs.get((None, 'value'), "0")
363    
         #try:  
             #value  = Str2Num(attrib_value)  
         #except:  
             #value  = attrib_value  
   
364          value = self.conv(attrib_value)          value = self.conv(attrib_value)
365    
366          self.cl_group = ClassGroupSingleton(value)          self.cl_group = ClassGroupSingleton(value)
367          self.cl_group.SetLabel(attrs.get((None, 'label'), ""))          self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
368          self.cl_prop = ClassGroupProperties()          self.cl_prop = ClassGroupProperties()
369    
370    
# Line 300  class SessionLoader(XMLReader): Line 375  class SessionLoader(XMLReader):
375    
376      def start_clrange(self, name, qname, attrs):      def start_clrange(self, name, qname, attrs):
377    
378            range = attrs.get((None, 'range'), None)
379            # for backward compatibility (min/max are not saved)
380            min   = attrs.get((None, 'min'), None)
381            max   = attrs.get((None, 'max'), None)
382    
383          try:          try:
384              min = self.conv(attrs.get((None, 'min'), "0"))              if range is not None:
385              max = self.conv(attrs.get((None, 'max'), "0"))                  self.cl_group = ClassGroupRange(Range(range))
386              #min = Str2Num(attrs.get((None, 'min'), "0"))              elif min is not None and max is not None:
387              #max = Str2Num(attrs.get((None, 'max'), "0"))                  self.cl_group = ClassGroupRange(self.conv(min), self.conv(max))
388                else:
389                    self.cl_group = ClassGroupRange(Range(None))
390    
391          except ValueError:          except ValueError:
392              raise ValueError(_("Classification range is not a number!"))              raise ValueError(_("Classification range is not a number!"))
393    
         self.cl_group = ClassGroupRange(min, max)  
394          self.cl_group.SetLabel(attrs.get((None, 'label'), ""))          self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
395          self.cl_prop = ClassGroupProperties()          self.cl_prop = ClassGroupProperties()
396    
# Line 328  class SessionLoader(XMLReader): Line 410  class SessionLoader(XMLReader):
410      def end_cldata(self, name, qname):      def end_cldata(self, name, qname):
411          pass          pass
412    
     def start_table(self, name, qname, attrs):  
         #print "table title: %s" % attrs.get('title', None)  
         pass  
   
     def end_table(self, name, qname):  
         pass  
   
413      def start_labellayer(self, name, qname, attrs):      def start_labellayer(self, name, qname, attrs):
414          self.aLayer = self.aMap.LabelLayer()          self.aLayer = self.aMap.LabelLayer()
415    
416      def start_label(self, name, qname, attrs):      def start_label(self, name, qname, attrs):
417          x = float(attrs[(None, 'x')])          x = float(attrs[(None, 'x')])
418          y = float(attrs[(None, 'y')])          y = float(attrs[(None, 'y')])
419          text = attrs[(None, 'text')]          text = self.encode(attrs[(None, 'text')])
420          halign = attrs[(None, 'halign')]          halign = attrs[(None, 'halign')]
421          valign = attrs[(None, 'valign')]          valign = attrs[(None, 'valign')]
422          self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)          self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)

Legend:
Removed from v.744  
changed lines
  Added in v.1282

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26