lwgeom_svg.o \
lwgeom_gml.o \
lwgeom_kml.o \
+ lwgeom_in_gml.o \
lwgeom_geojson.o \
lwgeom_triggers.o \
lwgeom_dump.o \
--- /dev/null
+/**********************************************************************
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.refractions.net
+ * Copyright 2009 Oslandia
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of hte GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+/**
+* @file GML input routines.
+* Ability to parse GML geometry fragment and to return an LWGEOM
+* or an error message.
+*
+* Implement ISO SQL/MM ST_GMLToSQL method
+* Cf: ISO 13249-3 -> 5.1.50 (p 134)
+*
+* GML versions supported:
+* - GML 2.1.2
+* - GML 3.1.1 Simple Features profile (1.0.0)
+* Cf: <http://www.opengeospatial.org/standards/gml>
+*
+* Current known limitations:
+* - Support only GML SF profile geometries (i.e no PostGIS curves support)
+* - Don't care about GML namespace
+* - Don't handle Xlink or PointRef construction
+* - Don't reproject if mixed srsName in multi/aggregate geoms
+*
+* Written by Olivier Courtin - Oslandia
+*
+**********************************************************************/
+
+
+#include "postgres.h"
+#include "lwgeom_pg.h"
+#include "liblwgeom.h"
+
+#if HAVE_LIBXML2
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+
+#include "lwgeom_export.h" /* getSRSbySRID */
+
+
+Datum geom_from_gml(PG_FUNCTION_ARGS);
+static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz);
+
+
+/**
+ * Ability to parse GML geometry fragment and to return an LWGEOM
+ * or an error message.
+ *
+ * ISO SQL/MM define two error messages:
+* Cf: ISO 13249-3 -> 5.1.50 (p 134)
+ * - invalid GML representation
+ * - unknown spatial reference system
+ */
+PG_FUNCTION_INFO_V1(geom_from_gml);
+Datum geom_from_gml(PG_FUNCTION_ARGS)
+{
+ PG_LWGEOM *geom, *geom2d;
+ xmlDocPtr xmldoc;
+ text *xml_input;
+ LWGEOM *lwgeom;
+ int xml_size;
+ uchar *srl;
+ char *xml;
+ size_t size=0;
+ bool hasz=true;
+ xmlNodePtr xmlroot=NULL;
+
+
+ /* Get the GML stream */
+ if (PG_ARGISNULL(0)) PG_RETURN_NULL();
+ xml_input = PG_GETARG_TEXT_P(0);
+
+ xml_size = VARSIZE(xml_input) - VARHDRSZ; /* actual letters */
+ xml = palloc(xml_size + 1); /* +1 for null */
+ memcpy(xml, VARDATA(xml_input), xml_size);
+ xml[xml_size] = 0; /* null term */
+
+ /* Begin to Parse XML doc */
+ xmlInitParser();
+ xmldoc = xmlParseMemory(xml, xml_size);
+ if (!xmldoc || (xmlroot = xmlDocGetRootElement(xmldoc)) == NULL) {
+ xmlFreeDoc(xmldoc);
+ xmlCleanupParser();
+ lwerror("invalid GML representation");
+ }
+
+ lwgeom = parse_gml(xmlroot, &hasz);
+ geom = pglwgeom_serialize(lwgeom);
+ lwgeom_release(lwgeom);
+
+ xmlFreeDoc(xmldoc);
+ xmlCleanupParser();
+
+ /* GML geometry could be either 2 or 3D and can be nested mixed.
+ * Missing Z dimension is even tolerated inside some GML coords
+ *
+ * So we deal with 3D in all structure allocation, and flag hasz
+ * to false if we met once a missing Z dimension
+ * In this case, we force recursive 2D.
+ */
+ if (!hasz) {
+ srl = lwalloc(VARSIZE(geom));
+ lwgeom_force2d_recursive(SERIALIZED_FORM(geom), srl, &size);
+ geom2d = PG_LWGEOM_construct(srl, pglwgeom_getSRID(geom),
+ lwgeom_hasBBOX(geom->type));
+ lwfree(geom);
+ geom = geom2d;
+ }
+
+ PG_RETURN_POINTER(geom);
+}
+
+
+/**
+ * Parse a string supposed to be a double
+ */
+static double parse_gml_double(char *d, bool space_before, bool space_after)
+{
+ char *p;
+ int st;
+ enum states {
+ INIT = 0,
+ NEED_DIG = 1,
+ DIG = 2,
+ NEED_DIG_DEC = 3,
+ DIG_DEC = 4,
+ EXP = 5,
+ NEED_DIG_EXP = 6,
+ DIG_EXP = 7,
+ END = 8
+ };
+
+ /*
+ * Double pattern
+ * [-|\+]?[0-9]+(\.[0-9]+)?([Ee](\+|-)?[0-9]+)
+ *
+ * We could also meet spaces before or after
+ * this pattern upon parameters
+ */
+
+ if (space_before) while (isspace(*d)) d++;
+ for (st = INIT, p = d ; *p ; p++) {
+
+ if (isdigit(*p)) {
+ if (st == INIT || st == NEED_DIG) st = DIG;
+ else if (st == NEED_DIG_DEC) st = DIG_DEC;
+ else if (st == NEED_DIG_EXP || st == EXP) st = DIG_EXP;
+ else if (st == DIG || st == DIG_DEC || st == DIG_EXP);
+ else lwerror("invalid GML representation");
+ } else if (*p == '.') {
+ if (st == DIG) st = NEED_DIG_DEC;
+ else lwerror("invalid GML representation");
+ } else if (*p == '-' || *p == '+') {
+ if (st == INIT) st = NEED_DIG;
+ else if (st == EXP) st = NEED_DIG_EXP;
+ else lwerror("invalid GML representation");
+ } else if (*p == 'e' || *p == 'E') {
+ if (st == DIG || st == DIG_DEC) st = EXP;
+ else lwerror("invalid GML representation");
+ } else if (isspace(*p)) {
+ if (!space_after) lwerror("invalid GML representation");
+ if (st == DIG || st == DIG_DEC || st == DIG_EXP)st = END;
+ else if (st == END);
+ else lwerror("invalid GML representation");
+ } else lwerror("invalid GML representation");
+ }
+
+ if (st != DIG && st != DIG_DEC && st != DIG_EXP && st != END)
+ lwerror("invalid GML representation");
+
+ return atof(d);
+}
+
+
+/**
+ * Parse gml:coordinates
+ */
+static POINTARRAY* parse_gml_coordinates(xmlNodePtr xnode, bool *hasz)
+{
+ xmlChar *gml_coord, *gml_ts, *gml_cs, *gml_dec;
+ char *coord, *p, *q;
+ char cs, ts, dec;
+ DYNPTARRAY *dpa;
+ POINTARRAY *pa;
+ int gml_dims;
+ bool digit;
+ POINT4D pt;
+ uchar dims=0;
+
+ /* We begin to retrieve coordinates string */
+ gml_coord = xmlNodeGetContent(xnode);
+ p = coord = (char *) gml_coord;
+
+ /* Default GML coordinates pattern: x1,y1 x2,y2
+ * x1,y1,z1 x2,y2,z2
+ *
+ * Cf GML 2.1.2 -> 4.3.1 (p18)
+ */
+
+ /* Retrieve separator between coordinates tuples */
+ gml_ts = xmlGetProp(xnode, (xmlChar *) "ts");
+ if (gml_ts == NULL) ts = ' ';
+ else {
+ if (xmlStrlen(gml_ts) > 1 || isdigit(gml_ts[0]))
+ lwerror("invalid GML representation");
+ ts = gml_ts[0];
+ xmlFree(gml_ts);
+ }
+
+ /* Retrieve separator between each coordinate */
+ gml_cs = xmlGetProp(xnode, (xmlChar *) "cs");
+ if (gml_cs == NULL) cs = ',';
+ else {
+ if (xmlStrlen(gml_cs) > 1 || isdigit(gml_cs[0]))
+ lwerror("invalid GML representation");
+ cs = gml_cs[0];
+ xmlFree(gml_cs);
+ }
+
+ /* Retrieve decimal separator */
+ gml_dec = xmlGetProp(xnode, (xmlChar *) "decimal");
+ if (gml_dec == NULL) dec = '.';
+ else {
+ if (xmlStrlen(gml_dec) > 1 || isdigit(gml_dec[0]))
+ lwerror("invalid GML representation");
+ dec = gml_dec[0];
+ xmlFree(gml_dec);
+ }
+
+ if (cs == ts || cs == dec || ts == dec)
+ lwerror("invalid GML representation");
+
+ /* Now we create PointArray from coordinates values */
+ TYPE_SETZM(dims, 1, 0);
+ dpa = dynptarray_create(1, dims);
+
+ while(isspace(*p)) p++; /* Eat extra whitespaces if any */
+ for (q = p, gml_dims=0, digit = false ; *p ; p++) {
+
+ if (isdigit(*p)) digit = true; /* One state parser */
+
+ /* Coordinate Separator */
+ if (*p == cs) {
+ *p = '\0';
+ gml_dims++;
+
+ if (*(p+1) == '\0') lwerror("invalid GML representation");
+
+ if (gml_dims == 1) pt.x = parse_gml_double(q, 0, 1);
+ else if (gml_dims == 2) pt.y = parse_gml_double(q, 0, 1);
+
+ q = p+1;
+
+ /* Tuple Separator (or end string) */
+ } else if (digit && (*p == ts || *(p+1) == '\0')) {
+ if (*p == ts) *p = '\0';
+ gml_dims++;
+
+ if (gml_dims < 2 || gml_dims > 3)
+ lwerror("invalid GML representation");
+
+ if (gml_dims == 3) pt.z = parse_gml_double(q, 0, 1);
+ else {
+ pt.y = atof(q);
+ *hasz = false;
+ }
+
+ dynptarray_addPoint4d(dpa, &pt, 0);
+ digit = false;
+
+ q = p+1;
+ gml_dims = 0;
+
+ /* Need to put standard decimal separator to atof handle */
+ } else if (*p == dec && dec != '.') *p = '.';
+ }
+
+ xmlFree(gml_coord);
+ pa = ptarray_clone(dpa->pa);
+ lwfree(dpa);
+
+ return pa;
+}
+
+
+/**
+ * Parse gml:coord
+ */
+static POINTARRAY* parse_gml_coord(xmlNodePtr xnode, bool *hasz)
+{
+ xmlNodePtr coord, xyz;
+ DYNPTARRAY *dpa;
+ POINTARRAY *pa;
+ bool x,y,z;
+ xmlChar *c;
+ POINT4D p;
+ uchar dims=0;
+
+ TYPE_SETZM(dims, 1, 0);
+ dpa = dynptarray_create(1, dims);
+
+ for (coord = xnode ; coord != NULL ; coord = coord->next) {
+
+ /* Looking for gml:coord element */
+ if (coord->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) coord->name, "coord")) continue;
+
+ x = y = z = false;
+ for (xyz = coord->children ; xyz != NULL ; xyz = xyz->next) {
+
+ if (xyz->type != XML_ELEMENT_NODE) continue;
+
+ if (!strcmp((char *) xyz->name, "X")) {
+ if (x) lwerror("invalid GML representation");
+ c = xmlNodeGetContent(xyz);
+ p.x = parse_gml_double((char *) c, 1, 1);
+ x = true;
+ xmlFree(c);
+ } else if (!strcmp((char *) xyz->name, "Y")) {
+ if (y) lwerror("invalid GML representation");
+ c = xmlNodeGetContent(xyz);
+ p.y = parse_gml_double((char *) c, 1, 1);
+ y = true;
+ xmlFree(c);
+ } else if (!strcmp((char *) xyz->name, "Z")) {
+ if (z) lwerror("invalid GML representation");
+ c = xmlNodeGetContent(xyz);
+ p.z = parse_gml_double((char *) c, 1, 1);
+ z = true;
+ xmlFree(c);
+ }
+ }
+
+ /* Check dimension consistancy */
+ if (!x || !y) lwerror("invalid GML representation");
+ if (!z) *hasz = false;
+
+ dynptarray_addPoint4d(dpa, &p, 0);
+ x = y = z = false;
+ }
+
+ pa = ptarray_clone(dpa->pa);
+ lwfree(dpa);
+
+ return pa;
+}
+
+
+/**
+ * Parse gml:pos
+ */
+static POINTARRAY* parse_gml_pos(xmlNodePtr xnode, bool *hasz)
+{
+ xmlChar *dimension, *gmlpos;
+ xmlNodePtr posnode;
+ int dim, gml_dim;
+ DYNPTARRAY *dpa;
+ POINTARRAY *pa;
+ char *pos, *p;
+ bool digit;
+ POINT4D pt;
+ uchar dims=0;
+
+ TYPE_SETZM(dims, 1, 0);
+ dpa = dynptarray_create(1, dims);
+
+ for (posnode = xnode ; posnode != NULL ; posnode = posnode->next) {
+
+ /* We only care about pos element */
+ if (posnode->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) posnode->name, "pos")) continue;
+
+ dimension = xmlGetProp(xnode, (xmlChar *) "dimension");
+ if (dimension == NULL) dim = 2; /* We assume that we are in 2D */
+ else {
+ dim = atoi((char *) dimension);
+ xmlFree(dimension);
+ if (dim < 2 || dim > 3)
+ lwerror("invalid GML representation");
+ }
+ if (dim == 2) *hasz = false;
+
+ /* We retrieve gml:pos string */
+ gmlpos = xmlNodeGetContent(posnode);
+ pos = (char *) gmlpos;
+ while(isspace(*pos)) pos++; /* Eat extra whitespaces if any */
+
+ /* gml:pos pattern: x1 y1
+ * x1 y1 z1
+ */
+ for (p=pos, gml_dim=0, digit=false ; *pos ; pos++) {
+
+ if (isdigit(*pos)) digit = true;
+
+ if (digit && (*pos == ' ' || *(pos+1) == '\0')) {
+
+ if (*pos == ' ') *pos = '\0';
+ gml_dim++;
+ if (gml_dim == 1) pt.x = parse_gml_double(p, 0, 1);
+ else if (gml_dim == 2) pt.y = parse_gml_double(p, 0, 1);
+ else if (gml_dim == 3) pt.z = parse_gml_double(p, 0, 1);
+
+ p = pos+1;
+ digit = false;
+ }
+ }
+ xmlFree(gmlpos);
+
+ /* Test again coherent dimensions on each coord */
+ if (gml_dim == 2) *hasz = false;
+ if (gml_dim < 2 || gml_dim > 3 || gml_dim != dim)
+ lwerror("invalid GML representation");
+
+ dynptarray_addPoint4d(dpa, &pt, 0);
+ }
+
+ pa = ptarray_clone(dpa->pa);
+ lwfree(dpa);
+
+ return pa;
+}
+
+
+/**
+ * Parse gml:posList
+ */
+static POINTARRAY* parse_gml_poslist(xmlNodePtr xnode, bool *hasz)
+{
+ xmlChar *dimension, *gmlposlist;
+ char *poslist, *p;
+ int dim, gml_dim;
+ DYNPTARRAY *dpa;
+ POINTARRAY *pa;
+ POINT4D pt;
+ bool digit;
+ uchar dims=0;
+
+ /* Retrieve gml:dimension attribute if any */
+ dimension = xmlGetProp(xnode, (xmlChar *) "dimension");
+ if (dimension == NULL) dim = 2; /* We assume that we are in common 2D */
+ else {
+ dim = atoi((char *) dimension);
+ xmlFree(dimension);
+ if (dim < 2 || dim > 3) lwerror("invalid GML representation");
+ }
+ if (dim == 2) *hasz = false;
+
+ /* Retrieve gml:posList string */
+ gmlposlist = xmlNodeGetContent(xnode);
+ poslist = (char *) gmlposlist;
+
+ TYPE_SETZM(dims, 1, 0);
+ dpa = dynptarray_create(1, dims);
+
+ /* gml:posList pattern: x1 y1 x2 y2
+ * x1 y1 z1 x2 y2 z2
+ */
+ while(isspace(*poslist)) poslist++; /* Eat extra whitespaces if any */
+ for (p=poslist, gml_dim=0, digit=false ; *poslist ; poslist++) {
+
+ if (isdigit(*poslist)) digit = true;
+
+ if (digit && (*poslist == ' ' || *(poslist+1) == '\0')) {
+
+ if (*poslist == ' ') *poslist = '\0';
+
+ gml_dim++;
+ if (gml_dim == 1) pt.x = parse_gml_double(p, 0, 1);
+ else if (gml_dim == 2) pt.y = parse_gml_double(p, 0, 1);
+ else if (gml_dim == 3) pt.z = parse_gml_double(p, 0, 1);
+
+ if (gml_dim == dim) {
+ dynptarray_addPoint4d(dpa, &pt, 0);
+ gml_dim = 0;
+ } else if (*(poslist+1) == '\0')
+ lwerror("invalid GML representation");
+
+ p = poslist+1;
+ digit = false;
+ }
+ }
+
+ xmlFree(gmlposlist);
+ pa = ptarray_clone(dpa->pa);
+ lwfree(dpa);
+
+ return pa;
+}
+
+
+/**
+ * Parse data coordinates
+ *
+ * There's four ways to encode coordinates:
+ * - gml:pos element
+ * - gml:posList element
+ * - gml:coord elements with X,Y(,Z) nested elements (deprecated in 3.0.0)
+ * - gml:coordinate element with tuples string inside (deprecated in 3.1.0)
+ *
+ * Cf: GML 2.1.2 -> 4.3.2 (p17)
+ * Cf: GML 3.1.1 -> 9.1.3.5 (p45)
+ *
+ * NOTA: we don't support pointRep references !
+ */
+static POINTARRAY * parse_gml_data(xmlNodePtr xnode, bool *hasz)
+{
+ bool coordinates, coord, pos, poslist;
+ xmlNodePtr node;
+
+ coordinates = coord = pos = poslist = false;
+
+ for (node = xnode ; node != NULL ; node = node->next) {
+
+ if (node->type != XML_ELEMENT_NODE) continue;
+ if (!strcmp((char *) node->name, "pos")) {
+ pos=true;
+ break;
+ } else if (!strcmp((char *) node->name, "posList")) {
+ poslist=true;
+ break;
+ } else if (!strcmp((char *) node->name, "coordinates")) {
+ coordinates=true;
+ break;
+ } else if (!strcmp((char *) node->name, "coord")) {
+ coord=true;
+ break;
+ }
+ }
+
+ if (pos) return parse_gml_pos(node, hasz);
+ if (poslist) return parse_gml_poslist(node, hasz);
+ if (coordinates) return parse_gml_coordinates(node, hasz);
+ if (coord) return parse_gml_coord(node, hasz);
+
+ lwerror("invalid GML representation");
+
+ return NULL;
+}
+
+
+/**
+ * Parse gml srsName attribute
+ */
+static int parse_gml_srs(xmlNodePtr xnode)
+{
+ xmlChar *srs;
+ char *p;
+ int srid=-1;
+
+ srs = xmlGetProp(xnode, (xmlChar *) "srsName");
+ if (!srs) return -1; /* Default srid if no srsName attribute */
+
+ /* Severals srsName formats are available...
+ * cf WFS 1.1.0 -> 9.2 (p36)
+ * cf ISO 19142 -> 7.9.2.4.4 (p34)
+ * cf RFC 5165 <http://tools.ietf.org/html/rfc5165>
+ */
+
+ /* SRS pattern like: EPSG:4326
+ urn:EPSG:geographicCRS:4326
+ urn:ogc:def:crs:EPSG:4326
+ urn:ogc:def:crs:EPSG::4326
+ urn:ogc:def:crs:EPSG:6.6:4326
+ urn:x-ogc:def:crs:EPSG:6.6:4326 */
+
+ if ( !strncmp((char *) srs, "EPSG:", 5)
+ || !strncmp((char *) srs, "urn:ogc:def:crs:EPSG:", 21)
+ || !strncmp((char *) srs, "urn:x-ogc:def:crs:EPSG:", 23)
+ || !strncmp((char *) srs, "urn:EPSG:geographicCRS:", 23)) {
+
+ /* retrieve the last ':' char */
+ for (p = (char *) srs ; *p ; p++);
+ for (--p ; *p != ':' ; p--)
+ if (!isdigit(*p)) lwerror("unknown spatial reference system");
+
+ srid = atoi(++p);
+
+ /* SRS pattern like: http://www.opengis.net/gml/srs/epsg.xml#4326 */
+ } else if (!strncmp((char *) srs, "http://www.opengis.net/gml/srs/epsg.xml#", 40)) {
+ p = strchr((char *) srs, '#');
+ srid = atoi(++p);
+ }
+
+ /* Check into spatial_ref_sys that this SRID really exist */
+ if (srid == -1 || getSRSbySRID(srid, true) == NULL)
+ lwerror("unknown spatial reference system");
+
+ xmlFree(srs);
+ return srid;
+}
+
+
+/**
+ * Parse GML point (2.1.2, 3.x.x)
+ */
+static LWGEOM* parse_gml_point(xmlNodePtr xnode, bool *hasz)
+{
+ int srid;
+ POINTARRAY *pa;
+
+ srid = parse_gml_srs(xnode);
+
+ pa = parse_gml_data(xnode->children, hasz);
+ if (pa->npoints != 1)
+ lwerror("invalid GML representation");
+
+ return (LWGEOM *) lwpoint_construct(srid, NULL, pa);
+}
+
+
+/**
+ * Parse GML lineString (2.1.2, 3.x.x)
+ */
+static LWGEOM* parse_gml_line(xmlNodePtr xnode, bool *hasz)
+{
+ int srid;
+ POINTARRAY *pa;
+
+ srid = parse_gml_srs(xnode);
+ pa = parse_gml_data(xnode->children, hasz);
+ if (pa->npoints < 2)
+ lwerror("invalid GML representation");
+
+ return (LWGEOM *) lwline_construct(srid, NULL, pa);
+}
+
+
+/**
+ * Parse GML Curve (3.x.x)
+ */
+static LWGEOM* parse_gml_curve(xmlNodePtr xnode, bool *hasz)
+{
+ int srid, lss, last, i;
+ xmlChar *interpolation;
+ POINTARRAY **ppa;
+ POINTARRAY *pa;
+ xmlNodePtr xa;
+ bool found=false;
+ unsigned int npoints=0;
+
+ srid = parse_gml_srs(xnode);
+
+ /* Looking for gml:segments */
+ for (xa = xnode->children ; xa != NULL ; xa = xa->next) {
+
+ if (xa->type != XML_ELEMENT_NODE) continue;
+ if (!strcmp((char *) xa->name, "segments")) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) lwerror("invalid GML representation");
+
+ ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
+
+ /* Processing each gml:LineStringSegment */
+ for (xa = xa->children, lss=0; xa != NULL ; xa = xa->next) {
+
+ if (xa->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xa->name, "LineStringSegment")) continue;
+
+ /* GML SF is resticted to linear interpolation */
+ interpolation = xmlGetProp(xa, (xmlChar *) "interpolation");
+ if (interpolation != NULL) {
+ if (strcmp((char *) interpolation, "linear"))
+ lwerror("invalid GML representation");
+ xmlFree(interpolation);
+ }
+
+ if (lss > 0) ppa = (POINTARRAY**) lwrealloc((LWLINE *) ppa,
+ sizeof(POINTARRAY*) * (lss + 1));
+
+ ppa[lss] = parse_gml_data(xa->children, hasz);
+ npoints += ppa[lss]->npoints;
+ if (ppa[lss]->npoints < 2)
+ lwerror("invalid GML representation");
+ lss++;
+ }
+ if (lss == 0) lwerror("invalid GML representation");
+
+ /* Most common case, a single segment */
+ if (lss == 1) return (LWGEOM *) lwline_construct(srid, NULL, ppa[0]);
+
+
+ /*
+ * "The curve segments are connected to one another, with the end point
+ * of each segment except the last being the start point of the next
+ * segment" from ISO 19107 -> 6.3.16.1 (p43)
+ *
+ * So we must aggregate all the segments into a single one and avoid
+ * to copy the redundants points
+ */
+ pa = ptarray_construct(1, 0, npoints - (lss - 1));
+ for (last = npoints = i = 0; i < lss ; i++) {
+
+ if (i + 1 == lss) last = 1;
+ /* Check if segments are not disjoints */
+ if (i > 0 && memcmp( getPoint_internal(pa, npoints),
+ getPoint_internal(ppa[i], 0),
+ *hasz?sizeof(POINT3D):sizeof(POINT2D)))
+ lwerror("invalid GML representation");
+
+ /* Aggregate stuff */
+ memcpy( getPoint_internal(pa, npoints),
+ getPoint_internal(ppa[i], 0),
+ pointArray_ptsize(ppa[i]) * (ppa[i]->npoints + last));
+
+ npoints += ppa[i]->npoints - 1;
+ lwfree(ppa[i]);
+ }
+ lwfree(ppa);
+
+ return (LWGEOM *) lwline_construct(srid, NULL, pa);
+}
+
+
+/**
+ * Parse GML Polygon (2.1.2, 3.x.x)
+ */
+static LWGEOM* parse_gml_polygon(xmlNodePtr xnode, bool *hasz)
+{
+ int srid, ring;
+ xmlNodePtr xa, xb;
+ POINTARRAY **ppa = NULL;
+
+ for (xa = xnode->children ; xa != NULL ; xa = xa->next) {
+
+ /* Polygon/outerBoundaryIs -> GML 2.1.2 */
+ /* Polygon/exterior -> GML 3.x.x */
+ if (xa->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xa->name, "outerBoundaryIs") &&
+ strcmp((char *) xa->name, "exterior")) continue;
+
+ for (xb = xa->children ; xb != NULL ; xb = xb->next) {
+
+ if (xb->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xb->name, "LinearRing")) continue;
+
+ ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
+ ppa[0] = parse_gml_data(xb->children, hasz);
+
+ /* FIXME: And what about the 3D ? */
+ if (ppa[0]->npoints < 4 || !ptarray_isclosed2d(ppa[0]))
+ lwerror("invalid GML representation");
+ }
+ }
+
+ for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next) {
+
+ /* Polygon/innerBoundaryIs -> GML 2.1.2 */
+ /* Polygon/interior -> GML 3.x.x */
+ if (xa->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xa->name, "innerBoundaryIs") &&
+ strcmp((char *) xa->name, "interior")) continue;
+
+ for (xb = xa->children ; xb != NULL ; xb = xb->next) {
+
+ if (xb->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xb->name, "LinearRing")) continue;
+
+ ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
+ sizeof(POINTARRAY*) * (ring + 1));
+ ppa[ring] = parse_gml_data(xb->children, hasz);
+
+ /* FIXME: And what about the 3D ? */
+ if (ppa[ring]->npoints < 4 || !ptarray_isclosed2d(ppa[ring]))
+ lwerror("invalid GML representation");
+ ring++;
+ }
+ }
+
+ /* Exterior Ring is mandatory */
+ if (ppa == NULL || ppa[0] == NULL) lwerror("invalid GML representation");
+
+ srid = parse_gml_srs(xnode);
+ return (LWGEOM*) lwpoly_construct(srid, NULL, ring, ppa);
+}
+
+
+/**
+ * Parse GML Surface (3.x.x)
+ */
+static LWGEOM* parse_gml_surface(xmlNodePtr xnode, bool *hasz)
+{
+ xmlChar *interpolation;
+ xmlNodePtr xa, xb, xc;
+ int patch, ring, srid;
+ POINTARRAY **ppa;
+ bool found=false;
+
+ /* Looking for gml:patches */
+ for (xa = xnode->children ; xa != NULL ; xa = xa->next) {
+
+ if (xa->type != XML_ELEMENT_NODE) continue;
+ if (!strcmp((char *) xa->name, "patches")) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) lwerror("invalid GML representation");
+
+ /* Processing gml:PolygonPatch */
+ for (patch=0, xa = xa->children ; xa != NULL ; xa = xa->next) {
+
+ if (xa->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xa->name, "PolygonPatch")) continue;
+ patch++;
+
+ /* SQL/MM define ST_CurvePolygon as a single patch only,
+ cf ISO 13249-3 -> 4.2.9 (p27) */
+ if (patch > 1) lwerror("invalid GML representation");
+
+ /* GML SF is resticted to planar interpolation */
+ interpolation = xmlGetProp(xa, (xmlChar *) "interpolation");
+ if (interpolation != NULL) {
+ if (strcmp((char *) interpolation, "planar"))
+ lwerror("invalid GML representation");
+ xmlFree(interpolation);
+ }
+
+ /* PolygonPatch/exterior */
+ for (xb = xa->children ; xb != NULL ; xb = xb->next) {
+ if (strcmp((char *) xb->name, "exterior")) continue;
+
+ /* PolygonPatch/exterior/LinearRing */
+ for (xc = xb->children ; xc != NULL ; xc = xc->next) {
+
+ if (xc->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xc->name, "LinearRing")) continue;
+
+ ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
+ ppa[0] = parse_gml_data(xc->children, hasz);
+
+ /* FIXME: And what about the 3D ? */
+ if (ppa[0]->npoints < 4 || !ptarray_isclosed2d(ppa[0]))
+ lwerror("invalid GML representation");
+ }
+ }
+
+ /* PolygonPatch/interior */
+ for (ring=1, xb = xa->children ; xb != NULL ; xb = xb->next) {
+
+ if (xb->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xb->name, "interior")) continue;
+ if (xb->children == NULL) break; /* FIXME Why this is needed ??? */
+
+ /* PolygonPatch/interior/LinearRing */
+ for (xc = xb->children ; xc != NULL ; xc = xc->next) {
+
+ if (xc->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xc->name, "LinearRing")) continue;
+
+ ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
+ sizeof(POINTARRAY*) * (ring + 1));
+ ppa[ring] = parse_gml_data(xc->children, hasz);
+
+ /* FIXME: And what about the 3D ? */
+ if (ppa[ring]->npoints < 4 || !ptarray_isclosed2d(ppa[ring]))
+ lwerror("invalid GML representation");
+ }
+ ring++;
+ }
+ }
+
+ /* Exterior Ring is mandatory */
+ if (ppa == NULL || ppa[0] == NULL) lwerror("invalid GML representation");
+
+ srid = parse_gml_srs(xnode);
+ return (LWGEOM*) lwpoly_construct(srid, NULL, ring, ppa);
+}
+
+
+/**
+ * Parse gml:MultiPoint (2.1.2, 3.x.x)
+ */
+static LWGEOM* parse_gml_mpoint(xmlNodePtr xnode, bool *hasz)
+{
+ int srid;
+ xmlNodePtr xa;
+ LWGEOM *geom = NULL;
+
+ srid = parse_gml_srs(xnode);
+
+ geom = (LWGEOM *)lwcollection_construct_empty(srid, 1, 0);
+ geom->type = lwgeom_makeType(1, 0, srid != -1, MULTIPOINTTYPE);
+
+ for (xa = xnode->children ; xa != NULL ; xa = xa->next) {
+
+ /* MultiPoint/pointMember */
+ if (xa->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xa->name, "pointMember")) continue;
+ if (xa->children != NULL)
+ geom = lwmpoint_add((LWMPOINT *)geom, -1,
+ parse_gml(xa->children, hasz));
+ }
+
+ return geom;
+}
+
+
+/**
+ * Parse gml:MultiLineString (2.1.2, 3.x.x)
+ */
+static LWGEOM* parse_gml_mline(xmlNodePtr xnode, bool *hasz)
+{
+ int srid;
+ xmlNodePtr xa;
+ LWGEOM *geom = NULL;
+
+ srid = parse_gml_srs(xnode);
+
+ geom = (LWGEOM *)lwcollection_construct_empty(srid, 1, 0);
+ geom->type = lwgeom_makeType(1, 0, srid != -1, MULTILINETYPE);
+
+ for (xa = xnode->children ; xa != NULL ; xa = xa->next) {
+
+ /* MultiLineString/lineMember */
+ if (xa->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xa->name, "lineStringMember")) continue;
+ if (xa->children != NULL)
+ geom = lwmline_add((LWMLINE *)geom, -1,
+ parse_gml(xa->children, hasz));
+ }
+
+ return geom;
+}
+
+
+/**
+ * Parse GML MultiCurve (3.x.x)
+ */
+static LWGEOM* parse_gml_mcurve(xmlNodePtr xnode, bool *hasz)
+{
+ int srid;
+ xmlNodePtr xa;
+ LWGEOM *geom = NULL;
+
+ srid = parse_gml_srs(xnode);
+
+ geom = (LWGEOM *)lwcollection_construct_empty(srid, 1, 0);
+ geom->type = lwgeom_makeType(1, 0, srid != -1, MULTILINETYPE);
+
+ for (xa = xnode->children ; xa != NULL ; xa = xa->next) {
+
+ /* MultiCurve/curveMember */
+ if (xa->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xa->name, "curveMember")) continue;
+ if (xa->children != NULL)
+ geom = lwmline_add((LWMLINE *)geom, -1,
+ parse_gml(xa->children, hasz));
+ }
+
+ return geom;
+}
+
+
+/**
+ * Parse GML MultiPolygon (2.1.2, 3.x.x)
+ */
+static LWGEOM* parse_gml_mpoly(xmlNodePtr xnode, bool *hasz)
+{
+ int srid;
+ xmlNodePtr xa;
+ LWGEOM *geom = NULL;
+
+ srid = parse_gml_srs(xnode);
+
+ geom = (LWGEOM *)lwcollection_construct_empty(srid, 1, 0);
+ geom->type = lwgeom_makeType(1, 0, srid != -1, MULTIPOLYGONTYPE);
+
+ for (xa = xnode->children ; xa != NULL ; xa = xa->next) {
+
+ /* MultiPolygon/polygonMember */
+ if (xa->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xa->name, "polygonMember")) continue;
+ if (xa->children != NULL)
+ geom = lwmpoly_add((LWMPOLY *)geom, -1,
+ parse_gml(xa->children, hasz));
+ }
+
+ return geom;
+}
+
+
+/**
+ * Parse GML MultiSurface (3.x.x)
+ */
+static LWGEOM* parse_gml_msurface(xmlNodePtr xnode, bool *hasz)
+{
+ int srid;
+ xmlNodePtr xa;
+ LWGEOM *geom = NULL;
+
+ srid = parse_gml_srs(xnode);
+
+ geom = (LWGEOM *)lwcollection_construct_empty(srid, 1, 0);
+ geom->type = lwgeom_makeType(1, 0, srid != -1, MULTIPOLYGONTYPE);
+
+ for (xa = xnode->children ; xa != NULL ; xa = xa->next) {
+
+ /* MultiSurface/surfaceMember */
+ if (xa->type != XML_ELEMENT_NODE) continue;
+ if (strcmp((char *) xa->name, "surfaceMember")) continue;
+ if (xa->children != NULL)
+ geom = lwmpoly_add((LWMPOLY *)geom, -1,
+ parse_gml(xa->children, hasz));
+ }
+
+ return geom;
+}
+
+
+/**
+ * Parse GML MultiGeometry (2.1.2, 3.x.x)
+ */
+static LWGEOM* parse_gml_coll(xmlNodePtr xnode, bool *hasz)
+{
+ int srid;
+ xmlNodePtr xa;
+ LWGEOM *geom = NULL;
+
+ srid = parse_gml_srs(xnode);
+
+ geom = (LWGEOM *)lwcollection_construct_empty(srid, 1, 0);
+ geom->type = lwgeom_makeType(1, 0, srid != -1, COLLECTIONTYPE);
+
+ for (xa = xnode->children ; xa != NULL ; xa = xa->next) {
+
+ if (xa->type != XML_ELEMENT_NODE) continue;
+
+ if ( !strcmp((char *) xa->name, "pointMember")
+ || !strcmp((char *) xa->name, "lineMember")
+ || !strcmp((char *) xa->name, "curveMember")
+ || !strcmp((char *) xa->name, "polygonMember")
+ || !strcmp((char *) xa->name, "surfaceMember")
+ || !strcmp((char *) xa->name, "geometryMember")) {
+
+ if (xa->children == NULL) break;
+ geom = lwcollection_add((LWCOLLECTION *)geom, -1,
+ parse_gml(xa->children, hasz));
+
+ } else if ( !strcmp((char *) xa->name, "MultiPoint")
+ || !strcmp((char *) xa->name, "MultiLineString")
+ || !strcmp((char *) xa->name, "MultiCurve")
+ || !strcmp((char *) xa->name, "MultiPolygon")
+ || !strcmp((char *) xa->name, "MultiSurface")
+ || !strcmp((char *) xa->name, "MultiGeometry")) {
+
+ if (xa->children == NULL) break;
+ geom = lwcollection_add((LWCOLLECTION *)geom, -1,
+ parse_gml(xa, hasz));
+ }
+ }
+
+ return geom;
+}
+
+
+/**
+ * Parse GML
+ */
+static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz)
+{
+ xmlNodePtr xa = xnode;
+
+ while (xa != NULL && xa->type != XML_ELEMENT_NODE) xa = xa->next;
+
+ if (!strcmp((char *) xa->name, "Point"))
+ return parse_gml_point(xa, hasz);
+
+ if (!strcmp((char *) xa->name, "LineString"))
+ return parse_gml_line(xa, hasz);
+
+ if (!strcmp((char *) xa->name, "Curve"))
+ return parse_gml_curve(xa, hasz);
+
+ if (!strcmp((char *) xa->name, "Polygon"))
+ return parse_gml_polygon(xa, hasz);
+
+ if (!strcmp((char *) xa->name, "Surface"))
+ return parse_gml_surface(xa, hasz);
+
+ if (!strcmp((char *) xa->name, "MultiPoint"))
+ return parse_gml_mpoint(xa, hasz);
+
+ if (!strcmp((char *) xa->name, "MultiLineString"))
+ return parse_gml_mline(xa, hasz);
+
+ if (!strcmp((char *) xa->name, "MultiCurve"))
+ return parse_gml_mcurve(xa, hasz);
+
+ if (!strcmp((char *) xa->name, "MultiPolygon"))
+ return parse_gml_mpoly(xa, hasz);
+
+ if (!strcmp((char *) xa->name, "MultiSurface"))
+ return parse_gml_msurface(xa, hasz);
+
+ if (!strcmp((char *) xa->name, "MultiGeometry"))
+ return parse_gml_coll(xa, hasz);
+
+ lwerror("invalid GML representation");
+ return NULL; /* Never reach */
+}
+
+#endif /* if HAVE_LIBXML2 */
AS 'MODULE_PATHNAME','geomequals'
LANGUAGE 'C' IMMUTABLE STRICT;
+
+#if HAVE_LIBXML2
+-----------------------------------------------------------------------
+-- GML INPUT
+-- Availability: 1.5.0
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION ST_GeomFromGML(text)
+ RETURNS geometry
+ AS 'MODULE_PATHNAME','geom_from_gml'
+ LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION ST_GMLToSQL(text)
+ RETURNS geometry
+ AS 'MODULE_PATHNAME','geom_from_gml'
+ LANGUAGE 'C' IMMUTABLE STRICT;
+
+#endif
-----------------------------------------------------------------------
-- SVG OUTPUT
-----------------------------------------------------------------------
POSTGIS_PGSQL_VERSION=@POSTGIS_PGSQL_VERSION@
POSTGIS_GEOS_VERSION=@POSTGIS_GEOS_VERSION@
POSTGIS_PROJ_VERSION=@POSTGIS_PROJ_VERSION@
+HAVE_LIBXML2=@HAVE_LIBXML2@
# MingW hack: rather than use PGSQL_BINDIR directly, we change
# to the directory and then use "pwd" to return the path. This
TESTS += hausdorff
endif
+# GeomFromGML need libxml2
+ifeq ($(shell expr $(HAVE_LIBXML2) "=" 1),1)
+ TESTS += in_gml
+endif
+
+
all: test
--- /dev/null
+--
+-- GeomFromGML regression test
+-- Written by Olivier Courtin - Oslandia
+--
+
+
+--
+-- spatial_ref_sys data
+--
+INSERT INTO "spatial_ref_sys" ("srid","auth_name","auth_srid","srtext","proj4text") VALUES (4326,'EPSG',4326,'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ');
+
+
+-- Empty Geometry
+SELECT 'empty_geom', ST_AsEWKT(ST_GeomFromGML(NULL));
+
+--
+-- XML
+--
+
+-- Empty String
+SELECT 'xml_1', ST_AsEWKT(ST_GeomFromGML(''));
+
+-- Not well formed XML
+SELECT 'xml_2', ST_AsEWKT(ST_GeomFromGML('<foo>'));
+
+-- Not a GML Geometry
+SELECT 'xml_3', ST_AsEWKT(ST_GeomFromGML('<foo/>'));
+
+
+
+--
+-- Point
+--
+
+-- 1 Point
+SELECT 'point_1', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point>'));
+
+-- ERROR: 2 points
+SELECT 'point_2', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates>1,2 3,4</gml:coordinates></gml:Point>'));
+
+-- ERROR: empty point
+SELECT 'point_3', ST_AsEWKT(ST_GeomFromGML('<gml:Point></gml:Point>'));
+
+-- srsName handle
+SELECT 'point_4', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="EPSG:4326"><gml:pos>1 2</gml:pos></gml:Point>'));
+
+
+
+--
+-- LineString
+--
+
+-- 2 Points
+SELECT 'linestring_1', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates>1,2 3,4</gml:coordinates></gml:LineString>'));
+
+-- ERROR 1 Point
+SELECT 'linestring_2', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates>1,2</gml:coordinates></gml:LineString>'));
+
+-- srsName handle
+SELECT 'linestring_3', ST_AsEWKT(ST_GeomFromGML('<gml:LineString srsName="EPSG:4326"><gml:coordinates>1,2 3,4</gml:coordinates></gml:LineString>'));
+
+-- ERROR: empty coordinates
+SELECT 'linestring_4', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates></gml:coordinates></gml:LineString>'));
+SELECT 'linestring_5', ST_AsEWKT(ST_GeomFromGML('<gml:LineString></gml:LineString>'));
+
+-- XML not elements handle
+SELECT 'linestring_6', ST_AsEWKT(ST_GeomFromGML(' <!-- --> <gml:LineString> <!-- --> <gml:coordinates>1,2 3,4</gml:coordinates></gml:LineString>'));
+
+
+
+
+--
+-- Curve
+--
+
+-- 2 Points
+SELECT 'curve_1', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>1 2 3 4</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+
+-- ERROR 1 Point
+SELECT 'curve_2', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>1 2</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+
+-- srsName handle
+SELECT 'curve_3', ST_AsEWKT(ST_GeomFromGML('<gml:Curve srsName="EPSG:4326"><gml:segments><gml:LineStringSegment><gml:posList>1 2 3 4</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+
+-- ERROR: empty coordinates
+SELECT 'curve_4', ST_AsEWKT(ST_GeomFromGML('<gml:Curve srsName="EPSG:4326"><gml:segments><gml:LineStringSegment><gml:posList></gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+SELECT 'curve_5', ST_AsEWKT(ST_GeomFromGML('<gml:Curve srsName="EPSG:4326"><gml:segments><gml:LineStringSegment></gml:LineStringSegment></gml:segments></gml:Curve>'));
+SELECT 'curve_6', ST_AsEWKT(ST_GeomFromGML('<gml:Curve srsName="EPSG:4326"><gml:segments></gml:segments></gml:Curve>'));
+SELECT 'curve_7', ST_AsEWKT(ST_GeomFromGML('<gml:Curve srsName="EPSG:4326"></gml:Curve>'));
+
+-- linear interpolation
+SELECT 'curve_8', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment interpolation="linear"><gml:posList>1 2 3 4</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+
+-- ERROR: wrong interpolation
+SELECT 'curve_9', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment interpolation="spline"><gml:posList>1 2 3 4</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+
+-- XML not elements handle
+SELECT 'curve_10', ST_AsEWKT(ST_GeomFromGML(' <!-- --> <gml:Curve> <!-- --> <gml:segments> <!-- --> <gml:LineStringSegment> <!-- --> <gml:posList>1 2 3 4</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+
+-- 2 Segments
+SELECT 'curve_11', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>1 2 3 4</gml:posList></gml:LineStringSegment><gml:LineStringSegment><gml:posList>3 4 5 6</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+SELECT 'curve_12', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList dimension="3">1 2 3 4 5 6</gml:posList></gml:LineStringSegment><gml:LineStringSegment><gml:posList dimension="3">4 5 6 7 8 9</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+
+-- ERROR 2 Segments disjoint
+SELECT 'curve_13', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>1 2 3 4</gml:posList></gml:LineStringSegment><gml:LineStringSegment><gml:posList>5 6 7 8</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+
+-- ERROR 2 3D Segments disjoint in Z
+SELECT 'curve_14', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList dimension="3">1 2 3 4 5 6</gml:posList></gml:LineStringSegment><gml:LineStringSegment><gml:posList dimension="3">4 5 0 7 8 9</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+
+-- 2 segments, mixed dimension
+SELECT 'curve_15', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList dimension="3">1 2 3 4 5 6</gml:posList></gml:LineStringSegment><gml:LineStringSegment><gml:posList dimension="2">4 5 7 8</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+SELECT 'curve_16', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList dimension="2">1 2 3 4</gml:posList></gml:LineStringSegment><gml:LineStringSegment><gml:posList dimension="3">3 4 5 6 7 8</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
+
+
+
+
+--
+-- Polygon
+--
+
+-- GML 2 - 1 ring
+SELECT 'polygon_1', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon>'));
+
+-- srsName handle
+SELECT 'polygon_2', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon>'));
+
+-- ERROR: In exterior ring: Last point is not the same as the first one
+SELECT 'polygon_3', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon>'));
+
+-- TODO ERROR: In exterior 3D ring: Last point is not the same as the first one in Z
+
+-- ERROR: Only 3 points in exterior ring
+SELECT 'polygon_4', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon>'));
+
+-- ERROR: Empty exterior ring coordinates
+SELECT 'polygon_5', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates></gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon>'));
+SELECT 'polygon_6', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon>'));
+SELECT 'polygon_7', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:outerBoundaryIs></gml:outerBoundaryIs></gml:Polygon>'));
+SELECT 'polygon_8', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon></gml:Polygon>'));
+
+-- GML 2 - 2 rings
+SELECT 'polygon_9', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7,8 9,10 11,12 7,8</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon>'));
+
+-- XML not elements handle
+SELECT 'polygon_10', ST_AsEWKT(ST_GeomFromGML(' <!-- --> <gml:Polygon> <!-- --> <gml:outerBoundaryIs> <!-- --> <gml:LinearRing> <!-- --> <gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs> <!-- --> <gml:innerBoundaryIs> <!-- --> <gml:LinearRing><gml:coordinates>7,8 9,10 11,12 7,8</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon>'));
+
+-- Empty interior ring coordinates (even if defined)
+SELECT 'polygon_11', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs></gml:innerBoundaryIs></gml:Polygon>'));
+
+-- ERROR: Only 3 points in interior ring
+SELECT 'polygon_12', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7,8 9,10 7,8</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon>'));
+
+-- ERROR: In interior ring: Last point is not the same as the first one
+SELECT 'polygon_13', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7,8 9,10 11,12 7,9</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon>'));
+
+-- TODO ERROR: In interior 3D ring: Last point is not the same as the first one in Z
+
+-- GML 2 - 3 rings
+SELECT 'polygon_14', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7,8 9,10 11,12 7,8</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>13,14 15,16 17,18 13,14</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon>'));
+
+-- GML 3
+SELECT 'polygon_15', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:coordinates>7,8 9,10 11,12 7,8</gml:coordinates></gml:LinearRing></gml:interior></gml:Polygon>'));
+
+-- Mixed dimension in rings
+SELECT 'polygon_16', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:exterior><gml:LinearRing><gml:posList dimension="3">1 2 3 4 5 6 7 8 9 1 2 3</gml:posList></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:posList dimension="2">10 11 12 13 14 15 10 11</gml:posList></gml:LinearRing></gml:interior></gml:Polygon>'));
+SELECT 'polygon_17', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:exterior><gml:LinearRing><gml:posList dimension="2">1 2 3 4 5 6 1 2</gml:posList></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:posList dimension="3">7 8 9 10 11 12 13 14 15 7 8 9</gml:posList></gml:LinearRing></gml:interior></gml:Polygon>'));
+
+
+
+
+--
+-- Surface
+--
+
+-- 1 ring
+SELECT 'surface_1', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- srsName handle
+SELECT 'surface_2', ST_AsEWKT(ST_GeomFromGML('<gml:Surface srsName="EPSG:4326"><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- ERROR: In exterior ring: Last point is not the same as the first one
+SELECT 'surface_3', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,0</gml:coordinates></gml:LinearRing></gml:exterior></gml:PolygonPatch></gml:patches></gml:Surfacne>'));
+
+-- TODO -- ERROR: In exterior 3D ring: Last point is not the same as the first one in Z
+
+-- ERROR: Only 3 points in exterior ring
+SELECT 'surface_4', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 1,2</gml:coordinates></gml:LinearRing></gml:exterior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- ERROR: Empty exterior ring coordinates
+SELECT 'surface_5', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing></gml:LinearRing></gml:exterior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+SELECT 'surface_6', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior></gml:exterior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+SELECT 'surface_7', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch></gml:PolygonPatch></gml:patches></gml:Surface>'));
+SELECT 'surface_8', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches></gml:patches></gml:Surface>'));
+SELECT 'surface_9', ST_AsEWKT(ST_GeomFromGML('<gml:Surface></gml:Surface>'));
+
+-- 2 rings
+SELECT 'surface_10', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:coordinates>7,8 9,10 11,12 7,8</gml:coordinates></gml:LinearRing></gml:interior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- XML not elements handle
+SELECT 'surface_11', ST_AsEWKT(ST_GeomFromGML(' <!-- --> <gml:Surface> <!-- --> <gml:patches> <!-- --> <gml:PolygonPatch> <!-- --> <gml:exterior> <!-- --> <gml:LinearRing> <!-- --> <gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior> <!-- --> <gml:interior> <!-- --> <gml:LinearRing> <!-- --> <gml:coordinates>7,8 9,10 11,12 7,8</gml:coordinates></gml:LinearRing></gml:interior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- Empty interior ring coordinates (even if defined)
+SELECT 'surface_12', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior><gml:interior></gml:interior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- ERROR: Only 3 points in interior ring
+SELECT 'surface_13', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:coordinates>7,8 9,10 7,8</gml:coordinates></gml:LinearRing></gml:interior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- ERROR: In interior ring: Last point is not the same as the first one
+SELECT 'surface_14', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:coordinates>7,8 9,10 11,12 7,0</gml:coordinates></gml:LinearRing></gml:interior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- TODO -- ERROR: In interior 3D ring: Last point is not the same as the first one in Z
+
+-- 3 rings
+SELECT 'surface_15', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:coordinates>7,8 9,10 11,12 7,8</gml:coordinates></gml:LinearRing></gml:interior><gml:interior><gml:LinearRing><gml:coordinates>13,14 15,16 17,18 13,14</gml:coordinates></gml:LinearRing></gml:interior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- Mixed dimension in rings
+SELECT 'surface_16', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:posList dimension="3">1 2 3 4 5 6 7 8 9 1 2 3</gml:posList></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:posList dimension="2">10 11 12 13 14 15 10 11</gml:posList></gml:LinearRing></gml:interior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+SELECT 'surface_17', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:posList dimension="2">1 2 3 4 5 6 1 2</gml:posList></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:posList dimension="3">7 8 9 10 11 12 13 14 15 7 8 9</gml:posList></gml:LinearRing></gml:interior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- ERROR: two patches
+SELECT 'surface_18', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior></gml:PolygonPatch><gml:PolygonPatch><gml:exterior><gml:LinearRing><gml:coordinates>7,8 9,10 11,12 7,8</gml:coordinates></gml:LinearRing></gml:exterior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- planar interpolation
+SELECT 'surface_19', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch interpolation="planar"><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+-- ERROR: interpolation not planar
+SELECT 'surface_20', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch interpolation="not_planar"><gml:exterior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:exterior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
+
+
+
+--
+-- MultiPoint
+--
+
+-- 1 point
+SELECT 'mpoint_1', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPoint><gml:pointMember><gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point></gml:pointMember></gml:MultiPoint>'));
+
+-- 2 points
+SELECT 'mpoint_2', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPoint><gml:pointMember><gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point></gml:pointMember><gml:pointMember><gml:Point><gml:coordinates>3,4</gml:coordinates></gml:Point></gml:pointMember></gml:MultiPoint>'));
+
+-- srsName handle
+SELECT 'mpoint_3', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPoint srsName="EPSG:4326"><gml:pointMember><gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point></gml:pointMember></gml:MultiPoint>'));
+
+-- Empty MultiPoints
+SELECT 'mpoint_4', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPoint><gml:pointMember></gml:pointMember></gml:MultiPoint>'));
+SELECT 'mpoint_5', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPoint></gml:MultiPoint>'));
+
+-- XML not elements handle
+SELECT 'mpoint_6', ST_AsEWKT(ST_GeomFromGML(' <!-- --> <gml:MultiPoint> <!-- --> <gml:pointMember> <!-- --> <gml:Point> <!-- --> <gml:coordinates>1,2</gml:coordinates></gml:Point></gml:pointMember> <!-- --> <gml:pointMember> <!-- --> <gml:Point> <!-- --> <gml:coordinates>3,4</gml:coordinates></gml:Point></gml:pointMember></gml:MultiPoint>'));
+
+-- TODO Mixed srsName
+
+
+
+
+--
+-- MultiLineString
+--
+
+-- 1 line
+SELECT 'mline_1', ST_AsEWKT(ST_GeomFromGML('<gml:MultiLineString><gml:lineStringMember><gml:LineString><gml:coordinates>1,2 3,4</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString>'));
+
+-- 2 lines
+SELECT 'mline_2', ST_AsEWKT(ST_GeomFromGML('<gml:MultiLineString><gml:lineStringMember><gml:LineString><gml:coordinates>1,2 3,4</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>5,6 7,8</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString>'));
+
+-- srsName handle
+SELECT 'mline_3', ST_AsEWKT(ST_GeomFromGML('<gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>1,2 3,4</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString>'));
+
+-- Empty MultiLineString
+SELECT 'mline_4', ST_AsEWKT(ST_GeomFromGML('<gml:MultiLineString><gml:lineStringMember></gml:lineStringMember></gml:MultiLineString>'));
+SELECT 'mline_5', ST_AsEWKT(ST_GeomFromGML('<gml:MultiLineString></gml:MultiLineString>'));
+
+-- XML not elements handle
+SELECT 'mline_6', ST_AsEWKT(ST_GeomFromGML(' <!-- --> <gml:MultiLineString> <!-- --> <gml:lineStringMember> <!-- --> <gml:LineString> <!-- --> <gml:coordinates>1,2 3,4</gml:coordinates></gml:LineString></gml:lineStringMember> <!-- --> <gml:lineStringMember> <!-- --> <gml:LineString> <!-- --> <gml:coordinates>5,6 7,8</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString>'));
+
+-- Mixed dimension
+SELECT 'mline_7', ST_AsEWKT(ST_GeomFromGML('<gml:MultiLineString><gml:lineStringMember><gml:LineString><gml:posList dimension="3">1 2 3 4 5 6</gml:posList></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:posList dimension="2">7 8 9 10</gml:posList></gml:LineString></gml:lineStringMember></gml:MultiLineString>'));
+SELECT 'mline_8', ST_AsEWKT(ST_GeomFromGML('<gml:MultiLineString><gml:lineStringMember><gml:LineString><gml:posList dimension="2">1 2 3 4</gml:posList></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:posList dimension="3">5 6 7 8 9 10</gml:posList></gml:LineString></gml:lineStringMember></gml:MultiLineString>'));
+
+-- TODO Mixed srsName
+
+
+
+
+--
+-- MultiCurve
+--
+
+-- 1 curve
+SELECT 'mcurve_1', ST_AsEWKT(ST_GeomFromGML('<gml:MultiCurve><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>1 2 3 4</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve>'));
+
+-- 2 curves
+SELECT 'mcurve_2', ST_AsEWKT(ST_GeomFromGML('<gml:MultiCurve><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>1 2 3 4</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>5 6 7 8</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve>'));
+
+-- srsName handle
+SELECT 'mcurve_3', ST_AsEWKT(ST_GeomFromGML('<gml:MultiCurve srsName="EPSG:4326"><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>1 2 3 4</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve>'));
+
+-- Empty Curve
+SELECT 'mcurve_4', ST_AsEWKT(ST_GeomFromGML('<gml:MultiCurve><gml:curveMember></gml:curveMember></gml:MultiCurve>'));
+SELECT 'mcurve_5', ST_AsEWKT(ST_GeomFromGML('<gml:MultiCurve></gml:MultiCurve>'));
+
+-- XML not elements handle
+SELECT 'mcurve_6', ST_AsEWKT(ST_GeomFromGML(' <!-- --> <gml:MultiCurve> <!-- --> <gml:curveMember> <!-- --> <gml:Curve> <!-- --> <gml:segments> <!-- --> <gml:LineStringSegment> <!-- --> <gml:posList>1 2 3 4</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember> <!-- --> <gml:curveMember> <!-- --> <gml:Curve> <!-- --> <gml:segments> <!-- --> <gml:LineStringSegment><gml:posList>5 6 7 8</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve>'));
+
+-- Mixed dimension
+SELECT 'mcurve_7', ST_AsEWKT(ST_GeomFromGML('<gml:MultiCurve><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList dimension="3">1 2 3 4 5 6</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList dimension="2">7 8 9 10</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve>'));
+SELECT 'mcurve_8', ST_AsEWKT(ST_GeomFromGML('<gml:MultiCurve><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList dimension="2">1 2 3 4</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList dimension="3">5 6 7 8 9 10</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve>'));
+
+-- TODO Mixed srsName
+
+
+
+--
+-- MultiPolygon
+--
+
+-- 1 polygon
+SELECT 'mpoly_1', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPolygon><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon>'));
+
+-- 2 polygons
+SELECT 'mpoly_2', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPolygon><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>7,8 9,10 11,12 7,8</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon>'));
+
+-- srsName handle
+SELECT 'mpoly_3', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon>'));
+
+-- Empty MultiPolygon
+SELECT 'mpoly_4', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPolygon><gml:polygonMember></gml:polygonMember></gml:MultiPolygon>'));
+SELECT 'mpoly_5', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPolygon></gml:MultiPolygon>'));
+
+
+-- XML not elements handle
+SELECT 'mpoly_6', ST_AsEWKT(ST_GeomFromGML(' <!-- --> <gml:MultiPolygon> <!-- --> <gml:polygonMember> <!-- --> <gml:Polygon> <!-- --> <gml:outerBoundaryIs> <!-- --> <gml:LinearRing> <!-- --> <gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember> <!-- --> <gml:polygonMember> <!-- --> <gml:Polygon> <!-- --> <gml:outerBoundaryIs> <!-- --> <gml:LinearRing> <!-- --> <gml:coordinates>7,8 9,10 11,12 7,8</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon>'));
+
+-- Mixed dimension
+SELECT 'mpoly_7', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPolygon><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:posList dimension="3">1 2 3 4 5 6 7 8 9 1 2 3</gml:posList></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:posList dimension="2">10 11 12 13 14 15 10 11</gml:posList></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon>'));
+SELECT 'mpoly_8', ST_AsEWKT(ST_GeomFromGML('<gml:MultiPolygon><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:posList dimension="2">1 2 3 4 5 6 1 2</gml:posList></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:posList dimension="3">7 8 9 10 11 12 13 14 15 7 8 9</gml:posList></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon>'));
+
+-- TODO Mixed srsName
+
+
+
+
+--
+-- MultiSurface
+--
+
+-- 1 surface
+SELECT 'msurface_1', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>1 2 3 4 5 6 1 2</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiSurface>'));
+
+-- 2 surfaces
+SELECT 'msurface_2', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>1 2 3 4 5 6 1 2</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>7 8 9 10 11 12 7 8</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiSurface>'));
+
+-- srsName handle
+SELECT 'msurface_3', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface srsName="EPSG:4326"><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>1 2 3 4 5 6 1 2</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiSurface>'));
+
+-- Empty MultiSurface
+SELECT 'msurface_4', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface><gml:surfaceMember></gml:surfaceMember></gml:MultiSurface>'));
+SELECT 'msurface_5', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface></gml:MultiSurface>'));
+
+-- XML not elements handle
+SELECT 'msurface_6', ST_AsEWKT(ST_GeomFromGML(' <!-- --> <gml:MultiSurface> <!-- --> <gml:surfaceMember> <!-- --> <gml:Polygon> <!-- --> <gml:exterior> <!-- --> <gml:LinearRing> <!-- --> <gml:posList>1 2 3 4 5 6 1 2</gml:posList></gml:LinearRing></gml:exterior> <!-- --> </gml:Polygon> <!-- --> </gml:surfaceMember> <!-- --> <gml:surfaceMember> <!-- --> <gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>7 8 9 10 11 12 7 8</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiSurface>'));
+
+-- Mixed dimension
+SELECT 'msurface_7', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList dimension="3">1 2 3 4 5 6 7 8 9 1 2 3</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList dimension="2">10 11 12 13 14 15 10 11</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiSurface>'));
+SELECT 'msurface_8', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList dimension="2">1 2 3 4 5 6 1 2</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList dimension="3">7 8 9 10 11 12 13 14 15 7 8 9</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiSurface>'));
+
+-- TODO Mixed srsName
+
+
+
+--
+-- GeometryCollection
+--
+
+-- 1 simple geom
+SELECT 'collection_1', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry><gml:pointMember><gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point></gml:pointMember></gml:MultiGeometry>'));
+
+-- 2 simples geom
+SELECT 'collection_2', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry><gml:pointMember><gml:Point><gml:pos>1 2</gml:pos></gml:Point></gml:pointMember><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>3 4 5 6</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember></gml:MultiGeometry>'));
+
+-- 1 multi geom
+SELECT 'collection_3', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry><gml:MultiPoint><gml:pointMember><gml:Point><gml:pos>1 2</gml:pos></gml:Point></gml:pointMember><gml:pointMember><gml:Point><gml:pos>3 4</gml:pos></gml:Point></gml:pointMember></gml:MultiPoint></gml:MultiGeometry>'));
+
+-- 2 multi geom
+SELECT 'collection_4', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry><gml:MultiPoint><gml:pointMember><gml:Point><gml:pos>1 2</gml:pos></gml:Point></gml:pointMember><gml:pointMember><gml:Point><gml:pos>3 4</gml:pos></gml:Point></gml:pointMember></gml:MultiPoint><gml:MultiCurve><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>5 6 7 8</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>9 10 11 12</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve></gml:MultiGeometry>'));
+
+-- 2 multi geom and 2 simples
+SELECT 'collection_5', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry><gml:MultiPoint><gml:pointMember><gml:Point><gml:pos>1 2</gml:pos></gml:Point></gml:pointMember><gml:pointMember><gml:Point><gml:pos>3 4</gml:pos></gml:Point></gml:pointMember></gml:MultiPoint><gml:pointMember><gml:Point><gml:pos>5 6</gml:pos></gml:Point></gml:pointMember><gml:MultiCurve><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>7 8 9 10</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>11 12 13 14</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve><gml:surfaceMember><gml:Polygon><gml:exterior><gml:LinearRing><gml:posList>15 16 17 18 19 20 15 16</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiGeometry>'));
+
+-- Empty collection
+SELECT 'collection_6', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry><gml:pointMember></gml:pointMember></gml:MultiGeometry>'));
+SELECT 'collection_7', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry></gml:MultiGeometry>'));
+
+-- Collection of collection
+SELECT 'collection_8', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry><gml:pointMember><gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point></gml:pointMember><gml:MultiGeometry><gml:pointMember><gml:Point><gml:coordinates>3,4</gml:coordinates></gml:Point></gml:pointMember></gml:MultiGeometry></gml:MultiGeometry>'));
+
+-- Collection of collection of collection
+SELECT 'collection_9', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry><gml:pointMember><gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point></gml:pointMember><gml:MultiGeometry><gml:MultiGeometry><gml:pointMember><gml:Point><gml:coordinates>3,4</gml:coordinates></gml:Point></gml:pointMember></gml:MultiGeometry></gml:MultiGeometry></gml:MultiGeometry>'));
+
+-- srsName handle
+SELECT 'collection_10', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry srsName="EPSG:4326"><gml:pointMember><gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point></gml:pointMember></gml:MultiGeometry>'));
+
+-- XML not elements handle
+SELECT 'collection_11', ST_AsEWKT(ST_GeomFromGML(' <!-- --> <gml:MultiGeometry> <!-- --> <gml:pointMember> <!-- --> <gml:Point> <!-- --> <gml:coordinates>1,2</gml:coordinates></gml:Point></gml:pointMember> <!-- --> <gml:MultiGeometry> <!-- --> <gml:MultiGeometry> <!-- --> <gml:pointMember> <!-- --> <gml:Point> <!-- --> <gml:coordinates>3,4</gml:coordinates></gml:Point></gml:pointMember></gml:MultiGeometry></gml:MultiGeometry></gml:MultiGeometry>'));
+
+-- Mixed dimension
+SELECT 'collection_12', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry><gml:pointMember><gml:Point><gml:pos dimension="3">1 2 3</gml:pos></gml:Point></gml:pointMember><gml:MultiGeometry><gml:MultiGeometry><gml:pointMember><gml:Point><gml:pos dimension="2">4 5</gml:pos></gml:Point></gml:pointMember></gml:MultiGeometry></gml:MultiGeometry></gml:MultiGeometry>'));
+SELECT 'collection_13', ST_AsEWKT(ST_GeomFromGML('<gml:MultiGeometry><gml:pointMember><gml:Point><gml:pos dimension="2">1 2</gml:pos></gml:Point></gml:pointMember><gml:MultiGeometry><gml:MultiGeometry><gml:pointMember><gml:Point><gml:pos dimension="3">3 4 5</gml:pos></gml:Point></gml:pointMember></gml:MultiGeometry></gml:MultiGeometry></gml:MultiGeometry>'));
+
+-- TODO Mixed srsName
+
+
+
+
+
+--
+-- srsName
+--
+
+-- Supported srsName patterns
+SELECT 'srs_1', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="EPSG:4326"><gml:pos>1 2</gml:pos></gml:Point>'));
+SELECT 'srs_2', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="urn:EPSG:geographicCRS:4326"><gml:pos>1 2</gml:pos></gml:Point>'));
+SELECT 'srs_3', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="urn:ogc:def:crs:EPSG:4326"><gml:pos>1 2</gml:pos></gml:Point>'));
+SELECT 'srs_4', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="urn:ogc:def:crs:EPSG:4326"><gml:pos>1 2</gml:pos></gml:Point>'));
+SELECT 'srs_5', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="urn:ogc:def:crs:EPSG::4326"><gml:pos>1 2</gml:pos></gml:Point>'));
+SELECT 'srs_6', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="urn:ogc:def:crs:EPSG:6.6:4326"><gml:pos>1 2</gml:pos></gml:Point>'));
+SELECT 'srs_7', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="urn:x-ogc:def:crs:EPSG:6.6:4326"><gml:pos>1 2</gml:pos></gml:Point>'));
+SELECT 'srs_8', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"><gml:pos>1 2</gml:pos></gml:Point>'));
+
+-- ERROR not a valid pattern
+SELECT 'srs_9', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="a:wrong:pattern:4326"><gml:pos>1 2</gml:pos></gml:Point>'));
+
+-- ERROR: not a defined SRID
+SELECT 'srs_10', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="EPSG:01"><gml:pos>1 2</gml:pos></gml:Point>'));
+
+-- ERROR: SRID is not an int
+SELECT 'srs_11', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="EPSG:abc"><gml:pos>1 2</gml:pos></gml:Point>'));
+
+-- ERROR: SRID is not only int
+SELECT 'srs_12', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="EPSG:4326abc"><gml:pos>1 2</gml:pos></gml:Point>'));
+SELECT 'srs_13', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="EPSG:abc4326"><gml:pos>1 2</gml:pos></gml:Point>'));
+
+-- ERROR: srsName empty
+SELECT 'srs_14', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="EPSG:"><gml:pos>1 2</gml:pos></gml:Point>'));
+SELECT 'srs_15', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName=""><gml:pos>1 2</gml:pos></gml:Point>'));
+
+-- ERROR: srsName is defined as -1
+SELECT 'srs_16', ST_AsEWKT(ST_GeomFromGML('<gml:Point srsName="EPSG:-1"><gml:pos>1 2</gml:pos></gml:Point>'));
+
+
+
+--
+-- TODO GML Namespace
+--
+
+--
+-- TODO xlink/Reference
+--
+
+
+--
+-- Coordinates (simple)
+--
+
+-- X,Y
+SELECT 'coordinates_1', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point>'));
+
+-- ERROR: single X
+SELECT 'coordinates_2', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates>1</gml:coordinates></gml:Point>'));
+
+-- X,Y,Z
+SELECT 'coordinates_3', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates>1,2,3</gml:coordinates></gml:Point>'));
+
+-- ERROR: 4 dimension
+SELECT 'coordinates_4', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates>1,2,3,4</gml:coordinates></gml:Point>'));
+
+-- ERROR: Only commas
+SELECT 'coordinates_5', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates>,</gml:coordinates></gml:Point>'));
+SELECT 'coordinates_6', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates> , </gml:coordinates></gml:Point>'));
+
+-- ERROR: empty or spaces
+SELECT 'coordinates_7', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates></gml:coordinates></gml:Point>'));
+SELECT 'coordinates_8', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates> </gml:coordinates></gml:Point>'));
+
+-- ERROR: End on comma
+SELECT 'coordinates_9', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates>1,2,3,</gml:coordinates></gml:Point>'));
+SELECT 'coordinates_10', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates>1,2,</gml:coordinates></gml:Point>'));
+
+-- ERROR: Begin on comma
+SELECT 'coordinates_11', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates>,1 2,3</gml:coordinates></gml:LineString>'));
+
+-- Whitespaces before and after
+SELECT 'coordinates_12', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates> 1,2 3,4 </gml:coordinates></gml:LineString>'));
+SELECT 'coordinates_13', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates>
+ 1,2 3,4
+ </gml:coordinates></gml:LineString>'));
+
+-- Mixed dimension
+SELECT 'coordinates_14', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates>1,2,3 4,5</gml:coordinates></gml:LineString>'));
+
+-- ERROR: Spaces insides
+SELECT 'coordinates_15', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates>1, 2 3, 4</gml:coordinates></gml:LineString>'));
+SELECT 'coordinates_16', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates>1,2 3,4</gml:coordinates></gml:LineString>'));
+
+-- ERROR: Junk
+SELECT 'coordinates_17', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates>!@#$%^*()"</gml:coordinates></gml:LineString>'));
+
+
+
+
+--
+-- Coordinates (cs,ts,decimal)
+--
+
+-- Specify default CS separator
+SELECT 'coordinates_cs_1', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates cs="," >1,2</gml:coordinates></gml:Point>'));
+
+-- ERROR: wrong CS separator
+SELECT 'coordinates_cs_2', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates cs=";" >1,2</gml:coordinates></gml:Point>'));
+
+-- Specify a CS separator
+SELECT 'coordinates_cs_3', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates cs=";" >1;2</gml:coordinates></gml:Point>'));
+
+-- ERROR: CS separator is a number
+SELECT 'coordinates_cs_4', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates cs="0" >102</gml:coordinates></gml:Point>'));
+
+-- ERROR: CS separator is multichar
+SELECT 'coordinates_cs_5', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coordinates cs="||" >1||2</gml:coordinates></gml:Point>'));
+
+-- Specify default TS separator
+SELECT 'coordinates_cs_6', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates ts=" ">1,2 3,4</gml:coordinates></gml:LineString>'));
+
+-- ERROR: wrong TS separator
+SELECT 'coordinates_cs_7', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates ts=" ">1,2;3,4</gml:coordinates></gml:LineString>'));
+
+-- Specify a TS separator
+SELECT 'coordinates_cs_8', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates ts=";">1,2;3,4</gml:coordinates></gml:LineString>'));
+
+-- ERROR: TS separator is a number
+SELECT 'coordinates_cs_9', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates ts="0">1,203,4</gml:coordinates></gml:LineString>'));
+
+-- ERROR: TS separator is multichar
+SELECT 'coordinates_cs_10', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates ts="||">1,2||3,4</gml:coordinates></gml:LineString>'));
+
+-- Specify default Decimal separator
+SELECT 'coordinates_cs_11', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates decimal=".">1.1,2.2 3.3,4.4</gml:coordinates></gml:LineString>'));
+
+-- ERROR: wrong Decimal separator
+SELECT 'coordinates_cs_12', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates decimal=";">1;1,2;2 3;3,4;4</gml:coordinates></gml:LineString>'));
+
+-- ERROR: Decimal separator is a number
+SELECT 'coordinates_cs_13', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates decimal="0">101,202 303,404</gml:coordinates></gml:LineString>'));
+
+-- ERROR: Decimal separator is multichar
+SELECT 'coordinates_cs_14', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates decimal="||">1||1,2||2 3||3,4||4</gml:coordinates></gml:LineString>'));
+
+-- CS and TS and Decimal together
+SELECT 'coordinates_cs_15', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates cs="." ts=";" decimal=",">1,1.2,2;3,3.4,4</gml:coordinates></gml:LineString>'));
+
+-- ERROR: CS and Decimal are the same
+SELECT 'coordinates_cs_16', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates ts=" " cs=" ">1 2 3 4</gml:coordinates></gml:LineString>'));
+SELECT 'coordinates_cs_17', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates cs="." ts=";" decimal=".">1.1.2.2;3.3.4,4</gml:coordinates></gml:LineString>'));
+SELECT 'coordinates_cs_18', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates cs="." ts=";" decimal=";">1;1.2;2;3;3.4,4</gml:coordinates></gml:LineString>'));
+
+
+-- XML Entity substitution
+SELECT 'coordinates_cs_19', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coordinates ts="," cs=" ">1 2,3 4</gml:coordinates></gml:LineString>'));
+
+
+
+
+--
+-- pos
+--
+
+-- X,Y
+SELECT 'pos_1', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 2</gml:pos></gml:Point>'));
+
+-- ERROR: single X
+SELECT 'pos_2', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1</gml:pos></gml:Point>'));
+
+-- ERROR: X,Y,Z but without explicit dimension
+SELECT 'pos_3', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 2 3</gml:pos></gml:Point>'));
+
+-- ERROR: 4 dimension
+SELECT 'pos_4', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 2 3 4</gml:pos></gml:Point>'));
+
+-- ERROR: empty or spaces
+SELECT 'pos_5', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos></gml:pos></gml:Point>'));
+SELECT 'pos_6', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos> </gml:pos></gml:Point>'));
+SELECT 'pos_7', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos> </gml:pos></gml:Point>'));
+
+-- Whitespaces before and after
+SELECT 'pos_8', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos> 1 2 </gml:pos></gml:Point>'));
+SELECT 'pos_9', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos> 1 2 </gml:pos></gml:Point>'));
+SELECT 'pos_10', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>
+ 1 2
+ </gml:pos></gml:Point>'));
+-- ERROR: Several Spaces insides
+SELECT 'pos_11', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 2</gml:pos></gml:Point>'));
+
+-- ERROR: Junk
+SELECT 'pos_12', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>@!#$#%</gml:pos></gml:Point>'));
+
+-- ERROR: 1 dimension
+SELECT 'pos_13', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos dimension="1">1</gml:pos></gml:Point>'));
+
+-- 2 Dimensions explicit
+SELECT 'pos_14', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos dimension="2">1 2</gml:pos></gml:Point>'));
+
+-- ERROR: 2 Dimensions explicit but 3 dims
+SELECT 'pos_15', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos dimension="2">1 2 3</gml:pos></gml:Point>'));
+
+-- 3 Dimensions explicit
+SELECT 'pos_16', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos dimension="3">1 2 3</gml:pos></gml:Point>'));
+
+-- ERROR: 4 dimensions
+SELECT 'pos_17', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos dimension="4">1 2 3 4</gml:pos></gml:Point>'));
+
+
+--
+-- posList
+--
+-- 2 coords
+SELECT 'poslist_1', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList>1 2 3 4</gml:posList></gml:LineString>'));
+
+-- spaces before and after
+SELECT 'poslist_2', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList> 1 2 3 4 </gml:posList></gml:LineString>'));
+SELECT 'poslist_3', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList> 1 2 3 4 </gml:posList></gml:LineString>'));
+SELECT 'poslist_4', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList>
+ 1 2 3 4
+ </gml:posList></gml:LineString>'));
+
+-- explicit 2 dimension
+SELECT 'poslist_5', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList dimension="2">1 2 3 4</gml:posList></gml:LineString>'));
+-- ERROR: wrong dimension
+SELECT 'poslist_6', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList> 1 2 3 4 5 </gml:posList></gml:LineString>'));
+SELECT 'poslist_7', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList dimension="2">1 2 3 4 5</gml:posList></gml:LineString>'));
+
+-- 2 coord 3D
+SELECT 'poslist_8', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList dimension="3">1 2 3 4 5 6</gml:posList></gml:LineString>'));
+
+-- ERROR: 1 dimension
+SELECT 'poslist_9', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList>1</gml:posList></gml:LineString>'));
+SELECT 'poslist_10', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList dimension="1">1</gml:posList></gml:LineString>'));
+
+-- ERROR: 4 dimensions
+SELECT 'poslist_11', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList dimension="4">1 2 3 4 5 6 7 8</gml:posList></gml:LineString>'));
+
+-- ERROR: 3D but no explicit dimension
+SELECT 'poslist_12', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList>1 2 3</gml:posList></gml:LineString>'));
+
+-- ERROR: empty or spaces
+SELECT 'poslist_13', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList></gml:posList></gml:LineString>'));
+SELECT 'poslist_14', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList> </gml:posList></gml:LineString>'));
+SELECT 'poslist_15', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList> </gml:posList></gml:LineString>'));
+
+-- ERROR: spaces insides posList
+SELECT 'poslist_16', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList>1 2 3 4</gml:posList></gml:LineString>'));
+SELECT 'poslist_17', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList> 1 2 3 4 </gml:posList></gml:LineString>'));
+
+-- ERROR: Junk
+SELECT 'poslist_18', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:posList>!@#$%^*()"</gml:posList></gml:LineString>'));
+
+
+
+
+
+--
+-- coord
+--
+
+-- X,Y
+SELECT 'coord_1', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord><gml:X>1</gml:X><gml:Y>2</gml:Y></gml:coord></gml:Point>'));
+
+-- X,Y,Z
+SELECT 'coord_2', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord><gml:X>1</gml:X><gml:Y>2</gml:Y><gml:Z>3</gml:Z></gml:coord></gml:Point>'));
+
+-- ERROR no X or Y
+SELECT 'coord_3', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord><gml:X>1</gml:X><gml:Z>2</gml:Z></gml:coord></gml:Point>'));
+SELECT 'coord_4', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord><gml:Y>1</gml:Y><gml:Z>2</gml:Z></gml:coord></gml:Point>'));
+SELECT 'coord_5', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord><gml:Z>1</gml:Z></gml:coord></gml:Point>'));
+
+-- ERROR empty coord even if defined
+SELECT 'coord_6', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord><gml:X></gml:X><gml:Y></gml:Y></gml:coord></gml:Point>'));
+SELECT 'coord_7', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord></gml:coord></gml:Point>'));
+
+-- ERROR space in coord
+SELECT 'coord_8', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord><gml:X>1</gml:X><gml:Y> </gml:Y></gml:coord></gml:Point>'));
+SELECT 'coord_9', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord><gml:X>1</gml:X><gml:Y> </gml:Y></gml:coord></gml:Point>'));
+
+-- Spaces before and after coord
+SELECT 'coord_10', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord><gml:X>1</gml:X><gml:Y> 2 </gml:Y></gml:coord></gml:Point>'));
+SELECT 'coord_11', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord><gml:X>1</gml:X><gml:Y> 2 </gml:Y></gml:coord></gml:Point>'));
+SELECT 'coord_12', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:coord><gml:X>1</gml:X><gml:Y>
+ 2
+ </gml:Y></gml:coord></gml:Point>'));
+
+-- Several coords
+SELECT 'coord_13', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coord><gml:X>1</gml:X><gml:Y>2</gml:Y></gml:coord><gml:coord><gml:X>3</gml:X><gml:Y>4</gml:Y></gml:coord></gml:LineString>'));
+
+-- Several coords mixed dimension
+SELECT 'coord_14', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coord><gml:X>1</gml:X><gml:Y>2</gml:Y><gml:Z>3</gml:Z></gml:coord><gml:coord><gml:X>4</gml:X><gml:Y>5</gml:Y></gml:coord></gml:LineString>'));
+SELECT 'coord_15', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coord><gml:X>1</gml:X><gml:Y>2</gml:Y></gml:coord><gml:coord><gml:X>3</gml:X><gml:Y>4</gml:Y><gml:Z>5</gml:Z></gml:coord></gml:LineString>'));
+
+-- XML not elements handle
+SELECT 'coord_16', ST_AsEWKT(ST_GeomFromGML('<gml:LineString><gml:coord> <!-- --> <gml:X>1</gml:X> <!-- --> <gml:Y>2</gml:Y> <!-- --> </gml:coord> <!-- --> <gml:coord> <!-- --> <gml:X>3</gml:X> <!-- --> <gml:Y>4</gml:Y></gml:coord></gml:LineString>'));
+
+
+--
+-- Double
+--
+
+-- Several digits
+SELECT 'double_1', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1234567890</gml:pos></gml:Point>'));
+
+-- Sign +/-
+SELECT 'double_2', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 -1</gml:pos></gml:Point>'));
+SELECT 'double_3', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 +1</gml:pos></gml:Point>'));
+
+-- ERROR: double sign
+SELECT 'double_4', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 --1</gml:pos></gml:Point>'));
+
+-- ERROR: sign inside digit
+SELECT 'double_5', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1-1</gml:pos></gml:Point>'));
+
+-- Decimal part
+SELECT 'double_6', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1.2</gml:pos></gml:Point>'));
+SELECT 'double_7', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1.23</gml:pos></gml:Point>'));
+
+-- ERROR: no digit after dot
+SELECT 'double_8', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1.</gml:pos></gml:Point>'));
+
+-- ERROR: several dots
+SELECT 'double_9', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1.2.3</gml:pos></gml:Point>'));
+
+-- ERROR: no digit before dot
+SELECT 'double_10', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 .1</gml:pos></gml:Point>'));
+SELECT 'double_11', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 -.1</gml:pos></gml:Point>'));
+
+-- ERROR: not a digit
+SELECT 'double_12', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 a</gml:pos></gml:Point>'));
+SELECT 'double_13', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1a</gml:pos></gml:Point>'));
+SELECT 'double_14', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1a2</gml:pos></gml:Point>'));
+
+-- Exp
+SELECT 'double_15', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1e2</gml:pos></gml:Point>'));
+SELECT 'double_16', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1E+2</gml:pos></gml:Point>'));
+SELECT 'double_17', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1e-2</gml:pos></gml:Point>'));
+SELECT 'double_18', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1E-2</gml:pos></gml:Point>'));
+
+-- Exp with decimal parts
+SELECT 'double_19', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1.23E2</gml:pos></gml:Point>'));
+SELECT 'double_20', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1.23e2</gml:pos></gml:Point>'));
+SELECT 'double_21', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 -1.23E2</gml:pos></gml:Point>'));
+
+-- ERROR: no exp digit
+SELECT 'double_22', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1E</gml:pos></gml:Point>'));
+SELECT 'double_23', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1e</gml:pos></gml:Point>'));
+
+-- ERROR: dot inside exp digits
+SELECT 'double_24', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1e2.3</gml:pos></gml:Point>'));
+SELECT 'double_25', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 1E2.3</gml:pos></gml:Point>'));
+
+-- ERROR: spaces inside
+SELECT 'double_26', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 - 1.23</gml:pos></gml:Point>'));
+SELECT 'double_27', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 -1 .23</gml:pos></gml:Point>'));
+SELECT 'double_28', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 -1. 23</gml:pos></gml:Point>'));
+SELECT 'double_29', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 -1.23 E2</gml:pos></gml:Point>'));
+SELECT 'double_30', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 -1.23E 2</gml:pos></gml:Point>'));
+
+-- ERROR: Junk
+SELECT 'double_31', ST_AsEWKT(ST_GeomFromGML('<gml:Point><gml:pos>1 $0%@#$^%#</gml:pos></gml:Point>'));
+
+
+
+
+
+--
+-- Delete inserted spatial data
+--
+DELETE FROM spatial_ref_sys WHERE srid = 4326;
--- /dev/null
+empty_geom|
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+point_1|POINT(1 2)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+point_4|SRID=4326;POINT(1 2)
+linestring_1|LINESTRING(1 2,3 4)
+ERROR: invalid GML representation
+linestring_3|SRID=4326;LINESTRING(1 2,3 4)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+linestring_6|LINESTRING(1 2,3 4)
+curve_1|LINESTRING(1 2,3 4)
+ERROR: invalid GML representation
+curve_3|SRID=4326;LINESTRING(1 2,3 4)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+curve_8|LINESTRING(1 2,3 4)
+ERROR: invalid GML representation
+curve_10|LINESTRING(1 2,3 4)
+curve_11|LINESTRING(1 2,3 4,5 6)
+curve_12|LINESTRING(1 2 3,4 5 6,7 8 9)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+curve_15|LINESTRING(1 2,4 5,7 8)
+curve_16|LINESTRING(1 2,3 4,6 7)
+polygon_1|POLYGON((1 2,3 4,5 6,1 2))
+polygon_2|SRID=4326;POLYGON((1 2,3 4,5 6,1 2))
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+polygon_9|POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))
+polygon_10|POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))
+polygon_11|POLYGON((1 2,3 4,5 6,1 2))
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+polygon_14|POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8),(13 14,15 16,17 18,13 14))
+polygon_15|POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))
+polygon_16|POLYGON((1 2,4 5,7 8,1 2),(10 11,12 13,14 15,10 11))
+polygon_17|POLYGON((1 2,3 4,5 6,1 2),(7 8,10 11,13 14,7 8))
+surface_1|POLYGON((1 2,3 4,5 6,1 2))
+surface_2|SRID=4326;POLYGON((1 2,3 4,5 6,1 2))
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+surface_10|POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))
+surface_11|POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))
+surface_12|POLYGON((1 2,3 4,5 6,1 2))
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+surface_15|POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8),(13 14,15 16,17 18,13 14))
+surface_16|POLYGON((1 2,4 5,7 8,1 2),(10 11,12 13,14 15,10 11))
+surface_17|POLYGON((1 2,3 4,5 6,1 2),(7 8,10 11,13 14,7 8))
+ERROR: invalid GML representation
+surface_19|POLYGON((1 2,3 4,5 6,1 2))
+ERROR: invalid GML representation
+mpoint_1|MULTIPOINT(1 2)
+mpoint_2|MULTIPOINT(1 2,3 4)
+mpoint_3|SRID=4326;MULTIPOINT(1 2)
+mpoint_4|MULTIPOINT EMPTY
+mpoint_5|MULTIPOINT EMPTY
+mpoint_6|MULTIPOINT(1 2,3 4)
+mline_1|MULTILINESTRING((1 2,3 4))
+mline_2|MULTILINESTRING((1 2,3 4),(5 6,7 8))
+mline_3|SRID=4326;MULTILINESTRING((1 2,3 4))
+mline_4|MULTILINESTRING EMPTY
+mline_5|MULTILINESTRING EMPTY
+mline_6|MULTILINESTRING((1 2,3 4),(5 6,7 8))
+mline_7|MULTILINESTRING((1 2,4 5),(7 8,9 10))
+mline_8|MULTILINESTRING((1 2,3 4),(5 6,8 9))
+mcurve_1|MULTILINESTRING((1 2,3 4))
+mcurve_2|MULTILINESTRING((1 2,3 4),(5 6,7 8))
+mcurve_3|SRID=4326;MULTILINESTRING((1 2,3 4))
+mcurve_4|MULTILINESTRING EMPTY
+mcurve_5|MULTILINESTRING EMPTY
+mcurve_6|MULTILINESTRING((1 2,3 4),(5 6,7 8))
+mcurve_7|MULTILINESTRING((1 2,4 5),(7 8,9 10))
+mcurve_8|MULTILINESTRING((1 2,3 4),(5 6,8 9))
+mpoly_1|MULTIPOLYGON(((1 2,3 4,5 6,1 2)))
+mpoly_2|MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))
+mpoly_3|SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))
+mpoly_4|MULTIPOLYGON EMPTY
+mpoly_5|MULTIPOLYGON EMPTY
+mpoly_6|MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))
+mpoly_7|MULTIPOLYGON(((1 2,4 5,7 8,1 2)),((10 11,12 13,14 15,10 11)))
+mpoly_8|MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,10 11,13 14,7 8)))
+msurface_1|MULTIPOLYGON(((1 2,3 4,5 6,1 2)))
+msurface_2|MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))
+msurface_3|SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))
+msurface_4|MULTIPOLYGON EMPTY
+msurface_5|MULTIPOLYGON EMPTY
+msurface_6|MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))
+msurface_7|MULTIPOLYGON(((1 2,4 5,7 8,1 2)),((10 11,12 13,14 15,10 11)))
+msurface_8|MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,10 11,13 14,7 8)))
+collection_1|GEOMETRYCOLLECTION(POINT(1 2))
+collection_2|GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(3 4,5 6))
+collection_3|GEOMETRYCOLLECTION(MULTIPOINT(1 2,3 4))
+collection_4|GEOMETRYCOLLECTION(MULTIPOINT(1 2,3 4),MULTILINESTRING((5 6,7 8),(9 10,11 12)))
+collection_5|GEOMETRYCOLLECTION(MULTIPOINT(1 2,3 4),POINT(5 6),MULTILINESTRING((7 8,9 10),(11 12,13 14)),POLYGON((15 16,17 18,19 20,15 16)))
+collection_6|GEOMETRYCOLLECTION EMPTY
+collection_7|GEOMETRYCOLLECTION EMPTY
+collection_8|GEOMETRYCOLLECTION(POINT(1 2),GEOMETRYCOLLECTION(POINT(3 4)))
+collection_9|GEOMETRYCOLLECTION(POINT(1 2),GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(3 4))))
+collection_10|SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))
+collection_11|GEOMETRYCOLLECTION(POINT(1 2),GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(3 4))))
+collection_12|GEOMETRYCOLLECTION(POINT(1 2),GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(4 5))))
+collection_13|GEOMETRYCOLLECTION(POINT(1 2),GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(3 4))))
+srs_1|SRID=4326;POINT(1 2)
+srs_2|SRID=4326;POINT(1 2)
+srs_3|SRID=4326;POINT(1 2)
+srs_4|SRID=4326;POINT(1 2)
+srs_5|SRID=4326;POINT(1 2)
+srs_6|SRID=4326;POINT(1 2)
+srs_7|SRID=4326;POINT(1 2)
+srs_8|SRID=4326;POINT(1 2)
+ERROR: unknown spatial reference system
+ERROR: unknown spatial reference system
+ERROR: unknown spatial reference system
+ERROR: unknown spatial reference system
+ERROR: unknown spatial reference system
+ERROR: unknown spatial reference system
+ERROR: unknown spatial reference system
+ERROR: unknown spatial reference system
+coordinates_1|POINT(1 2)
+ERROR: invalid GML representation
+coordinates_3|POINT(1 2 3)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+coordinates_12|LINESTRING(1 2,3 4)
+coordinates_13|LINESTRING(1 2,3 4)
+coordinates_14|LINESTRING(1 2,4 5)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+coordinates_cs_1|POINT(1 2)
+ERROR: invalid GML representation
+coordinates_cs_3|POINT(1 2)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+coordinates_cs_6|LINESTRING(1 2,3 4)
+ERROR: invalid GML representation
+coordinates_cs_8|LINESTRING(1 2,3 4)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+coordinates_cs_11|LINESTRING(1.1 2.2,3.3 4.4)
+coordinates_cs_12|LINESTRING(1.1 2.2,3.3 4.4)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+coordinates_cs_15|LINESTRING(1.1 2.2,3.3 4.4)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+coordinates_cs_19|LINESTRING(1 2,3 4)
+pos_1|POINT(1 2)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+pos_8|POINT(1 2)
+pos_9|POINT(1 2)
+pos_10|POINT(1 2)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+pos_14|POINT(1 2)
+ERROR: invalid GML representation
+pos_16|POINT(1 2 3)
+ERROR: invalid GML representation
+poslist_1|LINESTRING(1 2,3 4)
+poslist_2|LINESTRING(1 2,3 4)
+poslist_3|LINESTRING(1 2,3 4)
+poslist_4|LINESTRING(1 2,3 4)
+poslist_5|LINESTRING(1 2,3 4)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+poslist_8|LINESTRING(1 2 3,4 5 6)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+coord_1|POINT(1 2)
+coord_2|POINT(1 2 3)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+coord_10|POINT(1 2)
+coord_11|POINT(1 2)
+coord_12|POINT(1 2)
+coord_13|LINESTRING(1 2,3 4)
+coord_14|LINESTRING(1 2,4 5)
+coord_15|LINESTRING(1 2,3 4)
+coord_16|LINESTRING(1 2,3 4)
+double_1|POINT(1 1234567890)
+double_2|POINT(1 -1)
+double_3|POINT(1 1)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+double_6|POINT(1 1.2)
+double_7|POINT(1 1.23)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+double_15|POINT(1 100)
+double_16|POINT(1 100)
+double_17|POINT(1 0.01)
+double_18|POINT(1 0.01)
+double_19|POINT(1 123)
+double_20|POINT(1 123)
+double_21|POINT(1 -123)
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation
+ERROR: invalid GML representation