1
2
3
4
5
6
7
8
9
10
11 package nl.javel.gisbeans.map.mapfile;
12
13 import java.awt.Color;
14 import java.awt.Dimension;
15 import java.awt.Font;
16 import java.awt.geom.Rectangle2D;
17 import java.io.IOException;
18 import java.net.URL;
19 import java.util.ArrayList;
20 import java.util.Iterator;
21
22 import nl.javel.gisbeans.io.esri.ShapeFile;
23 import nl.javel.gisbeans.map.AbstractAttribute;
24 import nl.javel.gisbeans.map.Attribute;
25 import nl.javel.gisbeans.map.AttributeInterface;
26 import nl.javel.gisbeans.map.Image;
27 import nl.javel.gisbeans.map.ImageInterface;
28 import nl.javel.gisbeans.map.Layer;
29 import nl.javel.gisbeans.map.LayerInterface;
30 import nl.javel.gisbeans.map.Legend;
31 import nl.javel.gisbeans.map.LegendInterface;
32 import nl.javel.gisbeans.map.Map;
33 import nl.javel.gisbeans.map.MapInterface;
34 import nl.javel.gisbeans.map.ReferenceMap;
35 import nl.javel.gisbeans.map.ReferenceMapInterface;
36 import nl.javel.gisbeans.map.Scalebar;
37 import nl.javel.gisbeans.map.ScalebarInterface;
38 import nl.javel.gisbeans.map.StaticAttribute;
39 import nl.tudelft.simulation.language.io.URLResource;
40
41 import org.apache.xerces.parsers.DOMParser;
42 import org.jdom.Element;
43 import org.jdom.Namespace;
44 import org.jdom.input.DOMBuilder;
45 import org.w3c.dom.Document;
46 import org.xml.sax.SAXException;
47 import org.xml.sax.SAXParseException;
48 import org.xml.sax.helpers.DefaultHandler;
49
50 /***
51 * This class parses XML-mapfiles and constructs appropriate map objects. <br>
52 * Validation is set with the system property
53 * nl.javel.gisbeans.map.mapfile.validate =[true|false] and the xmlschema is set
54 * with the systemproperty nl.javel.gisbeans.map.mapfile.schema = [file]
55 * <p>
56 * (c) copyright 2002-2004 <a href="http://www.javel.nl">Javel b.v. </a>, the
57 * Netherlands.
58 * <p>
59 * License of use: <a href="http://www.gnu.org/copyleft/gpl.html">General Public
60 * License (GPL) </a>, no warranty <br>
61 *
62 * @version 2.0 28.04.04
63 * <p>
64 * @author <a href="mailto:paul.jacobs@javel.nl">Paul Jacobs </a><a
65 * href="http://www.tbm.tudelft.nl/webstaf/peterja/index.htm">Peter
66 * Jacobs </a>
67 */
68 public final class MapFileXMLParser
69 {
70 /*** the default mapfile */
71 public static final URL MAPFILE_SCHEMA = URLResource
72 .getResource("/nl/javel/gisbeans/map/mapfile/mapfile.xsd");
73
74 /***
75 * parses a Mapfile URL to a mapFile.
76 *
77 * @param url the mapfile url.
78 * @return MapInterface the parsed mapfile.
79 * @throws IOException on failure.
80 */
81 public static MapInterface parseMapFile(final URL url) throws IOException
82 {
83 try
84 {
85 Map map = new Map();
86 DOMParser domParser = new DOMParser();
87 domParser
88 .setFeature("http://xml.org/sax/features/validation", true);
89 domParser.setFeature(
90 "http://apache.org/xml/features/validation/schema", true);
91 domParser
92 .setProperty(
93 "http://apache.org/xml/properties/schema/external-schemaLocation",
94 "http://www.javel.nl/gisbeans "
95 + MAPFILE_SCHEMA.toExternalForm());
96 domParser.setErrorHandler(new ValidHandler());
97 domParser.parse(url.toExternalForm());
98 Document document = domParser.getDocument();
99 DOMBuilder builder = new DOMBuilder();
100 org.jdom.Document jdomDocument = builder.build(document);
101 Element xmlMapFileElement = jdomDocument.getRootElement();
102 Element element = null;
103 Namespace nameSpace = xmlMapFileElement.getNamespace();
104 map.setName(xmlMapFileElement.getChildText("name"));
105 if ((element = xmlMapFileElement.getChild("units")) != null)
106 {
107 map.setUnits(parseUnits(element));
108 }
109 double[] extent = new double[4];
110 extent[MapInterface.MINX] = new Double(xmlMapFileElement.getChild(
111 "extent").getChildText("minX")).doubleValue();
112 extent[MapInterface.MINY] = new Double(xmlMapFileElement.getChild(
113 "extent").getChildText("minY")).doubleValue();
114 extent[MapInterface.MAXX] = new Double(xmlMapFileElement.getChild(
115 "extent").getChildText("maxX")).doubleValue();
116 extent[MapInterface.MAXY] = new Double(xmlMapFileElement.getChild(
117 "extent").getChildText("maxY")).doubleValue();
118 map.setExtent(new Rectangle2D.Double(extent[0], extent[1],
119 (extent[2] - extent[0]), (extent[3] - extent[1])));
120 if ((element = xmlMapFileElement.getChild("image", nameSpace)) != null)
121 {
122 map.setImage(parseImage(element, nameSpace));
123 }
124 if ((element = xmlMapFileElement
125 .getChild("referenceMap", nameSpace)) != null)
126 {
127 map.setReferenceMap(parseReferenceMap(element));
128 }
129 java.util.List layerElements = xmlMapFileElement.getChildren(
130 "layer", nameSpace);
131 ArrayList layers = new ArrayList();
132 for (Iterator iterator = layerElements.iterator(); iterator
133 .hasNext();)
134 {
135 Element layerElement = (Element) iterator.next();
136 layers.add(parseLayer(layerElement));
137 }
138 map.setLayers(layers);
139 return map;
140 } catch (Exception exception)
141 {
142 throw new IOException(exception.getMessage());
143 }
144 }
145
146 /***
147 * returns the columnNumber
148 *
149 * @param columnNames the names
150 * @param columnName the name
151 * @return the number
152 */
153 private static int getColumnNumber(String[] columnNames, String columnName)
154 {
155 for (int i = 0; i < columnNames.length; i++)
156 {
157 if (columnNames[i].equalsIgnoreCase(columnName))
158 return i;
159 }
160 return -1;
161 }
162
163 /***
164 * parses a xml-element representing an attribute
165 *
166 * @param element The j-dom element
167 * @param layer the layer.
168 * @return AttributeInterface value
169 * @throws IOException
170 */
171 private static AttributeInterface parseAttribute(Element element,
172 LayerInterface layer) throws IOException
173 {
174 AbstractAttribute result = null;
175 if (element.getChild("textColumn") != null)
176 {
177 int textColumnNumber = MapFileXMLParser.getColumnNumber(layer
178 .getDataSource().getColumnNames(), element
179 .getChildText("textColumn"));
180 int angleColumnNumber = -1;
181 if (element.getChild("degreesColumn") != null)
182 {
183 angleColumnNumber = MapFileXMLParser.getColumnNumber(layer
184 .getDataSource().getColumnNames(), element
185 .getChildText("degreesColumn"));
186 result = new Attribute(layer, Attribute.DEGREES,
187 angleColumnNumber, textColumnNumber);
188 } else if (element.getChild("radiansColumn") != null)
189 {
190 angleColumnNumber = MapFileXMLParser.getColumnNumber(layer
191 .getDataSource().getColumnNames(), element
192 .getChildText("radiansColumn"));
193 result = new Attribute(layer, Attribute.RADIANS,
194 angleColumnNumber, textColumnNumber);
195 } else
196 {
197 result = new Attribute(layer, Attribute.RADIANS, -1,
198 textColumnNumber);
199 }
200 } else
201 {
202 double angle = 0.0;
203 if (element.getChild("degrees") != null)
204 {
205 angle = Math.toRadians(new Double(element
206 .getChildText("degrees")).doubleValue());
207 }
208 if (element.getChild("radians") != null)
209 {
210 angle = new Double(element.getChildText("radians"))
211 .doubleValue();
212 }
213 String value = "";
214 if (element.getChild("text") != null)
215 {
216 value = element.getChildText("text");
217 }
218 result = new StaticAttribute(layer, angle, value);
219 }
220 if (element.getChild("minScale") != null)
221 result.setMinScale(new Integer(element.getChildText("minScale"))
222 .intValue());
223 else
224 result.setMinScale(layer.getMinScale());
225 if (element.getChild("maxScale") != null)
226 result.setMaxScale(new Integer(element.getChildText("maxScale"))
227 .intValue());
228 else
229 result.setMaxScale(layer.getMaxScale());
230 if (element.getChild("position") != null)
231 result.setPosition(parsePosition(element.getChild("position")));
232 if (element.getChild("font") != null)
233 {
234 result.setFont(parseFont(element.getChild("font")));
235 result.setFontColor(parseColor(element.getChild("font").getChild(
236 "fontColor")));
237 }
238 return result;
239 }
240
241 /***
242 * parses a xml-element representing a boolean
243 *
244 * @param element The j-dom element
245 * @return Boolean value
246 * @throws IOException
247 */
248 private static boolean parseBoolean(Element element) throws IOException
249 {
250 try
251 {
252 boolean result = false;
253 if (element.getText().equals("true"))
254 result = true;
255 return result;
256 } catch (Exception exception)
257 {
258 throw new IOException(exception.getMessage());
259 }
260 }
261
262 /***
263 * parses a xml-element representing a Color
264 *
265 * @param element The j-dom element
266 * @return Color of element
267 * @throws IOException
268 */
269 private static Color parseColor(Element element) throws IOException
270 {
271 try
272 {
273 int r = new Integer(element.getChildText("r")).intValue();
274 int g = new Integer(element.getChildText("g")).intValue();
275 int b = new Integer(element.getChildText("b")).intValue();
276 if (element.getChildText("a") != null)
277 {
278 int a = new Integer(element.getChildText("a")).intValue();
279 return new java.awt.Color(r, g, b, a);
280 }
281 return new java.awt.Color(r, g, b);
282 } catch (Exception exception)
283 {
284 throw new IOException(exception.getMessage());
285 }
286 }
287
288 /***
289 * parses a xml-element representing a Dimension
290 *
291 * @param element The j-dom element
292 * @return Dimension of element
293 * @throws IOException
294 */
295 private static Dimension parseDimension(Element element) throws IOException
296 {
297 try
298 {
299 int height = new Integer(element.getChildText("height")).intValue();
300 int width = new Integer(element.getChildText("width")).intValue();
301 return new Dimension(width, height);
302 } catch (Exception exception)
303 {
304 throw new IOException(exception.getMessage());
305 }
306 }
307
308 /***
309 * parses a xml-element representing a double[]
310 *
311 * @param element The j-dom element
312 * @return Value of extent
313 * @throws IOException
314 */
315 private static double[] parseExtent(Element element) throws IOException
316 {
317 try
318 {
319 double[] result = new double[4];
320 result[MapInterface.MINX] = new Double(element.getChildText("minX"))
321 .doubleValue();
322 result[MapInterface.MINY] = new Double(element.getChildText("minY"))
323 .doubleValue();
324 result[MapInterface.MAXY] = new Double(element.getChildText("maxX"))
325 .doubleValue();
326 result[MapInterface.MAXY] = new Double(element.getChildText("maxY"))
327 .doubleValue();
328 return result;
329 } catch (Exception exception)
330 {
331 throw new IOException(exception.getMessage());
332 }
333 }
334
335 /***
336 * parses a xml-element representing a font
337 *
338 * @param element The j-dom element
339 * @return the font
340 * @throws IOException
341 */
342 private static Font parseFont(Element element) throws IOException
343 {
344 try
345 {
346 String fontName = element.getChildText("fontName");
347 int fontSize = new Integer(element.getChildText("fontSize"))
348 .intValue();
349 return new Font(fontName, Font.TRUETYPE_FONT, fontSize);
350 } catch (Exception exception)
351 {
352 throw new IOException(exception.getMessage());
353 }
354 }
355
356 /***
357 * parses a xml-element representing the Image
358 *
359 * @param element The j-dom element
360 * @param nameSpace The gisbeans namespace
361 * @return Value of image
362 * @throws IOException
363 */
364 private static ImageInterface parseImage(org.jdom.Element element,
365 Namespace nameSpace) throws IOException
366 {
367 ImageInterface result = new Image();
368 try
369 {
370 if (element.getChild("backgroundColor") != null)
371 result.setBackgroundColor(parseColor(element
372 .getChild("backgroundColor")));
373 if (element.getChild("legend", nameSpace) != null)
374 result.setLegend(parseLegend(element.getChild("legend",
375 nameSpace)));
376 if (element.getChild("scalebar", nameSpace) != null)
377 result.setScalebar(parseScalebar(element.getChild("scalebar",
378 nameSpace)));
379 if (element.getChild("size") != null)
380 result.setSize(parseDimension(element.getChild("size")));
381 return result;
382 } catch (Exception exception)
383 {
384 throw new IOException(exception.getMessage());
385 }
386 }
387
388 /***
389 * parses a xml-element representing a Layer
390 *
391 * @param element The j-dom element
392 * @return Layer of element
393 * @throws IOException
394 */
395 private static LayerInterface parseLayer(Element element)
396 throws IOException
397 {
398 LayerInterface result = new Layer();
399 try
400 {
401 if (element.getChild("color") != null)
402 result.setColor(parseColor(element.getChild("color")));
403 if (element.getChild("data").getChild("shapeFile") != null)
404 {
405 String resource = element.getChild("data").getChildText(
406 "shapeFile");
407 ShapeFile dataSource = new ShapeFile(URLResource
408 .getResource(resource));
409 if (element.getAttribute("cache") != null
410 && element.getAttribute("cache").getValue().equals(
411 "false"))
412 {
413 dataSource.setCache(false);
414 } else
415 {
416 dataSource.setCache(true);
417 }
418 result.setDataSource(dataSource);
419 }
420 if (element.getChild("data").getChild("SDI") != null)
421 {
422 throw new IOException("SDI not yet supported");
423 }
424 if (element.getChild("maxScale") != null)
425 result
426 .setMaxScale(new Integer(element
427 .getChildText("maxScale")).intValue());
428 if (element.getChild("minScale") != null)
429 result
430 .setMinScale(new Integer(element
431 .getChildText("minScale")).intValue());
432 result.setName(element.getChildText("name"));
433 if (element.getChild("outlineColor") != null)
434 result.setOutlineColor(parseColor(element
435 .getChild("outlineColor")));
436 if (element.getChild("status") != null)
437 result.setStatus(parseBoolean(element.getChild("status")));
438 if (element.getChild("transform") != null)
439 result
440 .setTransform(parseBoolean(element
441 .getChild("transform")));
442 java.util.List attributesElements = element
443 .getChildren("attribute");
444 ArrayList attributes = new ArrayList();
445 for (Iterator iterator = attributesElements.iterator(); iterator
446 .hasNext();)
447 {
448 Element attributeElement = (Element) iterator.next();
449 attributes.add(parseAttribute(attributeElement, result));
450 }
451 result.setAttributes(attributes);
452 return result;
453 } catch (Exception exception)
454 {
455 exception.printStackTrace();
456 throw new IOException(exception.getMessage());
457 }
458 }
459
460 /***
461 * parses a xml-element representing a Legend
462 *
463 * @param element The j-dom element
464 * @return Legend of element
465 * @throws IOException
466 */
467 private static LegendInterface parseLegend(Element element)
468 throws IOException
469 {
470 LegendInterface result = new Legend();
471 try
472 {
473 if (element.getChild("backgroundColor") != null)
474 result.setOutlineColor(parseColor(element
475 .getChild("backgroundColor")));
476 if (element.getChild("embed") != null)
477 result.setEmbed(parseBoolean(element.getChild("embed")));
478 if (element.getChild("font") != null)
479 {
480 result.setFont(parseFont(element.getChild("font")));
481 result.setFontColor(parseColor(element.getChild("font")
482 .getChild("fontColor")));
483 }
484 if (element.getChild("outlineColor") != null)
485 result.setOutlineColor(parseColor(element
486 .getChild("outlineColor")));
487 if (element.getChild("position") != null)
488 result.setPosition(parsePosition(element.getChild("position")));
489 if (element.getChild("size") != null)
490 result.setSize(parseDimension(element.getChild("size")));
491 if (element.getChild("status") != null)
492 result.setStatus(parseBoolean(element.getChild("status")));
493 return result;
494 } catch (Exception exception)
495 {
496 throw new IOException(exception.getMessage());
497 }
498 }
499
500 /***
501 * parses a xml-element representing a Position
502 *
503 * @param element The j-dom element
504 * @return Position of element
505 */
506 private static int parsePosition(org.jdom.Element element)
507 {
508 if (element.getText().equals("ul"))
509 return MapInterface.UL;
510 if (element.getText().equals("uc"))
511 return MapInterface.UC;
512 if (element.getText().equals("ur"))
513 return MapInterface.UR;
514 if (element.getText().equals("cl"))
515 return MapInterface.CL;
516 if (element.getText().equals("cc"))
517 return MapInterface.CC;
518 if (element.getText().equals("cr"))
519 return MapInterface.CR;
520 if (element.getText().equals("ll"))
521 return MapInterface.LL;
522 if (element.getText().equals("lc"))
523 return MapInterface.LC;
524 if (element.getText().equals("lr"))
525 return MapInterface.LR;
526 return MapInterface.UL;
527 }
528
529 /***
530 * parses a xml-element representing a ReferenceMap
531 *
532 * @param element The j-dom element
533 * @return ReferenceMap of element
534 * @throws IOException
535 */
536 private static ReferenceMapInterface parseReferenceMap(
537 org.jdom.Element element) throws IOException
538 {
539 ReferenceMapInterface result = new ReferenceMap();
540 try
541 {
542 result.setImage(new java.net.URL(element.getChildText("image")));
543 result.setExtent(parseExtent(element.getChild("extent")));
544 if (element.getChild("outlineColor") != null)
545 result.setOutlineColor(parseColor(element
546 .getChild("outlineColor")));
547 if (element.getChild("size") != null)
548 result.setSize(parseDimension(element.getChild("size")));
549 if (element.getChild("status") != null)
550 result.setStatus(parseBoolean(element.getChild("status")));
551 return result;
552 } catch (Exception exception)
553 {
554 throw new IOException(exception.getMessage());
555 }
556 }
557
558 /***
559 * parses a xml-element representing a Scalebar
560 *
561 * @param element The j-dom element
562 * @return Scalebar of element
563 * @throws IOException
564 */
565 private static ScalebarInterface parseScalebar(org.jdom.Element element)
566 throws IOException
567 {
568 ScalebarInterface result = new Scalebar();
569 try
570 {
571 if (element.getChild("backgroundColor") != null)
572 result.setBackgroundColor(parseColor(element
573 .getChild("backgroundColor")));
574 if (element.getChild("color") != null)
575 result.setColor(parseColor(element.getChild("color")));
576 if (element.getChild("embed") != null)
577 result.setEmbed(parseBoolean(element.getChild("embed")));
578 if (element.getChild("font") != null)
579 {
580 result.setFont(parseFont(element.getChild("font")));
581 result.setFontColor(parseColor(element.getChild("font")
582 .getChild("fontColor")));
583 }
584 if (element.getChild("intervals") != null)
585 result.setIntervals(new Integer(element
586 .getChildText("intervals")).intValue());
587 if (element.getChild("position") != null)
588 result.setPosition(parsePosition(element.getChild("position")));
589 if (element.getChild("size") != null)
590 result.setSize(parseDimension(element.getChild("size")));
591 if (element.getChild("status") != null)
592 result.setStatus(parseBoolean(element.getChild("status")));
593 if (element.getChild("units") != null)
594 result.setUnits(parseUnits(element.getChild("units")));
595 return result;
596 } catch (Exception exception)
597 {
598 throw new IOException(exception.getMessage());
599 }
600 }
601
602 /***
603 * parses a xml-element representing a Units
604 *
605 * @param element The j-dom element
606 * @return Units of element
607 */
608 private static int parseUnits(org.jdom.Element element)
609 {
610 if (element.getText().equals("feet"))
611 return MapInterface.FEET;
612 if (element.getText().equals("dd"))
613 return MapInterface.DD;
614 if (element.getText().equals("inches"))
615 return MapInterface.INCHES;
616 if (element.getText().equals("kilometers"))
617 return MapInterface.KILOMETERS;
618 if (element.getText().equals("meters"))
619 return MapInterface.METERS;
620 if (element.getText().equals("miles"))
621 return MapInterface.MILES;
622 return MapInterface.METERS;
623 }
624
625 /***
626 * The validationHandler.
627 */
628 private static class ValidHandler extends DefaultHandler
629 {
630 /***
631 * format the exception with line number, column number, etc.
632 *
633 * @param exception
634 * @return
635 */
636 private String formatError(SAXParseException exception)
637 {
638 return "SAXParseException: \nsystemId=" + exception.getSystemId()
639 + "\npublicId=" + exception.getSystemId() + "\nMessage="
640 + exception.getMessage() + "\nline,col="
641 + exception.getLineNumber() + ","
642 + exception.getColumnNumber();
643 }
644
645 /***
646 * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
647 */
648 public void error(SAXParseException e) throws SAXException
649 {
650 throw new SAXException(formatError(e));
651 }
652
653 /***
654 * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
655 */
656 public void fatalError(SAXParseException e) throws SAXException
657 {
658 throw new SAXException(formatError(e));
659 }
660 }
661 }