]> granicus.if.org Git - postgis/commitdiff
Add initial version of GeomFromGML function, and units tests cases.
authorOlivier Courtin <olivier.courtin@camptocamp.com>
Tue, 20 Oct 2009 12:54:01 +0000 (12:54 +0000)
committerOlivier Courtin <olivier.courtin@camptocamp.com>
Tue, 20 Oct 2009 12:54:01 +0000 (12:54 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@4667 b70326c6-7e19-0410-871a-916f4a2858ee

postgis/Makefile.in
postgis/lwgeom_in_gml.c [new file with mode: 0644]
postgis/postgis.sql.in.c
regress/Makefile.in
regress/in_gml.sql [new file with mode: 0644]
regress/in_gml_expected [new file with mode: 0644]

index 667640ec0bdb52025b526552a90cc283891c6ed4..715705731ccf2fde125f8b4bf039090f03f27327 100644 (file)
@@ -42,6 +42,7 @@ PG_OBJS=lwgeom_pg.o \
        lwgeom_svg.o \
        lwgeom_gml.o \
        lwgeom_kml.o \
+       lwgeom_in_gml.o \
        lwgeom_geojson.o \
        lwgeom_triggers.o \
        lwgeom_dump.o \
diff --git a/postgis/lwgeom_in_gml.c b/postgis/lwgeom_in_gml.c
new file mode 100644 (file)
index 0000000..6f9e8ca
--- /dev/null
@@ -0,0 +1,1110 @@
+/**********************************************************************
+ * 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 */
index 2070b47d32a639d03dc331912e336c86b91d0101..811779189440ae0c5ad05884201c354f0d4c81f4 100644 (file)
@@ -4532,6 +4532,23 @@ CREATE OR REPLACE FUNCTION ST_Equals(geometry,geometry)
        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
 -----------------------------------------------------------------------
index 70648d26f1a82b4dd4086b764c0af5dc6a85ea72..1ac78a3b4514b334b3cf79fbe3d3aa1c0a6ff341 100644 (file)
@@ -3,6 +3,7 @@ TMPDIR?=/tmp
 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
@@ -81,6 +82,12 @@ ifeq ($(shell expr $(POSTGIS_GEOS_VERSION) ">=" 32),1)
        TESTS += hausdorff
 endif
 
+# GeomFromGML need libxml2
+ifeq ($(shell expr $(HAVE_LIBXML2) "=" 1),1)
+       TESTS += in_gml
+endif
+
+
 
 all: test 
 
diff --git a/regress/in_gml.sql b/regress/in_gml.sql
new file mode 100644 (file)
index 0000000..40fece6
--- /dev/null
@@ -0,0 +1,783 @@
+--
+-- 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="&#x20;">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;
diff --git a/regress/in_gml_expected b/regress/in_gml_expected
new file mode 100644 (file)
index 0000000..f3b0f0f
--- /dev/null
@@ -0,0 +1,252 @@
+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