1 |
# Copyright (C) 2001, 2002 by Intevation GmbH |
2 |
# Authors: |
3 |
# Jan-Oliver Wagner <[email protected]> |
4 |
# |
5 |
# This program is free software under the GPL (>=v2) |
6 |
# Read the file COPYING coming with GRASS for details. |
7 |
|
8 |
""" |
9 |
Parser for thuban session files. |
10 |
""" |
11 |
|
12 |
__version__ = "$Revision$" |
13 |
|
14 |
import sys, string, os |
15 |
from Thuban.Model.session import Session |
16 |
from Thuban.Model.map import Map |
17 |
from Thuban.Model.layer import Layer |
18 |
from Thuban.Model.color import Color |
19 |
from Thuban.Model.proj import Projection |
20 |
|
21 |
oldPython=0 |
22 |
|
23 |
if not sys.__dict__.has_key("version_info"): |
24 |
# We can assume to have python 1.5.2 or lower here now |
25 |
oldPython=1 |
26 |
|
27 |
if oldPython: |
28 |
try: |
29 |
from xml.sax.saxexts import make_parser |
30 |
from xml.sax.saxlib import HandlerBase |
31 |
from xml.sax import saxutils |
32 |
except ImportError: |
33 |
sys.stdout.write(("You need to have Python-XML installed or" |
34 |
" a modern Python!\n" |
35 |
"Check www.python.org/sigs/xml-sig/\n\n")) |
36 |
raise |
37 |
else: |
38 |
# Do the python 2.0 standard xml thing and map it on the old names |
39 |
import xml.sax |
40 |
import xml.sax.handler |
41 |
HandlerBase=xml.sax.handler.ContentHandler |
42 |
from xml.sax import make_parser |
43 |
|
44 |
class testSAXContentHandler(HandlerBase): |
45 |
# SAX compliant |
46 |
def characters(self, ch, start, length): |
47 |
pass |
48 |
|
49 |
def test_for_broken_SAX(): |
50 |
ch=testSAXContentHandler() |
51 |
try: |
52 |
xml.sax.parseString("""<?xml version="1.0"?> |
53 |
<child1 name="paul">Text goes here</child1> |
54 |
""",ch) |
55 |
except TypeError: |
56 |
return 1 |
57 |
return 0 |
58 |
|
59 |
|
60 |
def parse_color(color): |
61 |
""" |
62 |
Return the color object for the string color. Color may be either |
63 |
'None' or of the form '#RRGGBB' in the usual HTML color notation |
64 |
""" |
65 |
color = string.strip(color) |
66 |
if color == "None": |
67 |
result = None |
68 |
elif color[0] == '#': |
69 |
if len(color) == 7: |
70 |
r = string.atoi(color[1:3], 16) / 255.0 |
71 |
g = string.atoi(color[3:5], 16) / 255.0 |
72 |
b = string.atoi(color[5:7], 16) / 255.0 |
73 |
result = Color(r, g, b) |
74 |
else: |
75 |
raise ValueError("Invalid hexadecimal color specification %s" |
76 |
% color) |
77 |
else: |
78 |
raise ValueError("Invalid color specification %s" % color) |
79 |
return result |
80 |
|
81 |
|
82 |
class ProcessSession(HandlerBase): |
83 |
|
84 |
def __init__(self, directory): |
85 |
"""Inititialize the Sax handler. |
86 |
|
87 |
directory is the directory containing the session file. It's |
88 |
needed to interpret embedded relative filenames |
89 |
""" |
90 |
self.directory = directory |
91 |
self.chars = '' |
92 |
self.theSession = None |
93 |
self.aMap = None |
94 |
self.aLayer = None |
95 |
|
96 |
def startElement(self, name, attrs): |
97 |
if name == 'session': |
98 |
self.theSession = Session(attrs.get('title', None)) |
99 |
elif name == 'map': |
100 |
self.aMap = Map(attrs.get('title', None)) |
101 |
elif name == 'projection': |
102 |
self.ProjectionParams = [ ] |
103 |
elif name == 'parameter': |
104 |
s = attrs.get('value') |
105 |
s = str(s) # we can't handle unicode in proj |
106 |
self.ProjectionParams.append(s) |
107 |
elif name == 'layer': |
108 |
title = attrs.get('title', "") |
109 |
filename = attrs.get('filename', "") |
110 |
filename = os.path.join(self.directory, filename) |
111 |
fill = parse_color(attrs.get('fill', "None")) |
112 |
stroke = parse_color(attrs.get('stroke', "#000000")) |
113 |
stroke_width = int(attrs.get("stroke_width", "1")) |
114 |
self.aLayer = Layer(title, filename, fill = fill, stroke = stroke, |
115 |
stroke_width = stroke_width) |
116 |
elif name == 'table': |
117 |
print "table title: %s" % attrs.get('title', None) |
118 |
elif name == 'labellayer': |
119 |
self.aLayer = self.aMap.LabelLayer() |
120 |
elif name == 'label': |
121 |
x = float(attrs['x']) |
122 |
y = float(attrs['y']) |
123 |
text = attrs['text'] |
124 |
halign = attrs['halign'] |
125 |
valign = attrs['valign'] |
126 |
self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign) |
127 |
|
128 |
|
129 |
if not oldPython and test_for_broken_SAX(): |
130 |
# works with python 2.0, but is not SAX compliant |
131 |
def characters(self, ch): |
132 |
self.my_characters(ch) |
133 |
else: |
134 |
# SAX compliant |
135 |
def characters(self, ch, start, length): |
136 |
self.my_characters(ch[start:start+length]) |
137 |
|
138 |
def my_characters(self, ch): |
139 |
self.chars = self.chars + ch |
140 |
|
141 |
def endElement(self, name): |
142 |
# If it's not a parameter element, ignore it |
143 |
if name == 'session': |
144 |
#print "end of session" |
145 |
pass |
146 |
if name == 'map': |
147 |
self.theSession.AddMap(self.aMap) |
148 |
if name == 'projection': |
149 |
self.aMap.SetProjection(Projection(self.ProjectionParams)) |
150 |
if name == 'layer': |
151 |
self.aMap.AddLayer(self.aLayer) |
152 |
if name == 'table': |
153 |
#print "end of table" |
154 |
pass |
155 |
|
156 |
def load_session(filename): |
157 |
"""Load a Thuban session from the file object file""" |
158 |
dir = os.path.dirname(filename) |
159 |
file = open(filename) |
160 |
handler = ProcessSession(dir) |
161 |
|
162 |
if oldPython: |
163 |
parser = make_parser() |
164 |
parser.setDocumentHandler(handler) |
165 |
parser.setErrorHandler(saxutils.ErrorPrinter()) |
166 |
parser.parseFile(file) |
167 |
parser.close() |
168 |
else: |
169 |
xml.sax.parse(file,handler) |
170 |
session = handler.theSession |
171 |
# Newly loaded session aren't modified |
172 |
session.UnsetModified() |
173 |
|
174 |
return session |
175 |
|
176 |
if __name__ == "__main__": |
177 |
# find out the command to run |
178 |
if len(sys.argv) > 1: |
179 |
print "usage: cat <file> | " + sys.argv[0] |
180 |
else: |
181 |
parseSession(sys.stdin) |