/[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 6 by bh, Tue Aug 28 15:41:52 2001 UTC revision 614 by jonathan, Mon Apr 7 08:56:38 2003 UTC
# Line 1  Line 1 
1  # Copyright (C) 2001 by Intevation GmbH  # Copyright (C) 2001, 2002 by Intevation GmbH
2  # Authors:  # Authors:
3  # Jan-Oliver Wagner <[email protected]>  # Jan-Oliver Wagner <[email protected]>
4    # Bernhard Herzog <[email protected]>
5    # Jonathan Coles <[email protected]>
6  #  #
7  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
8  # Read the file COPYING coming with GRASS for details.  # Read the file COPYING coming with GRASS for details.
# Line 12  Parser for thuban session files. Line 14  Parser for thuban session files.
14  __version__ = "$Revision$"  __version__ = "$Revision$"
15    
16  import sys, string, os  import sys, string, os
17    
18    import xml.sax
19    import xml.sax.handler
20    from xml.sax import make_parser, ErrorHandler, SAXNotRecognizedException
21    
22    from Thuban import _
23    from Thuban.common import *
24    
25    from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
26         FIELDTYPE_STRING
27    
28  from Thuban.Model.session import Session  from Thuban.Model.session import Session
29  from Thuban.Model.map import Map  from Thuban.Model.map import Map
30  from Thuban.Model.layer import Layer  from Thuban.Model.layer import Layer
31  from Thuban.Model.color import Color  from Thuban.Model.color import Color
32  from Thuban.Model.proj import Projection  from Thuban.Model.proj import Projection
33    from Thuban.Model.classification import Classification, \
34  oldPython=0      ClassGroupDefault, ClassGroupSingleton, ClassGroupRange, ClassGroupMap, \
35        ClassGroupProperties
 if not sys.__dict__.has_key("version_info"):  
     # We can assume to have python 1.5.2 or lower here now  
     oldPython=1  
   
 if oldPython:  
     try:  
         from xml.sax.saxexts import make_parser  
         from xml.sax.saxlib import HandlerBase  
         from xml.sax import saxutils  
     except ImportError:  
         sys.stdout.write(("You need to have Python-XML installed or"  
                           " a modern Python!\n"  
                           "Check www.python.org/sigs/xml-sig/\n\n"))  
         raise  
 else:  
     # Do the python 2.0 standard xml thing and map it on the old names  
     import xml.sax  
     import xml.sax.handler  
     HandlerBase=xml.sax.handler.ContentHandler  
     from xml.sax import make_parser  
   
 class testSAXContentHandler(HandlerBase):  
 # SAX compliant  
     def characters(self, ch, start, length):  
         pass  
       
 def test_for_broken_SAX():  
     ch=testSAXContentHandler()  
     try:  
         xml.sax.parseString("""<?xml version="1.0"?>  
             <child1 name="paul">Text goes here</child1>  
         """,ch)  
     except TypeError:  
         return 1  
     return 0  
36    
37    
38  def parse_color(color):  def parse_color(color):
39      """      """Return the color object for the string color.
40      Return the color object for the string color. Color may be either  
41      'None' or of the form '#RRGGBB' in the usual HTML color notation      Color may be either 'None' or of the form '#RRGGBB' in the usual
42        HTML color notation
43      """      """
44      color = string.strip(color)      color = string.strip(color)
45      if color == "None":      if color == "None":
46          result = None          result = Color.Transparent
47      elif color[0] == '#':      elif color[0] == '#':
48          if len(color) == 7:          if len(color) == 7:
49              r = string.atoi(color[1:3], 16) / 255.0              r = string.atoi(color[1:3], 16) / 255.0
# Line 72  def parse_color(color): Line 51  def parse_color(color):
51              b = string.atoi(color[5:7], 16) / 255.0              b = string.atoi(color[5:7], 16) / 255.0
52              result = Color(r, g, b)              result = Color(r, g, b)
53          else:          else:
54              raise ValueError("Invalid hexadecimal color specification %s"              raise ValueError(_("Invalid hexadecimal color specification %s")
55                               % color)                               % color)
56      else:      else:
57          raise ValueError("Invalid color specification %s" % color)          raise ValueError(_("Invalid color specification %s") % color)
58      return result      return result
59    
60    
61  class ProcessSession(HandlerBase):  class ProcessSession(xml.sax.handler.ContentHandler):
62    
63        # Dictionary mapping element names (or (URI, element name) pairs for
64        # documents using namespaces) to method names. The methods should
65        # accept the same parameters as the startElement (or startElementNS)
66        # methods. The start_dispatcher is used by the default startElement
67        # and startElementNS methods to call a method for the open tag of an
68        # element.
69        start_dispatcher = {}
70    
71        # end_dispatcher works just like start_dispatcher but it's used by
72        # endElement and endElementNS. The method whose names it maps to
73        # should accept the same parameters as endElement and endElementNS.
74        end_dispatcher = {}
75    
76    
77      def __init__(self, directory):      def __init__(self, directory):
78          """Inititialize the Sax handler.          """Inititialize the Sax handler.
79    
80          directory is the directory containing the session file. It's          The directory parameter should be the directory containing the
81          needed to interpret embedded relative filenames          session file. It's needed to interpret embedded relative
82            filenames.
83          """          """
84          self.directory = directory          self.directory = directory
85          self.chars = ''          self.chars = ''
# Line 93  class ProcessSession(HandlerBase): Line 87  class ProcessSession(HandlerBase):
87          self.aMap = None          self.aMap = None
88          self.aLayer = None          self.aLayer = None
89    
90      def startElement(self, name, attrs):      def startElementNS(self, name, qname, attrs):
91          if name == 'session':          """Call the method given for name in self.start_dispatcher
92              self.theSession = Session(attrs.get('title', None))          """
93          elif name == 'map':          if name[0] is None:
94              self.aMap = Map(attrs.get('title', None))              method_name = self.start_dispatcher.get(name[1])
95          elif name == 'projection':          else:
96              self.ProjectionParams = [ ]              # Dispatch with namespace
97          elif name == 'parameter':              method_name = self.start_dispatcher.get(name)
98              self.ProjectionParams.append(attrs.get('value', None))          if method_name is not None:
99          elif name == 'layer':              getattr(self, method_name)(name, qname, attrs)
100              title = attrs.get('title', "")  
101              filename = attrs.get('filename', "")      def endElementNS(self, name, qname):
102              filename = os.path.join(self.directory, filename)          """Call the method given for name in self.end_dispatcher
103              fill = parse_color(attrs.get('fill', "None"))          """
104              stroke = parse_color(attrs.get('stroke', "#000000"))          if name[0] is None:
105              self.aLayer = Layer(title, filename, fill = fill, stroke = stroke)              method_name = self.end_dispatcher.get(name[1])
106          elif name == 'table':          else:
107              print "table title: %s" % attrs.get('title', None)              # Dispatch with namespace
108          elif name == 'labellayer':              method_name = self.end_dispatcher.get(name)
109              self.aLayer = self.aMap.LabelLayer()          if method_name is not None:
110          elif name == 'label':              getattr(self, method_name)(name, qname)
111              x = float(attrs['x'])  
112              y = float(attrs['y'])      def start_session(self, name, qname, attrs):
113              text = attrs['text']          self.theSession = Session(attrs.get((None, 'title'), None))
114              halign = attrs['halign']      start_dispatcher['session'] = "start_session"
115              valign = attrs['valign']  
116              self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)      def end_session(self, name, qname):
117                    pass
118        end_dispatcher['session'] = "end_session"
119      if not oldPython and test_for_broken_SAX():  
120          # works with python 2.0, but is not SAX compliant      def start_map(self, name, qname, attrs):
121          def characters(self, ch):          """Start a map."""
122              self.my_characters(ch)          self.aMap = Map(attrs.get((None, 'title'), None))
123      else:      start_dispatcher['map'] = "start_map"
124          # SAX compliant  
125          def characters(self, ch, start, length):      def end_map(self, name, qname):
126              self.my_characters(ch[start:start+length])          self.theSession.AddMap(self.aMap)
127        end_dispatcher['map'] = "end_map"
128      def my_characters(self, ch):  
129          self.chars = self.chars + ch      def start_projection(self, name, qname, attrs):
130            self.ProjectionParams = [ ]
131      def endElement(self, name):      start_dispatcher['projection'] = "start_projection"
132          # If it's not a parameter element, ignore it  
133          if name == 'session':      def end_projection(self, name, qname):
134              #print "end of session"          self.aMap.SetProjection(Projection(self.ProjectionParams))
135              pass      end_dispatcher['projection'] = "end_projection"
136          if name == 'map':  
137              self.theSession.AddMap(self.aMap)      def start_parameter(self, name, qname, attrs):
138          if name == 'projection':          s = attrs.get((None, 'value'))
139              self.aMap.SetProjection(Projection(self.ProjectionParams))          s = str(s) # we can't handle unicode in proj
140          if name == 'layer':          self.ProjectionParams.append(s)
141              self.aMap.AddLayer(self.aLayer)      start_dispatcher['parameter'] = "start_parameter"
142          if name == 'table':  
143              #print "end of table"      def start_layer(self, name, qname, attrs, layer_class = Layer):
144              pass          """Start a layer
145    
146            Instantiate a layer of class layer_class from the attributes in
147            attrs which may be a dictionary as well as the normal SAX attrs
148            object and bind it to self.aLayer.
149            """
150            title = attrs.get((None, 'title'), "")
151            filename = attrs.get((None, 'filename'), "")
152            filename = os.path.join(self.directory, filename)
153            fill = parse_color(attrs.get((None, 'fill'), "None"))
154            stroke = parse_color(attrs.get((None, 'stroke'), "#000000"))
155            stroke_width = int(attrs.get((None, 'stroke_width'), "1"))
156            self.aLayer = layer_class(title, filename, fill = fill,
157                                      stroke = stroke, lineWidth = stroke_width)
158        start_dispatcher['layer'] = "start_layer"
159    
160        def end_layer(self, name, qname):
161            self.aMap.AddLayer(self.aLayer)
162        end_dispatcher['layer'] = "end_layer"
163    
164        def start_classification(self, name, qname, attrs):
165            field = attrs.get((None, 'field'), None)
166    
167            fieldType = attrs.get((None, 'field_type'), None)
168            dbFieldType = self.aLayer.GetFieldType(field)
169    
170            if fieldType != dbFieldType:
171                raise ValueError(_("xml field type differs from database!"))
172    
173            # setup conversion routines depending on the kind of data
174            # we will be seeing later on
175            if fieldType == FIELDTYPE_STRING:
176                self.conv = str
177            elif fieldType == FIELDTYPE_INT:
178                self.conv = lambda p: int(float(p))
179            elif fieldType == FIELDTYPE_DOUBLE:
180                self.conv = float
181    
182            self.aLayer.GetClassification().SetField(field)
183    
184        start_dispatcher['classification'] = "start_classification"
185    
186        def end_classification(self, name, qname):
187            pass
188        end_dispatcher['classification'] = "end_classification"
189    
190        def start_clnull(self, name, qname, attrs):
191            self.cl_group = ClassGroupDefault()
192            self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
193            self.cl_prop = ClassGroupProperties()
194        start_dispatcher['clnull'] = "start_clnull"
195    
196        def end_clnull(self, name, qname):
197            self.cl_group.SetProperties(self.cl_prop)
198            self.aLayer.GetClassification().SetDefaultGroup(self.cl_group)
199            del self.cl_group, self.cl_prop
200        end_dispatcher['clnull'] = "end_clnull"
201    
202        def start_clpoint(self, name, qname, attrs):
203            attrib_value = attrs.get((None, 'value'), "0")
204    
205            #try:
206                #value  = Str2Num(attrib_value)
207            #except:
208                #value  = attrib_value
209    
210            value = self.conv(attrib_value)
211    
212            self.cl_group = ClassGroupSingleton(value)
213            self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
214            self.cl_prop = ClassGroupProperties()
215    
216        start_dispatcher['clpoint'] = "start_clpoint"
217    
218        def end_clpoint(self, name, qname):
219            self.cl_group.SetProperties(self.cl_prop)
220            self.aLayer.GetClassification().AppendGroup(self.cl_group)
221            del self.cl_group, self.cl_prop
222        end_dispatcher['clpoint'] = "end_clpoint"
223    
224        def start_clrange(self, name, qname, attrs):
225    
226            try:
227                min = self.conv(attrs.get((None, 'min'), "0"))
228                max = self.conv(attrs.get((None, 'max'), "0"))
229                #min = Str2Num(attrs.get((None, 'min'), "0"))
230                #max = Str2Num(attrs.get((None, 'max'), "0"))
231            except ValueError:
232                raise ValueError(_("Classification range is not a number!"))
233    
234            self.cl_group = ClassGroupRange(min, max)
235            self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
236            self.cl_prop = ClassGroupProperties()
237    
238        start_dispatcher['clrange'] = "start_clrange"
239    
240        def end_clrange(self, name, qname):
241            self.cl_group.SetProperties(self.cl_prop)
242            self.aLayer.GetClassification().AppendGroup(self.cl_group)
243            del self.cl_group, self.cl_prop
244        end_dispatcher['clrange'] = "end_clrange"
245    
246        def start_cldata(self, name, qname, attrs):
247            self.cl_prop.SetLineColor(
248                parse_color(attrs.get((None, 'stroke'), "None")))
249            self.cl_prop.SetLineWidth(
250                int(attrs.get((None, 'stroke_width'), "0")))
251            self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))
252        start_dispatcher['cldata'] = "start_cldata"
253    
254        def end_cldata(self, name, qname):
255            pass
256        end_dispatcher['cldata'] = "end_cldata"
257    
258        def start_table(self, name, qname, attrs):
259            #print "table title: %s" % attrs.get('title', None)
260            pass
261        start_dispatcher['table'] = "start_table"
262    
263        def end_table(self, name, qname):
264            pass
265        end_dispatcher['table'] = "end_table"
266    
267        def start_labellayer(self, name, qname, attrs):
268            self.aLayer = self.aMap.LabelLayer()
269        start_dispatcher['labellayer'] = "start_labellayer"
270    
271        def start_label(self, name, qname, attrs):
272            x = float(attrs[(None, 'x')])
273            y = float(attrs[(None, 'y')])
274            text = attrs[(None, 'text')]
275            halign = attrs[(None, 'halign')]
276            valign = attrs[(None, 'valign')]
277            self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)
278        start_dispatcher['label'] = "start_label"
279    
280        def characters(self, chars):
281            pass
282    
283    
284  def load_session(filename):  def load_session(filename):
285      """Load a Thuban session from the file object file"""      """Load a Thuban session from the file object file"""
# Line 155  def load_session(filename): Line 287  def load_session(filename):
287      file = open(filename)      file = open(filename)
288      handler = ProcessSession(dir)      handler = ProcessSession(dir)
289    
290      if oldPython:      parser = make_parser()
291          parser = make_parser()      parser.setContentHandler(handler)
292          parser.setDocumentHandler(handler)      parser.setErrorHandler(ErrorHandler())
293          parser.setErrorHandler(saxutils.ErrorPrinter())      parser.setFeature(xml.sax.handler.feature_namespaces, 1)
294          parser.parseFile(file)  
295          parser.close()      #
296      else:      # Well, this isn't pretty, but it appears that if you
297          xml.sax.parse(file,handler)      # use Python 2.2 without the site-package _xmlplus then
298        # the following will fail, and without them it will work.
299        # However, if you do have the site-package and you don't
300        # call these functions, the reader raises an exception
301        #
302        # The reason we set these to 0 in the first place is
303        # because there is an unresolved issue with external
304        # entities causing an exception in the reader
305        #
306        try:
307            parser.setFeature(xml.sax.handler.feature_validation, 0)
308            parser.setFeature(xml.sax.handler.feature_external_ges, 0)
309            parser.setFeature(xml.sax.handler.feature_external_pes, 0)
310        except SAXNotRecognizedException:
311            pass
312    
313        parser.parse(file)
314    
315      session = handler.theSession      session = handler.theSession
316      # Newly loaded session aren't modified      # Newly loaded session aren't modified
317      session.UnsetModified()      session.UnsetModified()
318    
319      return session      return session
320    
 if __name__ == "__main__":  
     # find out the command to run  
     if len(sys.argv) > 1:  
         print "usage: cat <file> | " + sys.argv[0]  
     else:  
         parseSession(sys.stdin)  

Legend:
Removed from v.6  
changed lines
  Added in v.614

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26