/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.xacml.geoxacml.attr;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.CoordinateSequenceFactory;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.impl.CoordinateArraySequenceFactory;
/**
* Abstract base class for supporting GML encoding and GML Parsing
*
*
* @author Christian Mueller
*
*/
public abstract class GMLSupport {
CoordinateSequenceFactory csFactory;
GeometryFactory gf;
public static final String GMLNS = "http://www.opengis.net/gml";
public static final String GMLNS_PREFIX = "gml";
protected static String LINESTRING_ERROR = "LineString must have >2 coodinates";
protected static String LINEARRING_ERROR = "LinearRing must have >=4 coodinates";
protected GMLSupport() {
csFactory = CoordinateArraySequenceFactory.instance();
gf = new GeometryFactory();
}
protected Node getChild(Node node, String elemName) {
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node n = children.item(i);
if (elemName.equals(n.getLocalName())) {
String namespace = node.getNamespaceURI();
if (namespace == null || (GMLSupport.GMLNS.equals(namespace))) {
return n;
}
}
}
return null;
}
protected List<Node> getChildren(Node node, String elemName) {
List<Node> result = new ArrayList<Node>();
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node n = children.item(i);
if (elemName.equals(n.getLocalName())) {
String namespace = node.getNamespaceURI();
if (namespace == null || (GMLSupport.GMLNS.equals(namespace))) {
result.add(n);
}
}
}
return result;
}
protected Polygon toGeometry(Envelope e) {
return gf.createPolygon(gf.createLinearRing(new Coordinate[] {
new Coordinate(e.getMinX(), e.getMinY()), new Coordinate(e.getMaxX(), e.getMinY()),
new Coordinate(e.getMaxX(), e.getMaxY()), new Coordinate(e.getMinX(), e.getMaxY()),
new Coordinate(e.getMinX(), e.getMinY()) }), null);
}
protected void encodeStartTag(String elemName, StringBuffer buff,
Map<String, String> attributeMap) {
buff.append("<").append(GMLNS_PREFIX).append(":").append(elemName);
if (attributeMap != null) {
for (String name : attributeMap.keySet()) {
buff.append(" ").append(name).append("=\"");
buff.append(attributeMap.get(name));
buff.append("\"");
}
}
buff.append(">");
}
protected Map<String, String> abstractGeometryAttribueMap(GeometryAttribute attr) {
Map<String, String> res = new HashMap<String, String>();
if (attr.getSrsName() != null)
res.put("srsName", attr.getSrsName());
if (attr.getGid() != null)
res.put("gid", attr.getGid());
if (attr.getSrsDimension() > 0)
res.put("srsDimension", new Integer(attr.getSrsDimension()).toString());
return res;
}
protected void encodeEndTag(String elemName, StringBuffer buff) {
buff.append("</").append(GMLNS_PREFIX).append(":").append(elemName).append(">");
}
abstract GeometryAttribute buildFromGML(Node node) throws Exception;
abstract void encodeASGML(GeometryAttribute attr, StringBuffer buff);
protected Coordinate parseCoordGML2(Node node) throws GMLException {
int dimension = 1;
double x;
double y;
double z;
x = y = z = Double.NaN;
Node xNode = getChild(node, "X");
if (xNode == null)
throw new GMLException("Missing X");
x = Double.valueOf(xNode.getTextContent());
Node yNode = getChild(node, "Y");
if (yNode != null) {
dimension++;
y = Double.valueOf(yNode.getTextContent());
}
Node zNode = getChild(node, "Z");
if (zNode != null) {
dimension++;
z = Double.valueOf(zNode.getTextContent());
}
return new Coordinate(x, y, z);
}
protected CoordinateSequence parseCoordinatesGML2(Node node) throws GMLException {
// get the coordinate and tuple seperators
String decimal = ".";
String cs = ",";
String ts = " ";
NamedNodeMap attributeMap = node.getAttributes();
Node attribute = attributeMap.getNamedItem("decimal");
if (attribute != null) {
decimal = attribute.getTextContent();
}
attribute = attributeMap.getNamedItem("cs");
if (attribute != null) {
cs = attribute.getTextContent();
}
attribute = attributeMap.getNamedItem("ts");
if (attribute != null) {
ts = attribute.getTextContent();
}
// do the parsing
String text = node.getTextContent();
// eliminate newlines, repeated spaces, etc
final String anyBlankSeq = "\\s+";
final String singleSpace = " ";
text = text.replaceAll(anyBlankSeq, singleSpace).trim();
// first tokenize by tuple seperators
StringTokenizer tuples = new StringTokenizer(text, ts);
CoordinateSequence seq = null;
int i = 0;
int ncoords = tuples.countTokens(); // number of coordinates
while (tuples.hasMoreTokens()) {
String tuple = tuples.nextToken();
// next tokenize by coordinate seperator
StringTokenizer oords = new StringTokenizer(tuple, cs);
// String[] oords = tuple.split(cs);
// next tokenize by decimal
String x = null;
// next tokenize by decimal
String y = null;
// next tokenize by decimal
String z = null;
// must be at least 1D
String tmp = oords.nextToken();
int count = 1;
x = ".".equals(decimal) ? tmp : tmp.replaceAll(decimal, ".");
if (oords.hasMoreTokens()) {
tmp = oords.nextToken();
count++;
y = ".".equals(decimal) ? tmp : tmp.replaceAll(decimal, ".");
}
if (oords.hasMoreTokens()) {
tmp = oords.nextToken();
count++;
z = ".".equals(decimal) ? tmp : tmp.replaceAll(decimal, ".");
}
if (seq == null) {
seq = csFactory.create(ncoords, count);
}
seq.setOrdinate(i, CoordinateSequence.X, Double.parseDouble(x));
if (y != null) {
seq.setOrdinate(i, CoordinateSequence.Y, Double.parseDouble(y));
}
if (z != null) {
seq.setOrdinate(i, CoordinateSequence.Z, Double.parseDouble(z));
}
i++;
}
return seq;
}
protected LinearRing parseLinearRingGML2(Node node) throws GMLException {
List<Node> coordinates = getChildren(node, "coord");
if (!coordinates.isEmpty() && (coordinates.size() >= 4)) {
Coordinate[] coordArray = new Coordinate[coordinates.size()];
for (int i = 0; i < coordinates.size(); i++) {
coordArray[i] = parseCoordGML2(coordinates.get(i));
}
return gf.createLinearRing(coordArray);
}
if (!coordinates.isEmpty()) {
throw new GMLException(LINEARRING_ERROR);
}
Node coords = getChild(node, "coordinates");
if (coords != null) {
CoordinateSequence cs = parseCoordinatesGML2(coords);
if (cs.size() < 4) {
throw new GMLException(LINEARRING_ERROR);
}
return gf.createLinearRing(cs);
}
return null;
}
protected LineString parseLineStringGML2(Node node) throws GMLException {
List<Node> coordinates = getChildren(node, "coord");
if (!coordinates.isEmpty() && (coordinates.size() >= 2)) {
Coordinate[] coordArray = new Coordinate[coordinates.size()];
for (int i = 0; i < coordinates.size(); i++) {
coordArray[i] = parseCoordGML2(coordinates.get(i));
}
return gf.createLineString(coordArray);
}
if (!coordinates.isEmpty()) {
throw new GMLException(LINESTRING_ERROR);
}
Node coords = getChild(node, "coordinates");
if (coords != null) {
CoordinateSequence cs = parseCoordinatesGML2(coords);
if (cs.size() < 2) {
throw new GMLException(LINESTRING_ERROR);
}
return gf.createLineString(cs);
}
return null;
}
protected Point parsePointGML2(Node node) throws GMLException {
Node coord = getChild(node, "coord");
if (coord != null) {
Coordinate c = parseCoordGML2(coord);
return gf.createPoint(c);
}
Node coordinates = getChild(node, "coordinates");
if (coordinates != null) {
CoordinateSequence seq = parseCoordinatesGML2(coordinates);
return gf.createPoint(seq);
}
return null;
}
}