source: josm/trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java@ 6968

Last change on this file since 6968 was 6968, checked in by stoecker, 10 years ago

also store untranslated imagery name

File size: 10.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.imagery;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.Utils.equal;
6
7import java.io.IOException;
8import java.io.InputStream;
9import java.util.ArrayList;
10import java.util.Arrays;
11import java.util.List;
12import java.util.Stack;
13
14import javax.xml.parsers.ParserConfigurationException;
15import javax.xml.parsers.SAXParserFactory;
16
17import org.openstreetmap.josm.Main;
18import org.openstreetmap.josm.data.imagery.ImageryInfo;
19import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
20import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
21import org.openstreetmap.josm.data.imagery.Shape;
22import org.openstreetmap.josm.io.MirroredInputStream;
23import org.openstreetmap.josm.io.UTFInputStreamReader;
24import org.xml.sax.Attributes;
25import org.xml.sax.InputSource;
26import org.xml.sax.SAXException;
27import org.xml.sax.helpers.DefaultHandler;
28
29public class ImageryReader {
30
31 private String source;
32
33 private enum State {
34 INIT, // initial state, should always be at the bottom of the stack
35 IMAGERY, // inside the imagery element
36 ENTRY, // inside an entry
37 ENTRY_ATTRIBUTE, // note we are inside an entry attribute to collect the character data
38 PROJECTIONS,
39 CODE,
40 BOUNDS,
41 SHAPE,
42 UNKNOWN, // element is not recognized in the current context
43 }
44
45 public ImageryReader(String source) {
46 this.source = source;
47 }
48
49 public List<ImageryInfo> parse() throws SAXException, IOException {
50 Parser parser = new Parser();
51 try {
52 SAXParserFactory factory = SAXParserFactory.newInstance();
53 factory.setNamespaceAware(true);
54 InputStream in = new MirroredInputStream(source);
55 InputSource is = new InputSource(UTFInputStreamReader.create(in));
56 factory.newSAXParser().parse(is, parser);
57 return parser.entries;
58 } catch (SAXException e) {
59 throw e;
60 } catch (ParserConfigurationException e) {
61 Main.error(e); // broken SAXException chaining
62 throw new SAXException(e);
63 }
64 }
65
66 private static class Parser extends DefaultHandler {
67 private StringBuffer accumulator = new StringBuffer();
68
69 private Stack<State> states;
70
71 List<ImageryInfo> entries;
72
73 /**
74 * Skip the current entry because it has mandatory attributes
75 * that this version of JOSM cannot process.
76 */
77 boolean skipEntry;
78
79 ImageryInfo entry;
80 ImageryBounds bounds;
81 Shape shape;
82 List<String> projections;
83
84 @Override public void startDocument() {
85 accumulator = new StringBuffer();
86 skipEntry = false;
87 states = new Stack<State>();
88 states.push(State.INIT);
89 entries = new ArrayList<ImageryInfo>();
90 entry = null;
91 bounds = null;
92 projections = null;
93 }
94
95 @Override
96 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
97 accumulator.setLength(0);
98 State newState = null;
99 switch (states.peek()) {
100 case INIT:
101 if (qName.equals("imagery")) {
102 newState = State.IMAGERY;
103 }
104 break;
105 case IMAGERY:
106 if (qName.equals("entry")) {
107 entry = new ImageryInfo();
108 skipEntry = false;
109 newState = State.ENTRY;
110 }
111 break;
112 case ENTRY:
113 if (Arrays.asList(new String[] {
114 "name",
115 "type",
116 "default",
117 "url",
118 "eula",
119 "min-zoom",
120 "max-zoom",
121 "attribution-text",
122 "attribution-url",
123 "logo-image",
124 "logo-url",
125 "terms-of-use-text",
126 "terms-of-use-url",
127 "country-code",
128 "icon",
129 }).contains(qName)) {
130 newState = State.ENTRY_ATTRIBUTE;
131 } else if (qName.equals("bounds")) {
132 try {
133 bounds = new ImageryBounds(
134 atts.getValue("min-lat") + "," +
135 atts.getValue("min-lon") + "," +
136 atts.getValue("max-lat") + "," +
137 atts.getValue("max-lon"), ",");
138 } catch (IllegalArgumentException e) {
139 break;
140 }
141 newState = State.BOUNDS;
142 } else if (qName.equals("projections")) {
143 projections = new ArrayList<String>();
144 newState = State.PROJECTIONS;
145 }
146 break;
147 case BOUNDS:
148 if (qName.equals("shape")) {
149 shape = new Shape();
150 newState = State.SHAPE;
151 }
152 break;
153 case SHAPE:
154 if (qName.equals("point")) {
155 try {
156 shape.addPoint(atts.getValue("lat"), atts.getValue("lon"));
157 } catch (IllegalArgumentException e) {
158 break;
159 }
160 }
161 break;
162 case PROJECTIONS:
163 if (qName.equals("code")) {
164 newState = State.CODE;
165 }
166 break;
167 }
168 /**
169 * Did not recognize the element, so the new state is UNKNOWN.
170 * This includes the case where we are already inside an unknown
171 * element, i.e. we do not try to understand the inner content
172 * of an unknown element, but wait till it's over.
173 */
174 if (newState == null) {
175 newState = State.UNKNOWN;
176 }
177 states.push(newState);
178 if (newState == State.UNKNOWN && equal(atts.getValue("mandatory"), "true")) {
179 skipEntry = true;
180 }
181 return;
182 }
183
184 @Override
185 public void characters(char[] ch, int start, int length) {
186 accumulator.append(ch, start, length);
187 }
188
189 @Override
190 public void endElement(String namespaceURI, String qName, String rqName) {
191 switch (states.pop()) {
192 case INIT:
193 throw new RuntimeException("parsing error: more closing than opening elements");
194 case ENTRY:
195 if (qName.equals("entry")) {
196 if (!skipEntry) {
197 entries.add(entry);
198 }
199 entry = null;
200 }
201 break;
202 case ENTRY_ATTRIBUTE:
203 if (qName.equals("name")) {
204 entry.setTranslatedName(accumulator.toString());
205 } else if (qName.equals("type")) {
206 boolean found = false;
207 for (ImageryType type : ImageryType.values()) {
208 if (equal(accumulator.toString(), type.getTypeString())) {
209 entry.setImageryType(type);
210 found = true;
211 break;
212 }
213 }
214 if (!found) {
215 skipEntry = true;
216 }
217 } else if (qName.equals("default")) {
218 if (accumulator.toString().equals("true")) {
219 entry.setDefaultEntry(true);
220 } else if (accumulator.toString().equals("false")) {
221 entry.setDefaultEntry(false);
222 } else {
223 skipEntry = true;
224 }
225 } else if (qName.equals("url")) {
226 entry.setUrl(accumulator.toString());
227 } else if (qName.equals("eula")) {
228 entry.setEulaAcceptanceRequired(accumulator.toString());
229 } else if (qName.equals("min-zoom") || qName.equals("max-zoom")) {
230 Integer val = null;
231 try {
232 val = Integer.parseInt(accumulator.toString());
233 } catch(NumberFormatException e) {
234 val = null;
235 }
236 if (val == null) {
237 skipEntry = true;
238 } else {
239 if (qName.equals("min-zoom")) {
240 entry.setDefaultMinZoom(val);
241 } else {
242 entry.setDefaultMaxZoom(val);
243 }
244 }
245 } else if (qName.equals("attribution-text")) {
246 entry.setAttributionText(accumulator.toString());
247 } else if (qName.equals("attribution-url")) {
248 entry.setAttributionLinkURL(accumulator.toString());
249 } else if (qName.equals("logo-image")) {
250 entry.setAttributionImage(accumulator.toString());
251 } else if (qName.equals("logo-url")) {
252 entry.setAttributionImageURL(accumulator.toString());
253 } else if (qName.equals("terms-of-use-text")) {
254 entry.setTermsOfUseText(accumulator.toString());
255 } else if (qName.equals("terms-of-use-url")) {
256 entry.setTermsOfUseURL(accumulator.toString());
257 } else if (qName.equals("country-code")) {
258 entry.setCountryCode(accumulator.toString());
259 } else if (qName.equals("icon")) {
260 entry.setIcon(accumulator.toString());
261 }
262 break;
263 case BOUNDS:
264 entry.setBounds(bounds);
265 bounds = null;
266 break;
267 case SHAPE:
268 bounds.addShape(shape);
269 shape = null;
270 break;
271 case CODE:
272 projections.add(accumulator.toString());
273 break;
274 case PROJECTIONS:
275 entry.setServerProjections(projections);
276 projections = null;
277 break;
278 }
279 }
280 }
281}
Note: See TracBrowser for help on using the repository browser.