2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
7 package gov
.nasa
.worldwind
;
9 import gov
.nasa
.worldwind
.geom
.*;
13 import javax
.xml
.parsers
.*;
14 import javax
.xml
.namespace
.*;
20 * @version $Id: GeoRSSParser.java 1686 2007-05-02 21:58:49Z tgaskins $
23 public class GeoRSSParser
25 public static final String GEORSS_URI
= "http://www.georss.org/georss";
26 public static final String GML_URI
= "http://www.opengis.net/gml";
28 public static List
<Renderable
> parseFragment(String fragmentString
, NamespaceContext nsc
)
30 return parseShapes(fixNamespaceQualification(fragmentString
));
33 public static List
<Renderable
> parseShapes(String docString
)
35 if (docString
== null)
37 String message
= WorldWind
.retrieveErrMsg("nullValue.StringIsNull");
38 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
39 throw new IllegalArgumentException(message
);
42 if (docString
.length() < 1) // avoid empty strings
47 DocumentBuilderFactory docBuilderFactory
= DocumentBuilderFactory
.newInstance();
48 docBuilderFactory
.setNamespaceAware(true);
49 DocumentBuilder docBuilder
= docBuilderFactory
.newDocumentBuilder();
50 Document doc
= docBuilder
.parse(new InputSource(new StringReader(docString
)));
52 List
<Renderable
> shapes
= parseShapes(doc
);
54 if (shapes
== null || shapes
.size() < 1)
56 String message
= WorldWind
.retrieveErrMsg("GeoRSS.NoShapes") + docString
;
57 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
63 catch (ParserConfigurationException e
)
65 String message
= WorldWind
.retrieveErrMsg("GeoRSS.ParserConfigurationException");
66 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
, e
);
67 throw new WWRuntimeException(message
, e
);
71 String message
= WorldWind
.retrieveErrMsg("GeoRSS.IOExceptionParsing") + docString
;
72 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
, e
);
73 throw new WWRuntimeException(message
, e
);
75 catch (SAXException e
)
77 String message
= WorldWind
.retrieveErrMsg("GeoRSS.IOExceptionParsing") + docString
;
78 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
, e
);
79 throw new WWRuntimeException(message
, e
);
83 private static String
fixNamespaceQualification(String xmlString
)
85 String lcaseString
= xmlString
.toLowerCase();
86 StringBuffer qualifiers
= new StringBuffer();
88 if (lcaseString
.contains("georss:") && !lcaseString
.contains(GEORSS_URI
))
90 qualifiers
.append(" xmlns:georss=\"");
91 qualifiers
.append(GEORSS_URI
);
92 qualifiers
.append("\"");
95 if (lcaseString
.contains("gml:") && !lcaseString
.contains(GML_URI
))
97 qualifiers
.append(" xmlns:gml=\"");
98 qualifiers
.append(GML_URI
);
99 qualifiers
.append("\"");
102 if (qualifiers
.length() > 0)
104 StringBuffer sb
= new StringBuffer();
105 sb
.append("<wwdummyelement");
106 sb
.append(qualifiers
);
108 sb
.append(xmlString
);
109 sb
.append("</wwdummyelement>");
111 return sb
.toString();
117 private static String
surroundWithNameSpaces(String docString
)
119 StringBuffer sb
= new StringBuffer();
120 sb
.append("<wwdummyelement");
121 sb
.append(" xmlns:georss=\"");
122 sb
.append(GEORSS_URI
);
124 sb
.append(" xmlns:gml=\"");
128 sb
.append(docString
);
129 sb
.append("</wwdummyelement>");
130 // System.out.println(sb.toString());
132 return sb
.toString();
135 public static List
<Renderable
> parseShapes(File file
)
139 String message
= WorldWind
.retrieveErrMsg("nullValue.FileIsNull");
140 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
141 throw new IllegalArgumentException(message
);
146 DocumentBuilderFactory docBuilderFactory
= DocumentBuilderFactory
.newInstance();
147 docBuilderFactory
.setNamespaceAware(false);
148 DocumentBuilder docBuilder
= docBuilderFactory
.newDocumentBuilder();
149 Document doc
= docBuilder
.parse(file
);
151 List
<Renderable
> shapes
= parseShapes(doc
);
153 if (shapes
== null || shapes
.size() < 1)
155 String message
= WorldWind
.retrieveErrMsg("GeoRSS.NoShapes") + file
.getPath();
156 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
162 catch (ParserConfigurationException e
)
164 String message
= WorldWind
.retrieveErrMsg("GeoRSS.ParserConfigurationException");
165 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
, e
);
166 throw new WWRuntimeException(message
, e
);
168 catch (IOException e
)
170 String message
= WorldWind
.retrieveErrMsg("GeoRSS.IOExceptionParsing") + file
.getPath();
171 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
, e
);
172 throw new WWRuntimeException(message
, e
);
174 catch (SAXException e
)
176 String message
= WorldWind
.retrieveErrMsg("GeoRSS.IOExceptionParsing") + file
.getPath();
177 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
, e
);
178 throw new WWRuntimeException(message
, e
);
182 public static List
<Renderable
> parseShapes(Document xmlDoc
)
186 String message
= WorldWind
.retrieveErrMsg("nullValue.DocumentIsNull");
187 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
188 throw new IllegalArgumentException(message
);
191 ArrayList
<Node
> shapeNodes
= new ArrayList
<Node
>();
192 ArrayList
<Node
> attributeNodes
= new ArrayList
<Node
>();
195 NodeList nodes
= xmlDoc
.getElementsByTagNameNS(GEORSS_URI
, "where");
196 if (nodes
!= null && nodes
.getLength() > 0)
197 addNodes(shapeNodes
, nodes
);
199 nodes
= xmlDoc
.getElementsByTagNameNS(GEORSS_URI
, "point");
200 if (nodes
!= null && nodes
.getLength() > 0)
201 addNodes(shapeNodes
, nodes
);
203 nodes
= xmlDoc
.getElementsByTagNameNS(GEORSS_URI
, "line");
204 if (nodes
!= null && nodes
.getLength() > 0)
205 addNodes(shapeNodes
, nodes
);
207 nodes
= xmlDoc
.getElementsByTagNameNS(GEORSS_URI
, "polygon");
208 if (nodes
!= null && nodes
.getLength() > 0)
209 addNodes(shapeNodes
, nodes
);
211 nodes
= xmlDoc
.getElementsByTagNameNS(GEORSS_URI
, "box");
212 if (nodes
!= null && nodes
.getLength() > 0)
213 addNodes(shapeNodes
, nodes
);
216 nodes
= xmlDoc
.getElementsByTagNameNS(GEORSS_URI
, "radius");
217 if (nodes
!= null && nodes
.getLength() > 0)
218 addNodes(attributeNodes
, nodes
);
220 nodes
= xmlDoc
.getElementsByTagNameNS(GEORSS_URI
, "elev");
221 if (nodes
!= null && nodes
.getLength() > 0)
222 addNodes(attributeNodes
, nodes
);
224 ArrayList
<Renderable
> shapes
= new ArrayList
<Renderable
>();
226 if (shapeNodes
.size() < 1)
227 return null; // No warning here. Let the calling method inform of this case.
229 for (Node node
: shapeNodes
)
231 Renderable shape
= null;
232 String localName
= node
.getLocalName();
234 if (localName
.equals("point"))
235 shape
= makePointShape(node
, attributeNodes
);
237 else if (localName
.equals("where"))
238 shape
= makeWhereShape(node
);
240 else if (localName
.equals("line"))
241 shape
= makeLineShape(node
, attributeNodes
);
243 else if (localName
.equals("polygon"))
244 shape
= makePolygonShape(node
, attributeNodes
);
246 else if (localName
.equals("box"))
247 shape
= makeBoxShape(node
, attributeNodes
);
256 private static void addNodes(ArrayList
<Node
> nodeList
, NodeList nodes
)
258 for (int i
= 0; i
< nodes
.getLength(); i
++)
260 nodeList
.add(nodes
.item(i
));
264 private static Renderable
makeWhereShape(Node node
)
266 Node typeNode
= findChildByLocalName(node
, "Polygon");
267 if (typeNode
!= null)
268 return makeGMLPolygonShape(typeNode
);
270 typeNode
= findChildByLocalName(node
, "Envelope");
271 if (typeNode
!= null)
272 return makeGMLEnvelopeShape(typeNode
);
274 typeNode
= findChildByLocalName(node
, "LineString");
275 if (typeNode
!= null)
276 return makeGMLineStringShape(typeNode
);
278 typeNode
= findChildByLocalName(node
, "Point");
279 if (typeNode
!= null)
280 return makeGMLPointShape(typeNode
);
282 String message
= WorldWind
.retrieveErrMsg("GeoRSS.MissingElementContent") + " where";
283 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
287 private static Renderable
makeGMLPolygonShape(Node node
)
289 Node n
= findChildByLocalName(node
, "exterior");
292 String message
= WorldWind
.retrieveErrMsg("GeoRSS.MissingElement") + " exterior";
293 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
297 n
= findChildByLocalName(n
, "LinearRing");
300 String message
= WorldWind
.retrieveErrMsg("GeoRSS.MissingElement") + " LinearRing";
301 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
305 return makePolygonShape(n
, null);
308 private static Renderable
makePolygonShape(Node node
, Iterable
<Node
> attrs
)
310 String valuesString
= node
.getTextContent();
311 if (valuesString
== null)
313 String message
= WorldWind
.retrieveErrMsg("GeoRSS.NoCoordinates" + node
.getLocalName());
314 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
318 ArrayList
<Double
> values
= getDoubleValues(valuesString
);
319 if (values
.size() < 8 || values
.size() % 2 != 0)
321 String message
= WorldWind
.retrieveErrMsg("GeoRSS.InvalidCoordinateCount" + node
.getLocalName());
322 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
326 ArrayList
<LatLon
> positions
= new ArrayList
<LatLon
>();
327 for (int i
= 0; i
< values
.size(); i
+= 2)
329 positions
.add(LatLon
.fromDegrees(values
.get(i
), values
.get(i
+ 1)));
332 double elevation
= attrs
!= null ?
getElevation(node
, attrs
) : 0d
;
335 Polyline pl
= new Polyline(positions
, elevation
);
337 pl
.setFollowGreatCircles(true);
343 return new SurfacePolygon(positions
);
347 private static Renderable
makeGMLEnvelopeShape(Node node
)
349 Node n
= findChildByLocalName(node
, "lowerCorner");
352 String message
= WorldWind
.retrieveErrMsg("GeoRSS.MissingElement") + " lowerCorner";
353 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
357 String lowerCornerString
= n
.getTextContent();
358 if (lowerCornerString
== null)
360 String message
= WorldWind
.retrieveErrMsg("GeoRSS.MissingElementContent") + " lowerCorner";
361 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
365 n
= findChildByLocalName(node
, "upperCorner");
368 String message
= WorldWind
.retrieveErrMsg("GeoRSS.MissingElement") + " upperCorner";
369 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
373 String upperCornerString
= n
.getTextContent();
374 if (upperCornerString
== null)
376 String message
= WorldWind
.retrieveErrMsg("GeoRSS.MissingElementContent") + " upperCorner";
377 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
381 ArrayList
<Double
> lv
= getDoubleValues(lowerCornerString
);
384 String message
= WorldWind
.retrieveErrMsg("GeoRSS.InvalidCoordinateCount" + " lowerCorner");
385 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
389 ArrayList
<Double
> uv
= getDoubleValues(upperCornerString
);
392 String message
= WorldWind
.retrieveErrMsg("GeoRSS.InvalidCoordinateCount" + " upperCorner");
393 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
397 return new SurfaceQuadrilateral(Sector
.fromDegrees(lv
.get(0), uv
.get(0), lv
.get(1), uv
.get(1)));
400 private static Renderable
makeBoxShape(Node node
, Iterable
<Node
> attrs
)
402 String valuesString
= node
.getTextContent();
403 if (valuesString
== null)
405 String message
= WorldWind
.retrieveErrMsg("GeoRSS.NoCoordinates" + node
.getLocalName());
406 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
410 ArrayList
<Double
> p
= getDoubleValues(valuesString
);
413 String message
= WorldWind
.retrieveErrMsg("GeoRSS.InvalidCoordinateCount" + node
.getLocalName());
414 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
418 double elevation
= getElevation(node
, attrs
);
420 return new Quadrilateral(LatLon
.fromDegrees(p
.get(0), p
.get(1)),
421 LatLon
.fromDegrees(p
.get(2), p
.get(3)), elevation
);
423 return new SurfaceQuadrilateral(Sector
.fromDegrees(p
.get(0), p
.get(2), p
.get(1), p
.get(3)));
426 private static Renderable
makeGMLineStringShape(Node node
)
428 Node n
= findChildByLocalName(node
, "posList");
431 String message
= WorldWind
.retrieveErrMsg("GeoRSS.MissingElement") + " posList";
432 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
436 return makeLineShape(n
, null);
439 private static Renderable
makeLineShape(Node node
, Iterable
<Node
> attrs
)
441 String valuesString
= node
.getTextContent();
442 if (valuesString
== null)
444 String message
= WorldWind
.retrieveErrMsg("GeoRSS.NoCoordinates" + node
.getLocalName());
445 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
449 ArrayList
<Double
> values
= getDoubleValues(valuesString
);
450 if (values
.size() < 4)
452 String message
= WorldWind
.retrieveErrMsg("GeoRSS.InvalidCoordinateCount" + node
.getLocalName());
453 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
457 ArrayList
<LatLon
> positions
= new ArrayList
<LatLon
>();
458 for (int i
= 0; i
< values
.size(); i
+= 2)
460 positions
.add(LatLon
.fromDegrees(values
.get(i
), values
.get(i
+ 1)));
463 double elevation
= attrs
!= null ?
getElevation(node
, attrs
) : 0d
;
466 Polyline pl
= new Polyline(positions
, elevation
);
467 pl
.setFollowGreatCircles(true);
472 return new SurfacePolyline(positions
);
476 @SuppressWarnings({"UnusedDeclaration"})
477 private static Renderable
makeGMLPointShape(Node node
)
479 return null; // No shape provided for points. Expect app to use icons.
482 @SuppressWarnings({"UnusedDeclaration"})
483 private static Renderable
makePointShape(Node node
, Iterable
<Node
> attrs
)
485 return null; // No shape provided for points. Expect app to use icons.
488 private static Node
findChildByLocalName(Node parent
, String localName
)
490 NodeList children
= parent
.getChildNodes();
491 if (children
== null || children
.getLength() < 1)
494 for (int i
= 0; i
< children
.getLength(); i
++)
496 String ln
= children
.item(i
).getLocalName();
497 if (ln
!= null && ln
.equals(localName
))
498 return children
.item(i
);
504 private static Node
findSiblingAttribute(String attrName
, Iterable
<Node
> attribs
, Node shapeNode
)
506 for (Node attrib
: attribs
)
508 if (!attrib
.getLocalName().equals(attrName
))
511 if (attrib
.getParentNode().equals(shapeNode
.getParentNode()))
518 private static ArrayList
<Double
> getDoubleValues(String stringValues
)
520 String
[] tokens
= stringValues
.trim().split("[ ,\n]");
521 if (tokens
.length
< 1)
524 ArrayList
<Double
> arl
= new ArrayList
<Double
>();
525 for (String s
: tokens
)
527 if (s
== null || s
.length() < 1)
533 d
= Double
.parseDouble(s
);
535 catch (NumberFormatException e
)
537 String message
= WorldWind
.retrieveErrMsg("GeoRSS.NumberFormatException" + s
);
538 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
548 private static double getElevation(Node shapeNode
, Iterable
<Node
> attrs
)
550 double elevation
= 0d
;
552 Node elevNode
= findSiblingAttribute("elev", attrs
, shapeNode
);
553 if (elevNode
!= null)
555 ArrayList
<Double
> ev
= getDoubleValues(elevNode
.getTextContent());
556 if (ev
!= null && ev
.size() > 0)
558 elevation
= ev
.get(0);
562 String message
= WorldWind
.retrieveErrMsg("GeoRSS.MissingElementContent") + " elev";
563 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);