001:
002: /*
003: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
004: * for visualizing and manipulating spatial features with geometry and attributes.
005: *
006: * Copyright (C) 2003 Vivid Solutions
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License
010: * as published by the Free Software Foundation; either version 2
011: * of the License, or (at your option) any later version.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: *
022: * For more information, contact:
023: *
024: * Vivid Solutions
025: * Suite #1A
026: * 2328 Government Street
027: * Victoria BC V8T 5G5
028: * Canada
029: *
030: * (250)385-6040
031: * www.vividsolutions.com
032: */
033:
034: // Changed by Uwe Dalluege, uwe.dalluege@rzcn.haw-hamburg.de
035: // to differ between LatLonBoundingBox and BoundingBox
036: // 2005-08-09
037: package com.vividsolutions.wms;
038:
039: import java.io.IOException;
040: import java.io.InputStream;
041: import java.io.InputStreamReader;
042: import java.util.LinkedList; // For the ArrayList [uwe dalluege]
043: import java.util.*;
044:
045: import org.apache.log4j.Logger;
046: import org.apache.xerces.parsers.DOMParser;
047: import org.w3c.dom.CharacterData;
048: import org.w3c.dom.Document;
049: import org.w3c.dom.NamedNodeMap;
050: import org.w3c.dom.Node;
051: import org.w3c.dom.NodeList;
052: import org.xml.sax.InputSource;
053: import org.xml.sax.SAXException;
054:
055: import com.vividsolutions.jump.util.*;
056: import com.vividsolutions.jump.I18N;
057: import com.vividsolutions.wms.util.XMLTools;
058:
059: /**
060: * Pulls WMS objects out of the XML
061: * @author Chris Hodgson chodgson@refractions.net
062: */
063: public class Parser {
064: private static Logger LOG = Logger.getLogger(Parser.class);
065:
066: /**
067: * Creates a Parser for dealing with WMS XML.
068: */
069:
070: public Parser() {
071: }
072:
073: /**
074: * Parses the WMT_MS_Capabilities XML from the given InputStream into
075: * a Capabilities object.
076: * @param service the WMService from which this MapDescriptor is derived
077: * @param inStream the inputStream containing the WMT_MS_Capabilities XML to parse
078: * @return the MapDescriptor object created from the specified XML InputStream
079: */
080:
081: public Capabilities parseCapabilities(WMService service,
082: InputStream inStream) throws IOException {
083: if (WMService.WMS_1_1_1.equals(service.getVersion())
084: || WMService.WMS_1_1_0.equals(service.getVersion())) {
085: return parseCapabilities_1_1_1(service, inStream);
086: }
087:
088: return parseCapabilities_1_0_0(service, inStream);
089: }
090:
091: /**
092: * Traverses the DOM tree underneath the specified Node and generates
093: * a corresponding WMSLayer object tree. The returned WMSLayer will be set to
094: * have the specified parent.
095: * @param layerNode a DOM Node which is a <layer> XML element
096: * @return a WMSLayer with complete subLayer tree that corresponds
097: * to the DOM Node provided
098: */
099: public MapLayer wmsLayerFromNode(Node layerNode) {
100: String name = null;
101: String title = null;
102: LinkedList srsList = new LinkedList();
103: LinkedList subLayers = new LinkedList();
104: BoundingBox bbox = null;
105:
106: // I think, bbox is LatLonBoundingBox.
107: // I need a new variable for BoundingBox.
108: // It must be a list because in the OGC document
109: // stands that Layers may have zero or more <BoundingBox> [uwe dalluege]
110: // BoundingBox boundingBox = null;
111: ArrayList boundingBoxList = new ArrayList();
112:
113: NodeList nl = layerNode.getChildNodes();
114:
115: for (int i = 0; i < nl.getLength(); i++) {
116: Node n = nl.item(i);
117: try {
118:
119: if (n.getNodeType() == Node.ELEMENT_NODE) {
120: if (n.getNodeName().equals("Name")) {
121: name = ((CharacterData) n.getFirstChild())
122: .getData();
123: } else if (n.getNodeName().equals("Title")) {
124: title = ((CharacterData) n.getFirstChild())
125: .getData();
126:
127: } else if (n.getNodeName().equals("SRS")) {
128: String srsStr = ((CharacterData) n
129: .getFirstChild()).getData();
130: // split the srs String on spaces
131: while (srsStr.length() > 0) {
132: int ws = srsStr.indexOf(' ');
133: if (ws > 0) {
134: srsList.add(srsStr.substring(0, ws));
135: srsStr = srsStr.substring(ws + 1);
136: } else {
137: if (srsStr.length() > 0) {
138: srsList.add(srsStr);
139: srsStr = "";
140: }
141: }
142: }
143: } else if (n.getNodeName().equals(
144: "LatLonBoundingBox")) {
145: bbox = boundingBoxFromNode(n);
146: boundingBoxList.add(bbox);
147:
148: // Check for BoundingBox [uwe dalluege]
149: } else if (n.getNodeName().equals("BoundingBox")) {
150: bbox = boundingBoxFromNode(n);
151: boundingBoxList.add(bbox);
152:
153: } else if (n.getNodeName().equals("Layer")) {
154: subLayers.add(wmsLayerFromNode(n));
155: }
156: }
157: } catch (Exception e) {
158: e.printStackTrace();
159: LOG.error("Exception caught in wmsLayerFromNode(): "
160: + e.toString());
161: }
162: }
163:
164: // call the new constructor with boundingBoxList in MapLayer [uwe dalluege]
165: return new MapLayer(name, title, srsList, subLayers, bbox,
166: boundingBoxList);
167: }
168:
169: /**
170: * Creates a new BoundingBox object based on the DOM Node given.
171: * @param n the DOM Node to create the Bounding box from, must be either a
172: * LatLonBoundingBox element or a BoundingBox element
173: * @return a new BoundingBox object based on the DOM Node provided
174: */
175: public BoundingBox boundingBoxFromNode(Node n) throws Exception {
176: try {
177: String srs = "";
178: NamedNodeMap nm = n.getAttributes();
179:
180: if (n.getNodeName().equals("LatLonBoundingBox")) {
181: srs = "LatLon";
182: } else if (n.getNodeName().equals("BoundingBox")) {
183: srs = nm.getNamedItem("SRS").getNodeValue();
184: } else {
185: // don't bother...
186: // throw new Exception( I18N.get("com.vividsolutions.wms.Parser.not-a-latlon-boundingbox-element") );
187: }
188:
189: // could not parse when values equal "inf"
190: // double minx = Double.parseDouble(nm.getNamedItem("minx").getNodeValue());
191: // double miny = Double.parseDouble(nm.getNamedItem("miny").getNodeValue());
192: // double maxx = Double.parseDouble(nm.getNamedItem("maxx").getNodeValue());
193: // double maxy = Double.parseDouble(nm.getNamedItem("maxy").getNodeValue());
194:
195: // change "inf" values with +/-"Infinity"
196: double minx;
197: if (nm.getNamedItem("minx").getNodeValue().equals("inf")) {
198: minx = Double.NEGATIVE_INFINITY;
199: } else {
200: minx = Double.parseDouble(nm.getNamedItem("minx")
201: .getNodeValue());
202: }
203:
204: double miny;
205: if (nm.getNamedItem("miny").getNodeValue().equals("inf")) {
206: miny = Double.NEGATIVE_INFINITY;
207: } else {
208: miny = Double.parseDouble(nm.getNamedItem("miny")
209: .getNodeValue());
210: }
211: double maxx;
212:
213: if (nm.getNamedItem("maxx").getNodeValue().equals("inf")) {
214: maxx = Double.POSITIVE_INFINITY;
215: } else {
216: maxx = Double.parseDouble(nm.getNamedItem("maxx")
217: .getNodeValue());
218: }
219:
220: double maxy;
221: if (nm.getNamedItem("maxy").getNodeValue().equals("inf")) {
222: maxy = Double.POSITIVE_INFINITY;
223: } else {
224: maxy = Double.parseDouble(nm.getNamedItem("maxy")
225: .getNodeValue());
226: }
227:
228: return new BoundingBox(srs, minx, miny, maxx, maxy);
229:
230: } catch (Exception e) {
231: // possible NullPointerException from getNamedItem returning a null
232: // also possible NumberFormatException
233: e.printStackTrace();
234: throw new Exception(
235: I18N
236: .get("com.vividsolutions.wms.Parser.invalid-bounding-box-element-node")
237: + ": " + e.toString());
238: }
239: }
240:
241: private Capabilities parseCapabilities_1_0_0(WMService service,
242: InputStream inStream) throws IOException {
243: MapLayer topLayer = null;
244: String title = null;
245: LinkedList formatList = new LinkedList();
246: Document doc;
247:
248: try {
249: DOMParser parser = new DOMParser();
250: parser.setFeature("http://xml.org/sax/features/validation",
251: false);
252: parser.parse(new InputSource(inStream));
253: doc = parser.getDocument();
254: // DEBUG: XMLTools.printNode( doc, "" );
255: } catch (SAXException saxe) {
256: throw new IOException(saxe.toString());
257: }
258:
259: // get the title
260: try {
261: title = ((CharacterData) XMLTools.simpleXPath(doc,
262: "WMT_MS_Capabilities/Service/Title")
263: .getFirstChild()).getData();
264: } catch (Exception e) {
265: // possible NullPointerException if there is no firstChild()
266: // also possible miscast causing an Exception
267:
268: // [uwe dalluege]
269: throw new IOException("Maybe wrong Capabilities Version! ");
270: }
271:
272: // get the supported file formats
273: Node formatNode = XMLTools.simpleXPath(doc,
274: "WMT_MS_Capabilities/Capability/Request/Map/Format");
275: NodeList nl = formatNode.getChildNodes();
276: for (int i = 0; i < nl.getLength(); i++) {
277: Node n = nl.item(i);
278: if (n.getNodeType() == Node.ELEMENT_NODE) {
279: formatList.add(n.getNodeName());
280: }
281: }
282:
283: // get the top layer
284: topLayer = wmsLayerFromNode(XMLTools.simpleXPath(doc,
285: "WMT_MS_Capabilities/Capability/Layer"));
286:
287: return new Capabilities(service, title, topLayer, formatList);
288: }
289:
290: //UT TODO move this into a common method (
291: // private Capabilities parseCapabilities( WMService service, InputStream inStream,
292: // String version)
293:
294: private Capabilities parseCapabilities_1_1_1(WMService service,
295: InputStream inStream) throws IOException {
296: MapLayer topLayer = null;
297: String title = null;
298: LinkedList formatList = new LinkedList();
299: Document doc;
300:
301: try {
302: DOMParser parser = new DOMParser();
303: parser.setFeature("http://xml.org/sax/features/validation",
304: false);
305: //was throwing java.io.UTFDataFormatException: Invalid byte 2 of 3-byte UTF-8 sequence.
306: // parser.parse( new InputSource( inStream ) );
307:
308: InputStreamReader ireader = new InputStreamReader(inStream);
309:
310: parser.parse(new InputSource(ireader));
311: doc = parser.getDocument();
312: } catch (SAXException saxe) {
313: throw new IOException(saxe.toString());
314: }
315:
316: // get the title
317: try {
318: title = ((CharacterData) XMLTools.simpleXPath(doc,
319: "WMT_MS_Capabilities/Service/Title")
320: .getFirstChild()).getData();
321: } catch (Exception e) {
322: // possible NullPointerException if there is no firstChild()
323: // also possible miscast causing an Exception
324: e.printStackTrace();
325: }
326:
327: // get the supported file formats // UT was "WMT_MS_Capabilities/Capability/Request/Map/Format"
328: Node formatNode = XMLTools.simpleXPath(doc,
329: "WMT_MS_Capabilities/Capability/Request/GetMap");
330:
331: NodeList nl = formatNode.getChildNodes();
332: for (int i = 0; i < nl.getLength(); i++) {
333: Node n = nl.item(i);
334: if (n.getNodeType() == Node.ELEMENT_NODE
335: && "Format".equals(n.getNodeName())) {
336: formatList.add(n.getFirstChild().getNodeValue());
337: }
338: }
339:
340: // get the top layer
341: topLayer = wmsLayerFromNode(XMLTools.simpleXPath(doc,
342: "WMT_MS_Capabilities/Capability/Layer"));
343:
344: return new Capabilities(service, title, topLayer, formatList);
345: }
346:
347: }
|