PostGIS  3.3.9dev-r@@SVN_REVISION@@
lwgeom_in_gml.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright 2009 - 2010 Oslandia
22  *
23  **********************************************************************/
24 
25 
49 #include "postgres.h"
50 #include "executor/spi.h"
51 #include "utils/builtins.h"
52 
53 #include <libxml/tree.h>
54 #include <libxml/parser.h>
55 #include <libxml/xpath.h>
56 #include <libxml/xpathInternals.h>
57 
58 #include "../postgis_config.h"
59 #include "lwgeom_pg.h"
60 #include "liblwgeom.h"
61 #include "lwgeom_transform.h"
62 
63 
64 Datum geom_from_gml(PG_FUNCTION_ARGS);
65 static LWGEOM *lwgeom_from_gml(const char *wkt, int xml_size);
66 static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid);
67 
68 typedef struct struct_gmlSrs
69 {
70  int32_t srid;
72 }
74 
75 #define XLINK_NS ((char *) "http://www.w3.org/1999/xlink")
76 #define GML_NS ((char *) "http://www.opengis.net/gml")
77 #define GML32_NS ((char *) "http://www.opengis.net/gml/3.2")
78 
79 
80 
81 static void gml_lwpgerror(char *msg, __attribute__((__unused__)) int error_code)
82 {
83  POSTGIS_DEBUGF(3, "ST_GeomFromGML ERROR %i", error_code);
84  lwpgerror("%s", msg);
85 }
86 
97 Datum geom_from_gml(PG_FUNCTION_ARGS)
98 {
99  GSERIALIZED *geom;
100  text *xml_input;
101  LWGEOM *lwgeom;
102  char *xml;
103  int root_srid=SRID_UNKNOWN;
104  int xml_size;
105 
106  /* Get the GML stream */
107  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
108  xml_input = PG_GETARG_TEXT_P(0);
109  xml = text_to_cstring(xml_input);
110  xml_size = VARSIZE_ANY_EXHDR(xml_input);
111 
112  /* Zero for undefined */
113  root_srid = PG_GETARG_INT32(1);
114 
115 #if POSTGIS_PROJ_VERSION < 61
116  /* Internally lwgeom_from_gml calls gml_reproject_pa which, for PROJ before 6, called GetProj4String.
117  * That function requires access to spatial_ref_sys, so in order to have it ready we need to ensure
118  * the internal cache is initialized
119  */
120  postgis_initialize_cache();
121 #endif
122  lwgeom = lwgeom_from_gml(xml, xml_size);
123  if ( root_srid != SRID_UNKNOWN )
124  lwgeom->srid = root_srid;
125 
126  geom = geometry_serialize(lwgeom);
127  lwgeom_free(lwgeom);
128 
129  PG_RETURN_POINTER(geom);
130 }
131 
132 
133 static inline bool
134 is_gml_element(xmlNodePtr xn, const char *gml_name)
135 {
136  char *colon_pos;
137  char *node_name;
138 
139  /* Not an element node, can't do anything */
140  if (!xn || xn->type != XML_ELEMENT_NODE)
141  return false;
142 
143  /* If there's a colon in the element name, */
144  /* move past it before checking for equality with */
145  /* the element name we are looking for */
146  node_name = (char*)xn->name;
147  colon_pos = strchr(node_name, ':');
148  if (colon_pos)
149  node_name = colon_pos + 1;
150 
151  return strcmp(node_name, gml_name) == 0;
152 }
153 
154 
159 static bool is_gml_namespace(xmlNodePtr xnode, bool is_strict)
160 {
161  xmlNsPtr *ns, *p;
162 
163  ns = xmlGetNsList(xnode->doc, xnode);
164  /*
165  * If no namespace is available we could return true anyway
166  * (because we work only on GML fragment, we don't want to
167  * 'oblige' to add namespace on the geometry root node)
168  */
169  if (ns == NULL) { return !is_strict; }
170 
171  /*
172  * Handle namespaces:
173  * - http://www.opengis.net/gml (GML 3.1.1 and priors)
174  * - http://www.opengis.net/gml/3.2 (GML 3.2.1)
175  */
176  for (p=ns ; *p ; p++)
177  {
178  if ((*p)->href == NULL || (*p)->prefix == NULL ||
179  xnode->ns == NULL || xnode->ns->prefix == NULL) continue;
180 
181  if (!xmlStrcmp(xnode->ns->prefix, (*p)->prefix))
182  {
183  if ( !strcmp((char *) (*p)->href, GML_NS)
184  || !strcmp((char *) (*p)->href, GML32_NS))
185  {
186  xmlFree(ns);
187  return true;
188  } else {
189  xmlFree(ns);
190  return false;
191  }
192  }
193  }
194 
195  xmlFree(ns);
196  return !is_strict; /* Same reason here to not return false */
197 }
198 
199 
204 static xmlChar *gmlGetProp(xmlNodePtr xnode, const char *charProp)
205 {
206  xmlChar *value;
207  xmlChar *prop = (xmlChar*)charProp;
208 
209  if (!is_gml_namespace(xnode, true))
210  return xmlGetProp(xnode, prop);
211  /*
212  * Handle namespaces:
213  * - http://www.opengis.net/gml (GML 3.1.1 and priors)
214  * - http://www.opengis.net/gml/3.2 (GML 3.2.1)
215  */
216  value = xmlGetNsProp(xnode, prop, (xmlChar *) GML_NS);
217  if (value == NULL) value = xmlGetNsProp(xnode, prop, (xmlChar *) GML32_NS);
218 
219  /* In last case try without explicit namespace */
220  if (value == NULL) value = xmlGetNoNsProp(xnode, prop);
221 
222  return value;
223 }
224 
225 
230 static bool is_xlink(xmlNodePtr node)
231 {
232  xmlChar *prop;
233 
234  prop = xmlGetNsProp(node, (xmlChar *)"type", (xmlChar *) XLINK_NS);
235  if (prop == NULL) return false;
236  if (strcmp((char *) prop, "simple"))
237  {
238  xmlFree(prop);
239  return false;
240  }
241 
242  prop = xmlGetNsProp(node, (xmlChar *)"href", (xmlChar *) XLINK_NS);
243  if (prop == NULL) return false;
244  if (prop[0] != '#')
245  {
246  xmlFree(prop);
247  return false;
248  }
249  xmlFree(prop);
250 
251  return true;
252 }
253 
254 
258 static xmlNodePtr get_xlink_node(xmlNodePtr xnode)
259 {
260  char *id;
261  xmlNsPtr *ns, *n;
262  xmlXPathContext *ctx;
263  xmlXPathObject *xpath;
264  xmlNodePtr node, ret_node;
265  xmlChar *href, *p, *node_id;
266 
267  href = xmlGetNsProp(xnode, (xmlChar *)"href", (xmlChar *) XLINK_NS);
268  p = href;
269  p++; /* ignore '#' first char */
270 
271  if (xnode->ns)
272  {
273  id = lwalloc((xmlStrlen(xnode->ns->prefix) * 2 + xmlStrlen(xnode->name) +
274  xmlStrlen(href) + sizeof("//:[@:id='']") + 1));
275  /* XPath pattern look like: //gml:point[@gml:id='p1'] */
276  sprintf(id, "//%s:%s[@%s:id='%s']",
277  (char *) xnode->ns->prefix,
278  (char *) xnode->name,
279  (char *) xnode->ns->prefix,
280  (char *) p);
281  }
282  else
283  {
284  id = lwalloc((xmlStrlen(xnode->name) +
285  xmlStrlen(href) + sizeof("//:[@:id='']") + 1));
286  /* XPath pattern look like: //gml:point[@gml:id='p1'] */
287  sprintf(id, "//%s[@id='%s']",
288  (char *) xnode->name,
289  (char *) p);
290  }
291 
292  ctx = xmlXPathNewContext(xnode->doc);
293  if (ctx == NULL)
294  {
295  xmlFree(href);
296  lwfree(id);
297  return NULL;
298  }
299 
300  /* Handle namespaces */
301  ns = xmlGetNsList(xnode->doc, xnode);
302  for (n=ns ; *n; n++) xmlXPathRegisterNs(ctx, (*n)->prefix, (*n)->href);
303  xmlFree(ns);
304 
305  /* Execute XPath expression */
306  xpath = xmlXPathEvalExpression((xmlChar *) id, ctx);
307  lwfree(id);
308  if (xpath == NULL || xpath->nodesetval == NULL || xpath->nodesetval->nodeNr != 1)
309  {
310  xmlFree(href);
311  xmlXPathFreeObject(xpath);
312  xmlXPathFreeContext(ctx);
313  return NULL;
314  }
315  ret_node = xpath->nodesetval->nodeTab[0];
316  xmlXPathFreeObject(xpath);
317  xmlXPathFreeContext(ctx);
318 
319  /* Protection against circular calls */
320  for (node = xnode ; node != NULL ; node = node->parent)
321  {
322  if (node->type != XML_ELEMENT_NODE) continue;
323  node_id = gmlGetProp(node, "id");
324  if (node_id != NULL)
325  {
326  if (!xmlStrcmp(node_id, p))
327  gml_lwpgerror("invalid GML representation", 2);
328  xmlFree(node_id);
329  }
330  }
331 
332  xmlFree(href);
333  return ret_node;
334 }
335 
336 
337 
342 #if POSTGIS_PROJ_VERSION < 61
343 
344 static POINTARRAY *
345 gml_reproject_pa(POINTARRAY *pa, int32_t srid_in, int32_t srid_out)
346 {
347  LWPROJ pj;
348  char *text_in, *text_out;
349 
350  if (srid_in == SRID_UNKNOWN) return pa; /* nothing to do */
351  if (srid_out == SRID_UNKNOWN) gml_lwpgerror("invalid GML representation", 3);
352 
353  text_in = GetProj4String(srid_in);
354  text_out = GetProj4String(srid_out);
355 
356  pj.pj_from = projpj_from_string(text_in);
357  pj.pj_to = projpj_from_string(text_out);
358 
359  lwfree(text_in);
360  lwfree(text_out);
361 
362  if ( ptarray_transform(pa, &pj) == LW_FAILURE )
363  {
364  elog(ERROR, "gml_reproject_pa: reprojection failed");
365  }
366 
367  pj_free(pj.pj_from);
368  pj_free(pj.pj_to);
369 
370  return pa;
371 }
372 
373 #else /* POSTGIS_PROJ_VERSION >= 61 */
374 
375 static POINTARRAY *
376 gml_reproject_pa(POINTARRAY *pa, int32_t epsg_in, int32_t epsg_out)
377 {
378  LWPROJ *lwp;
379  char text_in[16];
380  char text_out[16];
381 
382  if (epsg_in == SRID_UNKNOWN)
383  return pa; /* nothing to do */
384 
385  if (epsg_out == SRID_UNKNOWN)
386  {
387  gml_lwpgerror("invalid GML representation", 3);
388  return NULL;
389  }
390 
391  snprintf(text_in, 16, "EPSG:%d", epsg_in);
392  snprintf(text_out, 16, "EPSG:%d", epsg_out);
393 
394 
395  lwp = lwproj_from_str(text_in, text_out);
396  if (!lwp)
397  {
398  gml_lwpgerror("Could not create LWPROJ*", 57);
399  return NULL;
400  }
401 
402  if (ptarray_transform(pa, lwp) == LW_FAILURE)
403  {
404  elog(ERROR, "gml_reproject_pa: reprojection failed");
405  return NULL;
406  }
407  proj_destroy(lwp->pj);
408  pfree(lwp);
409 
410  return pa;
411 }
412 
413 #endif /* POSTGIS_PROJ_VERSION */
414 
415 
421 static int
423 {
424  char *srtext;
425  char query[256];
426  int is_axis_order_gis_friendly, err;
427 
428  if (SPI_OK_CONNECT != SPI_connect ())
429  lwpgerror("gml_is_srs_axis_order_gis_friendly: could not connect to SPI manager");
430 
431  sprintf(query, "SELECT srtext \
432  FROM spatial_ref_sys WHERE srid='%d'", srid);
433 
434  err = SPI_exec(query, 1);
435  if (err < 0) lwpgerror("gml_is_srs_axis_order_gis_friendly: error executing query %d", err);
436 
437  /* No entry in spatial_ref_sys */
438  if (SPI_processed <= 0)
439  {
440  SPI_finish();
441  return -1;
442  }
443 
444  srtext = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
445 
446  is_axis_order_gis_friendly = 1;
447  if (srtext && srtext[0] != '\0')
448  {
449  char* ptr;
450  char* srtext_horizontal = (char*) malloc(strlen(srtext) + 1);
451  strcpy(srtext_horizontal, srtext);
452 
453  /* Remove the VERT_CS part if we are in a COMPD_CS */
454  ptr = strstr(srtext_horizontal, ",VERT_CS[");
455  if (ptr)
456  *ptr = '\0';
457 
458  if( strstr(srtext_horizontal, "AXIS[") == NULL &&
459  strstr(srtext_horizontal, "GEOCCS[") == NULL )
460  {
461  /* If there is no axis definition, then due to how GDAL < 3
462  * generated the WKT, this means that the axis order is not
463  * GIS friendly */
464  is_axis_order_gis_friendly = 0;
465  }
466  else if( strstr(srtext_horizontal,
467  "AXIS[\"Latitude\",NORTH],AXIS[\"Longitude\",EAST]") != NULL )
468  {
469  is_axis_order_gis_friendly = 0;
470  }
471  else if( strstr(srtext_horizontal,
472  "AXIS[\"Northing\",NORTH],AXIS[\"Easting\",EAST]") != NULL )
473  {
474  is_axis_order_gis_friendly = 0;
475  }
476  else if( strstr(srtext_horizontal,
477  "AXIS[\"geodetic latitude (Lat)\",north,ORDER[1]") != NULL )
478  {
479  is_axis_order_gis_friendly = 0;
480  }
481 
482  free(srtext_horizontal);
483  }
484  SPI_finish();
485 
486  return is_axis_order_gis_friendly;
487 }
488 
489 
493 static void parse_gml_srs(xmlNodePtr xnode, gmlSrs *srs)
494 {
495  char *p;
496  int is_axis_order_gis_friendly;
497  xmlNodePtr node;
498  xmlChar *srsname;
499  bool honours_authority_axis_order = false;
500  char sep = ':';
501 
502  node = xnode;
503  srsname = gmlGetProp(node, "srsName");
504  /*printf("srsname %s\n",srsname);*/
505  if (!srsname)
506  {
507  if (node->parent == NULL)
508  {
509  srs->srid = SRID_UNKNOWN;
510  srs->reverse_axis = false;
511  return;
512  }
513  parse_gml_srs(node->parent, srs);
514  }
515  else
516  {
517  /* Severals srsName formats are available...
518  * cf WFS 1.1.0 -> 9.2 (p36)
519  * cf ISO 19142:2009 -> 7.9.2.4.4 (p34)
520  * cf RFC 5165 <http://tools.ietf.org/html/rfc5165>
521  * cf CITE WFS-1.1 (GetFeature-tc17.2)
522  */
523 
524  /* SRS pattern like: EPSG:4326
525  urn:EPSG:geographicCRS:4326
526  urn:ogc:def:crs:EPSG:4326
527  urn:ogc:def:crs:EPSG::4326
528  urn:ogc:def:crs:EPSG:6.6:4326
529  urn:x-ogc:def:crs:EPSG:6.6:4326
530  http://www.opengis.net/gml/srs/epsg.xml#4326
531  http://www.epsg.org/6.11.2/4326
532  */
533 
534  if (!strncmp((char *) srsname, "EPSG:", 5))
535  {
536  sep = ':';
537  honours_authority_axis_order = false;
538  }
539  else if (!strncmp((char *) srsname, "urn:ogc:def:crs:EPSG:", 21)
540  || !strncmp((char *) srsname, "urn:x-ogc:def:crs:EPSG:", 23)
541  || !strncmp((char *) srsname, "urn:EPSG:geographicCRS:", 23))
542  {
543  sep = ':';
544  honours_authority_axis_order = true;
545  }
546  else if (!strncmp((char *) srsname,
547  "http://www.opengis.net/gml/srs/epsg.xml#", 40))
548  {
549  sep = '#';
550  honours_authority_axis_order = false;
551  }
552  else gml_lwpgerror("unknown spatial reference system", 4);
553 
554  /* retrieve the last ':' or '#' char */
555  for (p = (char *) srsname ; *p ; p++);
556  for (--p ; *p != sep ; p--)
557  if (!isdigit(*p)) gml_lwpgerror("unknown spatial reference system", 5);
558 
559  srs->srid = atoi(++p);
560 
561  /* Check into spatial_ref_sys that this SRID really exist */
562  is_axis_order_gis_friendly = gml_is_srs_axis_order_gis_friendly(srs->srid);
563  if (srs->srid == SRID_UNKNOWN || is_axis_order_gis_friendly == -1)
564  gml_lwpgerror("unknown spatial reference system", 6);
565 
566  /* Reverse axis order if the srsName is meant to honour the axis
567  order defined by the authority and if that axis order is not
568  the GIS friendly one. */
569  srs->reverse_axis = !is_axis_order_gis_friendly && honours_authority_axis_order;
570 
571  xmlFree(srsname);
572  return;
573  }
574 }
575 
576 
580 static double parse_gml_double(char *d, bool space_before, bool space_after)
581 {
582  char *p;
583  int st;
584  enum states
585  {
586  INIT = 0,
587  NEED_DIG = 1,
588  DIG = 2,
589  NEED_DIG_DEC = 3,
590  DIG_DEC = 4,
591  EXP = 5,
592  NEED_DIG_EXP = 6,
593  DIG_EXP = 7,
594  END = 8
595  };
596 
597  /*
598  * Double pattern
599  * [-|\+]?[0-9]+(\.)?([0-9]+)?([Ee](\+|-)?[0-9]+)?
600  * We could also meet spaces before and/or after
601  * this pattern upon parameters
602  */
603 
604  if (space_before) while (isspace(*d)) d++;
605  for (st = INIT, p = d ; *p ; p++)
606  {
607 
608  if (isdigit(*p))
609  {
610  if (st == INIT || st == NEED_DIG) st = DIG;
611  else if (st == NEED_DIG_DEC) st = DIG_DEC;
612  else if (st == NEED_DIG_EXP || st == EXP) st = DIG_EXP;
613  else if (st == DIG || st == DIG_DEC || st == DIG_EXP);
614  else gml_lwpgerror("invalid GML representation", 7);
615  }
616  else if (*p == '.')
617  {
618  if (st == DIG) st = NEED_DIG_DEC;
619  else gml_lwpgerror("invalid GML representation", 8);
620  }
621  else if (*p == '-' || *p == '+')
622  {
623  if (st == INIT) st = NEED_DIG;
624  else if (st == EXP) st = NEED_DIG_EXP;
625  else gml_lwpgerror("invalid GML representation", 9);
626  }
627  else if (*p == 'e' || *p == 'E')
628  {
629  if (st == DIG || st == DIG_DEC) st = EXP;
630  else gml_lwpgerror("invalid GML representation", 10);
631  }
632  else if (isspace(*p))
633  {
634  if (!space_after) gml_lwpgerror("invalid GML representation", 11);
635  if (st == DIG || st == DIG_DEC || st == DIG_EXP)st = END;
636  else if (st == NEED_DIG_DEC) st = END;
637  else if (st == END);
638  else gml_lwpgerror("invalid GML representation", 12);
639  }
640  else gml_lwpgerror("invalid GML representation", 13);
641  }
642 
643  if (st != DIG && st != NEED_DIG_DEC && st != DIG_DEC && st != DIG_EXP && st != END)
644  gml_lwpgerror("invalid GML representation", 14);
645 
646  return atof(d);
647 }
648 
649 
653 static POINTARRAY* parse_gml_coordinates(xmlNodePtr xnode, bool *hasz)
654 {
655  xmlChar *gml_coord, *gml_ts, *gml_cs, *gml_dec;
656  char cs, ts, dec;
657  POINTARRAY *dpa;
658  int gml_dims;
659  char *p, *q;
660  bool digit;
661  POINT4D pt = {0};
662 
663  /* We begin to retrieve coordinates string */
664  gml_coord = xmlNodeGetContent(xnode);
665  p = (char *) gml_coord;
666 
667  /* Default GML coordinates pattern: x1,y1 x2,y2
668  * x1,y1,z1 x2,y2,z2
669  *
670  * Cf GML 2.1.2 -> 4.3.1 (p18)
671  */
672 
673  /* Retrieve separator between coordinates tuples */
674  gml_ts = gmlGetProp(xnode, "ts");
675  if (gml_ts == NULL) ts = ' ';
676  else
677  {
678  if (xmlStrlen(gml_ts) > 1 || isdigit(gml_ts[0]))
679  gml_lwpgerror("invalid GML representation", 15);
680  ts = gml_ts[0];
681  xmlFree(gml_ts);
682  }
683 
684  /* Retrieve separator between each coordinate */
685  gml_cs = gmlGetProp(xnode, "cs");
686  if (gml_cs == NULL) cs = ',';
687  else
688  {
689  if (xmlStrlen(gml_cs) > 1 || isdigit(gml_cs[0]))
690  gml_lwpgerror("invalid GML representation", 16);
691  cs = gml_cs[0];
692  xmlFree(gml_cs);
693  }
694 
695  /* Retrieve decimal separator */
696  gml_dec = gmlGetProp(xnode, "decimal");
697  if (gml_dec == NULL) dec = '.';
698  else
699  {
700  if (xmlStrlen(gml_dec) > 1 || isdigit(gml_dec[0]))
701  gml_lwpgerror("invalid GML representation", 17);
702  dec = gml_dec[0];
703  xmlFree(gml_dec);
704  }
705 
706  if (cs == ts || cs == dec || ts == dec)
707  gml_lwpgerror("invalid GML representation", 18);
708 
709  /* HasZ, !HasM, 1 Point */
710  dpa = ptarray_construct_empty(1, 0, 1);
711 
712  while (isspace(*p)) p++; /* Eat extra whitespaces if any */
713  for (q = p, gml_dims=0, digit = false ; *p ; p++)
714  {
715 
716  if (isdigit(*p)) digit = true; /* One state parser */
717 
718  /* Coordinate Separator */
719  if (*p == cs)
720  {
721  *p = '\0';
722  gml_dims++;
723 
724  if (*(p+1) == '\0') gml_lwpgerror("invalid GML representation", 19);
725 
726  if (gml_dims == 1) pt.x = parse_gml_double(q, false, true);
727  else if (gml_dims == 2) pt.y = parse_gml_double(q, false, true);
728 
729  q = p+1;
730 
731  /* Tuple Separator (or end string) */
732  }
733  else if (digit && (*p == ts || *(p+1) == '\0'))
734  {
735  if (*p == ts) *p = '\0';
736  gml_dims++;
737 
738  if (gml_dims < 2 || gml_dims > 3)
739  gml_lwpgerror("invalid GML representation", 20);
740 
741  if (gml_dims == 3)
742  pt.z = parse_gml_double(q, false, true);
743  else
744  {
745  pt.y = parse_gml_double(q, false, true);
746  *hasz = false;
747  }
748 
749  ptarray_append_point(dpa, &pt, LW_TRUE);
750  digit = false;
751 
752  q = p+1;
753  gml_dims = 0;
754 
755  /* Need to put standard decimal separator to atof handle */
756  }
757  else if (*p == dec && dec != '.') *p = '.';
758  }
759 
760  xmlFree(gml_coord);
761 
762  return dpa; /* ptarray_clone_deep(dpa); */
763 }
764 
765 
769 static POINTARRAY* parse_gml_coord(xmlNodePtr xnode, bool *hasz)
770 {
771  xmlNodePtr xyz;
772  POINTARRAY *dpa;
773  bool x,y,z;
774  xmlChar *c;
775  POINT4D p = {0};
776 
777  /* HasZ?, !HasM, 1 Point */
778  dpa = ptarray_construct_empty(1, 0, 1);
779 
780  x = y = z = false;
781  for (xyz = xnode->children ; xyz != NULL ; xyz = xyz->next)
782  {
783  if (xyz->type != XML_ELEMENT_NODE) continue;
784  if (!is_gml_namespace(xyz, false)) continue;
785 
786  if (is_gml_element(xyz, "X"))
787  {
788  if (x) gml_lwpgerror("invalid GML representation", 21);
789  c = xmlNodeGetContent(xyz);
790  p.x = parse_gml_double((char *) c, true, true);
791  x = true;
792  xmlFree(c);
793  }
794  else if (is_gml_element(xyz, "Y"))
795  {
796  if (y) gml_lwpgerror("invalid GML representation", 22);
797  c = xmlNodeGetContent(xyz);
798  p.y = parse_gml_double((char *) c, true, true);
799  y = true;
800  xmlFree(c);
801  }
802  else if (is_gml_element(xyz, "Z"))
803  {
804  if (z) gml_lwpgerror("invalid GML representation", 23);
805  c = xmlNodeGetContent(xyz);
806  p.z = parse_gml_double((char *) c, true, true);
807  z = true;
808  xmlFree(c);
809  }
810  }
811  /* Check dimension consistancy */
812  if (!x || !y) gml_lwpgerror("invalid GML representation", 24);
813  if (!z) *hasz = false;
814 
815  ptarray_append_point(dpa, &p, LW_FALSE);
816 
817  return dpa; /* ptarray_clone_deep(dpa); */
818 }
819 
820 
824 static POINTARRAY* parse_gml_pos(xmlNodePtr xnode, bool *hasz)
825 {
826  xmlChar *dimension, *gmlpos;
827  int dim, gml_dim;
828  POINTARRAY *dpa;
829  char *pos, *p;
830  bool digit;
831  POINT4D pt = {0, 0, 0, 0};
832 
833  /* HasZ, !HasM, 1 Point */
834  dpa = ptarray_construct_empty(1, 0, 1);
835 
836  dimension = gmlGetProp(xnode, "srsDimension");
837  if (dimension == NULL) /* in GML 3.0.0 it was dimension */
838  dimension = gmlGetProp(xnode, "dimension");
839  if (dimension == NULL) dim = 2; /* We assume that we are in 2D */
840  else
841  {
842  dim = atoi((char *) dimension);
843  xmlFree(dimension);
844  if (dim < 2 || dim > 3)
845  gml_lwpgerror("invalid GML representation", 25);
846  }
847  if (dim == 2) *hasz = false;
848 
849  /* We retrieve gml:pos string */
850  gmlpos = xmlNodeGetContent(xnode);
851  pos = (char *) gmlpos;
852  while (isspace(*pos)) pos++; /* Eat extra whitespaces if any */
853 
854  /* gml:pos pattern: x1 y1
855  * x1 y1 z1
856  */
857  for (p=pos, gml_dim=0, digit=false ; *pos ; pos++)
858  {
859  if (isdigit(*pos)) digit = true;
860  if (digit && (*pos == ' ' || *(pos+1) == '\0'))
861  {
862  if (*pos == ' ') *pos = '\0';
863  gml_dim++;
864  if (gml_dim == 1)
865  pt.x = parse_gml_double(p, true, true);
866  else if (gml_dim == 2)
867  pt.y = parse_gml_double(p, true, true);
868  else if (gml_dim == 3)
869  pt.z = parse_gml_double(p, true, true);
870 
871  p = pos+1;
872  digit = false;
873  }
874  }
875  xmlFree(gmlpos);
876 
877  /* Test again coherent dimensions on each coord */
878  if (gml_dim == 2) *hasz = false;
879  if (gml_dim < 2 || gml_dim > 3 || gml_dim != dim)
880  gml_lwpgerror("invalid GML representation", 26);
881 
882  ptarray_append_point(dpa, &pt, LW_FALSE);
883 
884  return dpa; /* ptarray_clone_deep(dpa); */
885 }
886 
887 
891 static POINTARRAY* parse_gml_poslist(xmlNodePtr xnode, bool *hasz)
892 {
893  xmlChar *dimension, *gmlposlist;
894  char *poslist, *p;
895  int dim, gml_dim;
896  POINTARRAY *dpa;
897  POINT4D pt = {0, 0, 0, 0};
898  bool digit;
899 
900  /* Retrieve gml:srsDimension attribute if any */
901  dimension = gmlGetProp(xnode, "srsDimension");
902  if (dimension == NULL) /* in GML 3.0.0 it was dimension */
903  dimension = gmlGetProp(xnode, "dimension");
904  if (dimension == NULL) dim = 2; /* We assume that we are in common 2D */
905  else
906  {
907  dim = atoi((char *) dimension);
908  xmlFree(dimension);
909  if (dim < 2 || dim > 3) gml_lwpgerror("invalid GML representation", 27);
910  }
911  if (dim == 2) *hasz = false;
912 
913  /* Retrieve gml:posList string */
914  gmlposlist = xmlNodeGetContent(xnode);
915  poslist = (char *) gmlposlist;
916 
917  /* HasZ?, !HasM, 1 point */
918  dpa = ptarray_construct_empty(1, 0, 1);
919 
920  /* gml:posList pattern: x1 y1 x2 y2
921  * x1 y1 z1 x2 y2 z2
922  */
923  while (isspace(*poslist)) poslist++; /* Eat extra whitespaces if any */
924  for (p=poslist, gml_dim=0, digit=false ; *poslist ; poslist++)
925  {
926  if (isdigit(*poslist)) digit = true;
927  if (digit && (*poslist == ' ' || *(poslist+1) == '\0'))
928  {
929  if (*poslist == ' ') *poslist = '\0';
930 
931  gml_dim++;
932  if (gml_dim == 1) pt.x = parse_gml_double(p, true, true);
933  else if (gml_dim == 2) pt.y = parse_gml_double(p, true, true);
934  else if (gml_dim == 3) pt.z = parse_gml_double(p, true, true);
935 
936  if (gml_dim == dim)
937  {
938  /* Add to ptarray, allowing dupes */
939  ptarray_append_point(dpa, &pt, LW_TRUE);
940  pt.x = pt.y = pt.z = pt.m = 0.0;
941  gml_dim = 0;
942  }
943  else if (*(poslist+1) == '\0')
944  gml_lwpgerror("invalid GML representation", 28);
945 
946  p = poslist+1;
947  digit = false;
948  }
949  }
950 
951  xmlFree(gmlposlist);
952 
953  return dpa; /* ptarray_clone_deep(dpa); */
954 }
955 
956 
969 static POINTARRAY* parse_gml_data(xmlNodePtr xnode, bool *hasz, int *root_srid)
970 {
971  POINTARRAY *pa = 0, *tmp_pa = 0;
972  xmlNodePtr xa, xb;
973  gmlSrs srs;
974  bool found;
975 
976  pa = NULL;
977 
978  for (xa = xnode ; xa != NULL ; xa = xa->next)
979  {
980  if (xa->type != XML_ELEMENT_NODE) continue;
981  if (!is_gml_namespace(xa, false)) continue;
982  if (xa->name == NULL) continue;
983 
984  if (is_gml_element(xa, "pos"))
985  {
986  tmp_pa = parse_gml_pos(xa, hasz);
987  if (pa == NULL) pa = tmp_pa;
988  else pa = ptarray_merge(pa, tmp_pa);
989 
990  }
991  else if (is_gml_element(xa, "posList"))
992  {
993  tmp_pa = parse_gml_poslist(xa, hasz);
994  if (pa == NULL) pa = tmp_pa;
995  else pa = ptarray_merge(pa, tmp_pa);
996 
997  }
998  else if (is_gml_element(xa, "coordinates"))
999  {
1000  tmp_pa = parse_gml_coordinates(xa, hasz);
1001  if (pa == NULL) pa = tmp_pa;
1002  else pa = ptarray_merge(pa, tmp_pa);
1003 
1004  }
1005  else if (is_gml_element(xa, "coord"))
1006  {
1007  tmp_pa = parse_gml_coord(xa, hasz);
1008  if (pa == NULL) pa = tmp_pa;
1009  else pa = ptarray_merge(pa, tmp_pa);
1010 
1011  }
1012  else if (is_gml_element(xa, "pointRep") ||
1013  is_gml_element(xa, "pointProperty"))
1014  {
1015  found = false;
1016  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1017  {
1018  if (xb->type != XML_ELEMENT_NODE) continue;
1019  if (!is_gml_namespace(xb, false)) continue;
1020  if (is_gml_element(xb, "Point"))
1021  {
1022  found = true;
1023  break;
1024  }
1025  }
1026  if (!found || xb == NULL)
1027  gml_lwpgerror("invalid GML representation", 29);
1028 
1029  if (is_xlink(xb)) xb = get_xlink_node(xb);
1030  if (xb == NULL || xb->children == NULL)
1031  gml_lwpgerror("invalid GML representation", 30);
1032 
1033  tmp_pa = parse_gml_data(xb->children, hasz, root_srid);
1034  if (tmp_pa->npoints != 1)
1035  gml_lwpgerror("invalid GML representation", 31);
1036 
1037  parse_gml_srs(xb, &srs);
1038  if (srs.reverse_axis) tmp_pa = ptarray_flip_coordinates(tmp_pa);
1039  if (*root_srid == SRID_UNKNOWN) *root_srid = srs.srid;
1040  else if (srs.srid != *root_srid)
1041  gml_reproject_pa(tmp_pa, srs.srid, *root_srid);
1042  if (pa == NULL) pa = tmp_pa;
1043  else pa = ptarray_merge(pa, tmp_pa);
1044  }
1045  }
1046 
1047  if (pa == NULL) gml_lwpgerror("invalid GML representation", 32);
1048 
1049  return pa;
1050 }
1051 
1052 
1056 static LWGEOM* parse_gml_point(xmlNodePtr xnode, bool *hasz, int *root_srid)
1057 {
1058  gmlSrs srs;
1059  LWGEOM *geom;
1060  POINTARRAY *pa;
1061 
1062  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1063  if (xnode == NULL)
1064  gml_lwpgerror("invalid GML representation", 30);
1065 
1066  if (xnode->children == NULL)
1067  return lwpoint_as_lwgeom(lwpoint_construct_empty(*root_srid, 0, 0));
1068 
1069  pa = parse_gml_data(xnode->children, hasz, root_srid);
1070  if (pa->npoints != 1) gml_lwpgerror("invalid GML representation", 34);
1071 
1072  parse_gml_srs(xnode, &srs);
1073  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1074  if (!*root_srid)
1075  {
1076  *root_srid = srs.srid;
1077  geom = (LWGEOM *) lwpoint_construct(*root_srid, NULL, pa);
1078  }
1079  else
1080  {
1081  if (srs.srid != *root_srid)
1082  gml_reproject_pa(pa, srs.srid, *root_srid);
1083  geom = (LWGEOM *) lwpoint_construct(SRID_UNKNOWN, NULL, pa);
1084  }
1085 
1086  return geom;
1087 }
1088 
1089 
1093 static LWGEOM* parse_gml_line(xmlNodePtr xnode, bool *hasz, int *root_srid)
1094 {
1095  gmlSrs srs;
1096  LWGEOM *geom;
1097  POINTARRAY *pa;
1098 
1099  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1100  if (xnode == NULL)
1101  gml_lwpgerror("invalid GML representation", 30);
1102 
1103  if (xnode->children == NULL)
1104  return lwline_as_lwgeom(lwline_construct_empty(*root_srid, 0, 0));
1105 
1106  pa = parse_gml_data(xnode->children, hasz, root_srid);
1107  if (pa->npoints < 2) gml_lwpgerror("invalid GML representation", 36);
1108 
1109  parse_gml_srs(xnode, &srs);
1110  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1111  if (!*root_srid)
1112  {
1113  *root_srid = srs.srid;
1114  geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
1115  }
1116  else
1117  {
1118  if (srs.srid != *root_srid)
1119  gml_reproject_pa(pa, srs.srid, *root_srid);
1120  geom = (LWGEOM *) lwline_construct(SRID_UNKNOWN, NULL, pa);
1121  }
1122 
1123  return geom;
1124 }
1125 
1126 
1130 static LWGEOM* parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
1131 {
1132  xmlNodePtr xa;
1133  size_t lss;
1134  bool found=false;
1135  gmlSrs srs;
1136  LWGEOM *geom=NULL;
1137  POINTARRAY *pa=NULL;
1138  POINTARRAY **ppa=NULL;
1139  uint32 npoints=0;
1140  xmlChar *interpolation=NULL;
1141 
1142  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1143  if (xnode == NULL)
1144  gml_lwpgerror("invalid GML representation", 30);
1145 
1146  /* Looking for gml:segments */
1147  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1148  {
1149  if (xa->type != XML_ELEMENT_NODE) continue;
1150  if (!is_gml_namespace(xa, false)) continue;
1151  if (is_gml_element(xa, "segments"))
1152  {
1153  found = true;
1154  break;
1155  }
1156  }
1157  if (!found) gml_lwpgerror("invalid GML representation", 37);
1158 
1159  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1160 
1161  /* Processing each gml:LineStringSegment */
1162  for (xa = xa->children, lss=0; xa != NULL ; xa = xa->next)
1163  {
1164  if (xa->type != XML_ELEMENT_NODE) continue;
1165  if (!is_gml_namespace(xa, false)) continue;
1166 
1167  if (!is_gml_element(xa, "LineStringSegment")) continue;
1168 
1169  /* GML SF is restricted to linear interpolation */
1170  interpolation = gmlGetProp(xa, "interpolation");
1171  if (interpolation != NULL)
1172  {
1173  if (strcmp((char *) interpolation, "linear"))
1174  gml_lwpgerror("invalid GML representation", 38);
1175  xmlFree(interpolation);
1176  }
1177 
1178  if (lss > 0) ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1179  sizeof(POINTARRAY*) * (lss + 1));
1180 
1181  ppa[lss] = parse_gml_data(xa->children, hasz, root_srid);
1182  npoints += ppa[lss]->npoints;
1183  if (ppa[lss]->npoints < 2)
1184  gml_lwpgerror("invalid GML representation", 39);
1185  lss++;
1186  }
1187  if (lss == 0) gml_lwpgerror("invalid GML representation", 40);
1188 
1189  /* Most common case, a single segment */
1190  if (lss == 1) pa = ppa[0];
1191 
1192  if (lss > 1)
1193  {
1194  /*
1195  * "The curve segments are connected to one another, with the end point
1196  * of each segment except the last being the start point of the next
1197  * segment" from ISO 19107:2003 -> 6.3.16.1 (p43)
1198  *
1199  * So we must aggregate all the segments into a single one and avoid
1200  * to copy the redundant points
1201  */
1202  size_t cp_point_size = sizeof(POINT3D); /* All internals are done with 3D */
1203  size_t final_point_size = *hasz ? sizeof(POINT3D) : sizeof(POINT2D);
1204  pa = ptarray_construct(1, 0, npoints - lss + 1);
1205 
1206  /* Copy the first linestring fully */
1207  memcpy(getPoint_internal(pa, 0), getPoint_internal(ppa[0], 0), cp_point_size * (ppa[0]->npoints));
1208  npoints = ppa[0]->npoints;
1209  lwfree(ppa[0]);
1210 
1211  /* For the rest of linestrings, ensure the first point matches the
1212  * last point of the previous one, and copy all points except the
1213  * first one (since it'd be repeated)
1214  */
1215  for (size_t i = 1; i < lss; i++)
1216  {
1217  if (memcmp(getPoint_internal(pa, npoints - 1), getPoint_internal(ppa[i], 0), final_point_size))
1218  gml_lwpgerror("invalid GML representation", 41);
1219 
1220  memcpy(getPoint_internal(pa, npoints),
1221  getPoint_internal(ppa[i], 1),
1222  cp_point_size * (ppa[i]->npoints - 1));
1223 
1224  npoints += ppa[i]->npoints - 1;
1225  lwfree(ppa[i]);
1226  }
1227  }
1228 
1229  lwfree(ppa);
1230 
1231  parse_gml_srs(xnode, &srs);
1232  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1233  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1234  gml_reproject_pa(pa, srs.srid, *root_srid);
1235  geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
1236 
1237  return geom;
1238 }
1239 
1240 
1244 static LWGEOM* parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid)
1245 {
1246  gmlSrs srs;
1247  LWGEOM *geom;
1248  POINTARRAY **ppa = NULL;
1249 
1250  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1251  if (xnode == NULL)
1252  gml_lwpgerror("invalid GML representation", 30);
1253  parse_gml_srs(xnode, &srs);
1254 
1255  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1256  ppa[0] = parse_gml_data(xnode->children, hasz, root_srid);
1257 
1258  if (ppa[0]->npoints < 4
1259  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1260  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1261  gml_lwpgerror("invalid GML representation", 42);
1262 
1263  if (srs.reverse_axis)
1264  ppa[0] = ptarray_flip_coordinates(ppa[0]);
1265 
1266  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1267  gml_reproject_pa(ppa[0], srs.srid, *root_srid);
1268 
1269  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, 1, ppa);
1270 
1271  return geom;
1272 }
1273 
1274 
1278 static LWGEOM* parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
1279 {
1280  gmlSrs srs;
1281  int i, ring;
1282  LWGEOM *geom;
1283  xmlNodePtr xa, xb;
1284  POINTARRAY **ppa = NULL;
1285 
1286  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1287  if (xnode == NULL)
1288  gml_lwpgerror("invalid GML representation", 30);
1289 
1290  if (xnode->children == NULL)
1291  return lwpoly_as_lwgeom(lwpoly_construct_empty(*root_srid, 0, 0));
1292 
1293  parse_gml_srs(xnode, &srs);
1294 
1295  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1296  {
1297  /* Polygon/outerBoundaryIs -> GML 2.1.2 */
1298  /* Polygon/exterior -> GML 3.1.1 */
1299  if (xa->type != XML_ELEMENT_NODE) continue;
1300  if (!is_gml_namespace(xa, false)) continue;
1301  if (!(is_gml_element(xa, "outerBoundaryIs") ||
1302  is_gml_element(xa, "exterior")))
1303  continue;
1304 
1305  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1306  {
1307  if (xb->type != XML_ELEMENT_NODE) continue;
1308  if (!is_gml_namespace(xb, false)) continue;
1309  if (!is_gml_element(xb, "LinearRing")) continue;
1310 
1311  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1312  ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
1313 
1314  if (ppa[0]->npoints < 4
1315  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1316  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1317  gml_lwpgerror("invalid GML representation", 43);
1318 
1319  if (srs.reverse_axis) ppa[0] = ptarray_flip_coordinates(ppa[0]);
1320  }
1321  }
1322 
1323  /* Found an <exterior> or <outerBoundaryIs> but no rings?!? We're outa here! */
1324  if ( ! ppa )
1325  gml_lwpgerror("invalid GML representation", 43);
1326 
1327  for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
1328  {
1329  /* Polygon/innerBoundaryIs -> GML 2.1.2 */
1330  /* Polygon/interior -> GML 3.1.1 */
1331  if (xa->type != XML_ELEMENT_NODE) continue;
1332  if (!is_gml_namespace(xa, false)) continue;
1333  if (!(is_gml_element(xa, "innerBoundaryIs") ||
1334  is_gml_element(xa, "interior")))
1335  continue;
1336 
1337  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1338  {
1339  if (xb->type != XML_ELEMENT_NODE) continue;
1340  if (!is_gml_namespace(xb, false)) continue;
1341  if (!is_gml_element(xb, "LinearRing")) continue;
1342 
1343  ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1344  sizeof(POINTARRAY*) * (ring + 1));
1345  ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
1346 
1347  if (ppa[ring]->npoints < 4
1348  || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
1349  || (*hasz && !ptarray_is_closed_3d(ppa[ring])))
1350  gml_lwpgerror("invalid GML representation", 43);
1351 
1352  if (srs.reverse_axis) ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
1353  ring++;
1354  }
1355  }
1356 
1357  /* Exterior Ring is mandatory */
1358  if (ppa == NULL || ppa[0] == NULL) gml_lwpgerror("invalid GML representation", 44);
1359 
1360  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1361  {
1362  for (i=0 ; i < ring ; i++)
1363  gml_reproject_pa(ppa[i], srs.srid, *root_srid);
1364  }
1365  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
1366 
1367  return geom;
1368 }
1369 
1370 
1374 static LWGEOM* parse_gml_triangle(xmlNodePtr xnode, bool *hasz, int *root_srid)
1375 {
1376  gmlSrs srs;
1377  LWGEOM *geom;
1378  xmlNodePtr xa, xb;
1379  POINTARRAY *pa = NULL;
1380  xmlChar *interpolation=NULL;
1381 
1382  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1383  if (xnode == NULL)
1384  gml_lwpgerror("invalid GML representation", 30);
1385 
1386  if (xnode->children == NULL)
1387  return lwtriangle_as_lwgeom(lwtriangle_construct_empty(*root_srid, 0, 0));
1388 
1389  /* GML SF is restricted to planar interpolation
1390  NOTA: I know Triangle is not part of SF, but
1391  we have to be consistent with other surfaces */
1392  interpolation = gmlGetProp(xnode, "interpolation");
1393  if (interpolation != NULL)
1394  {
1395  if (strcmp((char *) interpolation, "planar"))
1396  gml_lwpgerror("invalid GML representation", 45);
1397  xmlFree(interpolation);
1398  }
1399 
1400  parse_gml_srs(xnode, &srs);
1401 
1402  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1403  {
1404  /* Triangle/exterior */
1405  if (xa->type != XML_ELEMENT_NODE) continue;
1406  if (!is_gml_namespace(xa, false)) continue;
1407  if (!is_gml_element(xa, "exterior")) continue;
1408 
1409  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1410  {
1411  /* Triangle/exterior/LinearRing */
1412  if (xb->type != XML_ELEMENT_NODE) continue;
1413  if (!is_gml_namespace(xb, false)) continue;
1414  if (!is_gml_element(xb, "LinearRing")) continue;
1415 
1416  pa = (POINTARRAY*) lwalloc(sizeof(POINTARRAY));
1417  pa = parse_gml_data(xb->children, hasz, root_srid);
1418 
1419  if (pa->npoints != 4
1420  || (!*hasz && !ptarray_is_closed_2d(pa))
1421  || (*hasz && !ptarray_is_closed_3d(pa)))
1422  gml_lwpgerror("invalid GML representation", 46);
1423 
1424  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1425  }
1426  }
1427 
1428  /* Exterior Ring is mandatory */
1429  if (pa == NULL) gml_lwpgerror("invalid GML representation", 47);
1430 
1431  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1432  gml_reproject_pa(pa, srs.srid, *root_srid);
1433 
1434  geom = (LWGEOM *) lwtriangle_construct(*root_srid, NULL, pa);
1435 
1436  return geom;
1437 }
1438 
1439 
1443 static LWGEOM* parse_gml_patch(xmlNodePtr xnode, bool *hasz, int *root_srid)
1444 {
1445  xmlChar *interpolation=NULL;
1446  POINTARRAY **ppa=NULL;
1447  LWGEOM *geom=NULL;
1448  xmlNodePtr xa, xb;
1449  int i, ring=0;
1450  gmlSrs srs;
1451 
1452  /* PolygonPatch */
1453  if (!is_gml_element(xnode, "PolygonPatch"))
1454  gml_lwpgerror("invalid GML representation", 48);
1455 
1456  /* GML SF is restricted to planar interpolation */
1457  interpolation = gmlGetProp(xnode, "interpolation");
1458  if (interpolation != NULL)
1459  {
1460  if (strcmp((char *) interpolation, "planar"))
1461  gml_lwpgerror("invalid GML representation", 48);
1462  xmlFree(interpolation);
1463  }
1464 
1465  parse_gml_srs(xnode, &srs);
1466 
1467  /* PolygonPatch/exterior */
1468  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1469  {
1470  if (!is_gml_namespace(xa, false)) continue;
1471  if (!is_gml_element(xa, "exterior")) continue;
1472 
1473  /* PolygonPatch/exterior/LinearRing */
1474  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1475  {
1476  if (xb->type != XML_ELEMENT_NODE) continue;
1477  if (!is_gml_namespace(xb, false)) continue;
1478  if (!is_gml_element(xb, "LinearRing")) continue;
1479 
1480  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1481  ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
1482 
1483  if (ppa[0]->npoints < 4
1484  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1485  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1486  gml_lwpgerror("invalid GML representation", 48);
1487 
1488  if (srs.reverse_axis)
1489  ppa[0] = ptarray_flip_coordinates(ppa[0]);
1490  }
1491  }
1492 
1493  /* Interior but no Exterior ! */
1494  if ( ! ppa )
1495  gml_lwpgerror("invalid GML representation", 48);
1496 
1497  /* PolygonPatch/interior */
1498  for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
1499  {
1500  if (xa->type != XML_ELEMENT_NODE) continue;
1501  if (!is_gml_namespace(xa, false)) continue;
1502  if (!is_gml_element(xa, "interior")) continue;
1503 
1504  /* PolygonPatch/interior/LinearRing */
1505  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1506  {
1507  if (xb->type != XML_ELEMENT_NODE) continue;
1508  if (!is_gml_element(xb, "LinearRing")) continue;
1509 
1510  ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1511  sizeof(POINTARRAY*) * (ring + 1));
1512  ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
1513 
1514  if (ppa[ring]->npoints < 4
1515  || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
1516  || ( *hasz && !ptarray_is_closed_3d(ppa[ring])))
1517  gml_lwpgerror("invalid GML representation", 49);
1518 
1519  if (srs.reverse_axis)
1520  ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
1521 
1522  ring++;
1523  }
1524  }
1525 
1526  /* Exterior Ring is mandatory */
1527  if (ppa == NULL || ppa[0] == NULL) gml_lwpgerror("invalid GML representation", 50);
1528 
1529  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1530  {
1531  for (i=0 ; i < ring ; i++)
1532  gml_reproject_pa(ppa[i], srs.srid, *root_srid);
1533  }
1534  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
1535 
1536  return geom;
1537 }
1538 
1539 
1543 static LWGEOM* parse_gml_surface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1544 {
1545  xmlNodePtr xa;
1546  int patch;
1547  LWGEOM *geom=NULL;
1548  bool found=false;
1549 
1550  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1551  if (xnode == NULL)
1552  gml_lwpgerror("invalid GML representation", 30);
1553 
1554  /* Looking for gml:patches */
1555  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1556  {
1557  if (xa->type != XML_ELEMENT_NODE) continue;
1558  if (!is_gml_namespace(xa, false)) continue;
1559  if (is_gml_element(xa, "patches"))
1560  {
1561  found = true;
1562  break;
1563  }
1564  }
1565  if (!found) gml_lwpgerror("invalid GML representation", 51);
1566 
1567  /* Processing gml:PolygonPatch */
1568  for (patch=0, xa = xa->children ; xa != NULL ; xa = xa->next)
1569  {
1570  if (xa->type != XML_ELEMENT_NODE) continue;
1571  if (!is_gml_namespace(xa, false)) continue;
1572  if (!is_gml_element(xa, "PolygonPatch")) continue;
1573  patch++;
1574 
1575  /* SQL/MM define ST_CurvePolygon as a single patch only,
1576  cf ISO 13249-3:2009 -> 4.2.9 (p27) */
1577  if (patch > 1) gml_lwpgerror("invalid GML representation", 52);
1578 
1579  geom = parse_gml_patch(xa, hasz, root_srid);
1580  }
1581 
1582  if (!patch) gml_lwpgerror("invalid GML representation", 53);
1583 
1584  return geom;
1585 }
1586 
1587 
1597 static LWGEOM* parse_gml_tin(xmlNodePtr xnode, bool *hasz, int *root_srid)
1598 {
1599  gmlSrs srs;
1600  xmlNodePtr xa;
1601  LWGEOM *geom=NULL;
1602  bool found=false;
1603 
1604  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1605  if (xnode == NULL)
1606  gml_lwpgerror("invalid GML representation", 30);
1607 
1608  parse_gml_srs(xnode, &srs);
1609  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1610  *root_srid = srs.srid;
1611 
1612  geom = (LWGEOM *)lwcollection_construct_empty(TINTYPE, *root_srid, 1, 0);
1613 
1614  if (xnode->children == NULL)
1615  return geom;
1616 
1617  /* Looking for gml:patches or gml:trianglePatches */
1618  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1619  {
1620  if (xa->type != XML_ELEMENT_NODE) continue;
1621  if (!is_gml_namespace(xa, false)) continue;
1622  if (is_gml_element(xa, "patches") ||
1623  is_gml_element(xa, "trianglePatches"))
1624  {
1625  found = true;
1626  break;
1627  }
1628  }
1629  if (!found) return geom; /* empty one */
1630 
1631  /* Processing each gml:Triangle */
1632  for (xa = xa->children ; xa != NULL ; xa = xa->next)
1633  {
1634  if (xa->type != XML_ELEMENT_NODE) continue;
1635  if (!is_gml_namespace(xa, false)) continue;
1636  if (!is_gml_element(xa, "Triangle")) continue;
1637 
1638  if (xa->children != NULL)
1639  geom = (LWGEOM*) lwtin_add_lwtriangle((LWTIN *) geom,
1640  (LWTRIANGLE *) parse_gml_triangle(xa, hasz, root_srid));
1641  }
1642 
1643  return geom;
1644 }
1645 
1646 
1650 static LWGEOM* parse_gml_mpoint(xmlNodePtr xnode, bool *hasz, int *root_srid)
1651 {
1652  gmlSrs srs;
1653  xmlNodePtr xa, xb;
1654  LWGEOM *geom = NULL;
1655 
1656  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1657  if (xnode == NULL)
1658  gml_lwpgerror("invalid GML representation", 30);
1659 
1660  parse_gml_srs(xnode, &srs);
1661  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1662  *root_srid = srs.srid;
1663 
1664  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOINTTYPE, *root_srid, 1, 0);
1665 
1666  if (xnode->children == NULL)
1667  return geom;
1668 
1669  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1670  {
1671  /* MultiPoint/pointMember */
1672  if (xa->type != XML_ELEMENT_NODE) continue;
1673  if (!is_gml_namespace(xa, false)) continue;
1674  if (is_gml_element(xa, "pointMembers"))
1675  {
1676  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1677  {
1678  geom = (LWGEOM*)lwmpoint_add_lwpoint(
1679  (LWMPOINT*)geom,
1680  (LWPOINT*)parse_gml(xb, hasz, root_srid));
1681  }
1682  }
1683  else if (is_gml_element(xa, "pointMember"))
1684  {
1685  if (xa->children != NULL)
1686  geom = (LWGEOM*)lwmpoint_add_lwpoint((LWMPOINT*)geom,
1687  (LWPOINT*)parse_gml(xa->children, hasz, root_srid));
1688  }
1689  }
1690 
1691  return geom;
1692 }
1693 
1694 
1698 static LWGEOM* parse_gml_mline(xmlNodePtr xnode, bool *hasz, int *root_srid)
1699 {
1700  gmlSrs srs;
1701  xmlNodePtr xa;
1702  LWGEOM *geom = NULL;
1703 
1704  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1705  if (xnode == NULL)
1706  gml_lwpgerror("invalid GML representation", 30);
1707  if (xnode == NULL)
1708  gml_lwpgerror("invalid GML representation", 30);
1709 
1710  parse_gml_srs(xnode, &srs);
1711  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1712  *root_srid = srs.srid;
1713 
1714  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
1715 
1716  if (xnode->children == NULL)
1717  return geom;
1718 
1719  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1720  {
1721  /* MultiLineString/lineStringMember */
1722  if (xa->type != XML_ELEMENT_NODE) continue;
1723  if (!is_gml_namespace(xa, false)) continue;
1724  if (!is_gml_element(xa, "lineStringMember")) continue;
1725  if (xa->children != NULL)
1726  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1727  (LWLINE*)parse_gml(xa->children, hasz, root_srid));
1728  }
1729 
1730  return geom;
1731 }
1732 
1733 
1737 static LWGEOM* parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
1738 {
1739  gmlSrs srs;
1740  xmlNodePtr xa, xb;
1741  LWGEOM *geom = NULL;
1742 
1743  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1744  if (xnode == NULL)
1745  gml_lwpgerror("invalid GML representation", 30);
1746 
1747  parse_gml_srs(xnode, &srs);
1748  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1749  *root_srid = srs.srid;
1750 
1751  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
1752 
1753  if (xnode->children == NULL)
1754  return geom;
1755 
1756  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1757  {
1758 
1759  /* MultiCurve/curveMember */
1760  if (xa->type != XML_ELEMENT_NODE) continue;
1761  if (!is_gml_namespace(xa, false)) continue;
1762  if (is_gml_element(xa, "curveMembers"))
1763  {
1764  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1765  {
1766  if (xb != NULL)
1767  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1768  (LWLINE*)parse_gml(xb, hasz, root_srid));
1769  }
1770  }
1771  else if (is_gml_element(xa, "curveMember"))
1772  {
1773  if (xa->children != NULL)
1774  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1775  (LWLINE*)parse_gml(xa->children, hasz, root_srid));
1776  }
1777  }
1778 
1779  return geom;
1780 }
1781 
1782 
1786 static LWGEOM* parse_gml_mpoly(xmlNodePtr xnode, bool *hasz, int *root_srid)
1787 {
1788  gmlSrs srs;
1789  xmlNodePtr xa;
1790  LWGEOM *geom = NULL;
1791 
1792  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1793  if (xnode == NULL)
1794  gml_lwpgerror("invalid GML representation", 30);
1795 
1796  parse_gml_srs(xnode, &srs);
1797  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1798  *root_srid = srs.srid;
1799 
1800  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
1801 
1802  if (xnode->children == NULL)
1803  return geom;
1804 
1805  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1806  {
1807  /* MultiPolygon/polygonMember */
1808  if (xa->type != XML_ELEMENT_NODE) continue;
1809  if (!is_gml_namespace(xa, false)) continue;
1810  if (!is_gml_element(xa, "polygonMember")) continue;
1811  if (xa->children != NULL)
1812  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1813  (LWPOLY*)parse_gml(xa->children, hasz, root_srid));
1814  }
1815 
1816  return geom;
1817 }
1818 
1819 
1823 static LWGEOM* parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1824 {
1825  gmlSrs srs;
1826  xmlNodePtr xa, xb;
1827  LWGEOM *geom = NULL;
1828 
1829  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1830  if (xnode == NULL)
1831  gml_lwpgerror("invalid GML representation", 30);
1832 
1833  parse_gml_srs(xnode, &srs);
1834  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1835  *root_srid = srs.srid;
1836 
1837  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
1838 
1839  if (xnode->children == NULL)
1840  return geom;
1841 
1842  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1843  {
1844  /* MultiSurface/surfaceMember */
1845  if (xa->type != XML_ELEMENT_NODE) continue;
1846  if (!is_gml_namespace(xa, false)) continue;
1847  if (is_gml_element(xa, "surfaceMembers"))
1848  {
1849  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1850  {
1851  if (xb != NULL)
1852  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1853  (LWPOLY*)parse_gml(xb, hasz, root_srid));
1854  }
1855  }
1856  else if (is_gml_element(xa, "surfaceMember"))
1857  {
1858  if (xa->children != NULL)
1859  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1860  (LWPOLY*)parse_gml(xa->children, hasz, root_srid));
1861  }
1862  }
1863 
1864  return geom;
1865 }
1866 
1867 
1872 static LWGEOM* parse_gml_psurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1873 {
1874  gmlSrs srs;
1875  xmlNodePtr xa;
1876  bool found = false;
1877  LWGEOM *geom = NULL;
1878 
1879  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1880  if (xnode == NULL)
1881  gml_lwpgerror("invalid GML representation", 30);
1882 
1883  parse_gml_srs(xnode, &srs);
1884  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1885  *root_srid = srs.srid;
1886 
1887  geom = (LWGEOM *)lwcollection_construct_empty(POLYHEDRALSURFACETYPE, *root_srid, 1, 0);
1888 
1889  if (xnode->children == NULL)
1890  return geom;
1891 
1892  /* Looking for gml:polygonPatches */
1893  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1894  {
1895  if (xa->type != XML_ELEMENT_NODE) continue;
1896  if (!is_gml_namespace(xa, false)) continue;
1897  if (is_gml_element(xa, "polygonPatches"))
1898  {
1899  found = true;
1900  break;
1901  }
1902  }
1903  if (!found) return geom;
1904 
1905  for (xa = xa->children ; xa != NULL ; xa = xa->next)
1906  {
1907  /* PolyhedralSurface/polygonPatches/PolygonPatch */
1908  if (xa->type != XML_ELEMENT_NODE) continue;
1909  if (!is_gml_namespace(xa, false)) continue;
1910  if (!is_gml_element(xa, "PolygonPatch")) continue;
1911 
1912  geom = (LWGEOM*)lwpsurface_add_lwpoly((LWPSURFACE*)geom,
1913  (LWPOLY*)parse_gml_patch(xa, hasz, root_srid));
1914  }
1915 
1916  return geom;
1917 }
1918 
1919 
1923 static LWGEOM* parse_gml_coll(xmlNodePtr xnode, bool *hasz, int *root_srid)
1924 {
1925  gmlSrs srs;
1926  xmlNodePtr xa;
1927  LWGEOM *geom = NULL;
1928 
1929  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1930 
1931  parse_gml_srs(xnode, &srs);
1932  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1933  *root_srid = srs.srid;
1934 
1935  geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, *root_srid, 1, 0);
1936 
1937  if (xnode->children == NULL)
1938  return geom;
1939 
1940  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1941  {
1942  if (xa->type != XML_ELEMENT_NODE) continue;
1943  if (!is_gml_namespace(xa, false)) continue;
1944 
1945  /*
1946  * In GML 2.1.2 pointMember, lineStringMember and
1947  * polygonMember are parts of geometryMember
1948  * substitution group
1949  */
1950  if ( is_gml_element(xa, "pointMember")
1951  || is_gml_element(xa, "lineStringMember")
1952  || is_gml_element(xa, "polygonMember")
1953  || is_gml_element(xa, "geometryMember"))
1954  {
1955  if (xa->children == NULL) break;
1956  geom = (LWGEOM*)lwcollection_add_lwgeom((LWCOLLECTION *)geom,
1957  parse_gml(xa->children, hasz, root_srid));
1958  }
1959  }
1960 
1961  return geom;
1962 }
1963 
1967 static LWGEOM *
1968 lwgeom_from_gml(const char *xml, int xml_size)
1969 {
1970  xmlDocPtr xmldoc;
1971  xmlNodePtr xmlroot=NULL;
1972  LWGEOM *lwgeom = NULL;
1973  bool hasz=true;
1974  int root_srid=SRID_UNKNOWN;
1975 
1976  /* Begin to Parse XML doc */
1977  xmlInitParser();
1978 
1979  xmldoc = xmlReadMemory(xml, xml_size, NULL, NULL, 0);
1980  if (!xmldoc)
1981  {
1982  xmlCleanupParser();
1983  gml_lwpgerror("invalid GML representation", 1);
1984  return NULL;
1985  }
1986 
1987  xmlroot = xmlDocGetRootElement(xmldoc);
1988  if (!xmlroot)
1989  {
1990  xmlFreeDoc(xmldoc);
1991  xmlCleanupParser();
1992  gml_lwpgerror("invalid GML representation", 1);
1993  return NULL;
1994  }
1995 
1996  lwgeom = parse_gml(xmlroot, &hasz, &root_srid);
1997 
1998  xmlFreeDoc(xmldoc);
1999  xmlCleanupParser();
2000  /* shouldn't we be releasing xmldoc too here ? */
2001 
2002  if ( root_srid != SRID_UNKNOWN )
2003  lwgeom->srid = root_srid;
2004 
2005  /* GML geometries could be either 2 or 3D and can be nested mixed.
2006  * Missing Z dimension is even tolerated inside some GML coords
2007  *
2008  * So we deal with 3D in all structures allocation, and flag hasz
2009  * to false if we met once a missing Z dimension
2010  * In this case, we force recursive 2D.
2011  */
2012  if (!hasz)
2013  {
2014  LWGEOM *tmp = lwgeom_force_2d(lwgeom);
2015  lwgeom_free(lwgeom);
2016  lwgeom = tmp;
2017  }
2018 
2019  return lwgeom;
2020 }
2021 
2022 
2026 static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid)
2027 {
2028  xmlNodePtr xa = xnode;
2029  gmlSrs srs;
2030 
2031  /* Scroll forward to the root node */
2032  while (xa != NULL &&
2033  (xa->type != XML_ELEMENT_NODE || !is_gml_namespace(xa, false)))
2034  {
2035  xa = xa->next;
2036  }
2037 
2038  if (xa == NULL) gml_lwpgerror("invalid GML representation", 55);
2039 
2040  parse_gml_srs(xa, &srs);
2041  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
2042  {
2043  *root_srid = srs.srid;
2044  }
2045 
2046  if (is_gml_element(xa, "Point"))
2047  return parse_gml_point(xa, hasz, root_srid);
2048 
2049  if (is_gml_element(xa, "LineString"))
2050  return parse_gml_line(xa, hasz, root_srid);
2051 
2052  if (is_gml_element(xa, "Curve"))
2053  return parse_gml_curve(xa, hasz, root_srid);
2054 
2055  if (is_gml_element(xa, "LinearRing"))
2056  return parse_gml_linearring(xa, hasz, root_srid);
2057 
2058  if (is_gml_element(xa, "Polygon"))
2059  return parse_gml_polygon(xa, hasz, root_srid);
2060 
2061  if (is_gml_element(xa, "Triangle"))
2062  return parse_gml_triangle(xa, hasz, root_srid);
2063 
2064  if (is_gml_element(xa, "Surface"))
2065  return parse_gml_surface(xa, hasz, root_srid);
2066 
2067  if (is_gml_element(xa, "MultiPoint"))
2068  return parse_gml_mpoint(xa, hasz, root_srid);
2069 
2070  if (is_gml_element(xa, "MultiLineString"))
2071  return parse_gml_mline(xa, hasz, root_srid);
2072 
2073  if (is_gml_element(xa, "MultiCurve"))
2074  return parse_gml_mcurve(xa, hasz, root_srid);
2075 
2076  if (is_gml_element(xa, "MultiPolygon"))
2077  return parse_gml_mpoly(xa, hasz, root_srid);
2078 
2079  if (is_gml_element(xa, "MultiSurface"))
2080  return parse_gml_msurface(xa, hasz, root_srid);
2081 
2082  if (is_gml_element(xa, "PolyhedralSurface"))
2083  return parse_gml_psurface(xa, hasz, root_srid);
2084 
2085  if (is_gml_element(xa, "Tin") ||
2086  is_gml_element(xa, "TriangulatedSurface"))
2087  return parse_gml_tin(xa, hasz, root_srid);
2088 
2089  if (is_gml_element(xa, "MultiGeometry"))
2090  return parse_gml_coll(xa, hasz, root_srid);
2091 
2092  gml_lwpgerror("invalid GML representation", 56);
2093  return NULL; /* Never reach */
2094 }
LWPOINT * lwpoint_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwpoint.c:151
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
#define LW_FALSE
Definition: liblwgeom.h:109
#define COLLECTIONTYPE
Definition: liblwgeom.h:123
int ptarray_transform(POINTARRAY *pa, LWPROJ *pj)
#define LW_FAILURE
Definition: liblwgeom.h:111
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1155
int ptarray_is_closed_3d(const POINTARRAY *pa)
Definition: ptarray.c:714
#define MULTILINETYPE
Definition: liblwgeom.h:121
LWTIN * lwtin_add_lwtriangle(LWTIN *mobj, const LWTRIANGLE *obj)
Definition: lwtin.c:34
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:329
#define MULTIPOINTTYPE
Definition: liblwgeom.h:120
LWMLINE * lwmline_add_lwline(LWMLINE *mobj, const LWLINE *obj)
Definition: lwmline.c:46
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
Definition: ptarray.c:51
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
LWTRIANGLE * lwtriangle_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwtriangle.c:58
LWMPOINT * lwmpoint_add_lwpoint(LWMPOINT *mobj, const LWPOINT *obj)
Definition: lwmpoint.c:45
#define TINTYPE
Definition: liblwgeom.h:131
LWMPOLY * lwmpoly_add_lwpoly(LWMPOLY *mobj, const LWPOLY *obj)
Definition: lwmpoly.c:47
LWPSURFACE * lwpsurface_add_lwpoly(LWPSURFACE *mobj, const LWPOLY *obj)
Definition: lwpsurface.c:33
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:122
LWPROJ * lwproj_from_str(const char *str_in, const char *str_out)
Allocate a new LWPROJ containing the reference to the PROJ's PJ If extra_geography_data is true,...
void * lwrealloc(void *mem, size_t size)
Definition: lwutil.c:235
void lwfree(void *mem)
Definition: lwutil.c:242
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:344
LWPOINT * lwpoint_construct(int32_t srid, GBOX *bbox, POINTARRAY *point)
Definition: lwpoint.c:129
#define __attribute__(x)
Definition: liblwgeom.h:243
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:129
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:59
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwcollection.c:92
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
Definition: ptarray.c:147
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:188
void * lwalloc(size_t size)
Definition: lwutil.c:227
int ptarray_is_closed_2d(const POINTARRAY *pa)
Definition: ptarray.c:701
LWGEOM * lwtriangle_as_lwgeom(const LWTRIANGLE *obj)
Definition: lwgeom.c:334
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:108
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:230
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwpoly.c:161
LWPOLY * lwpoly_construct(int32_t srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition: lwpoly.c:43
POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2)
Merge two given POINTARRAY and returns a pointer on the new aggregate one.
Definition: ptarray.c:603
POINTARRAY * ptarray_flip_coordinates(POINTARRAY *pa)
Reverse X and Y axis on a given POINTARRAY.
Definition: ptarray.c:368
LWLINE * lwline_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwline.c:55
LWTRIANGLE * lwtriangle_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwtriangle.c:40
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:793
This library is the generic geometry handling section of PostGIS.
static LWGEOM * parse_gml_surface(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Surface (3.1.1)
struct struct_gmlSrs gmlSrs
static xmlNodePtr get_xlink_node(xmlNodePtr xnode)
Return a xmlNodePtr on a node referenced by a XLink or NULL otherwise.
static POINTARRAY * parse_gml_pos(xmlNodePtr xnode, bool *hasz)
Parse gml:pos.
#define GML_NS
Definition: lwgeom_in_gml.c:76
PG_FUNCTION_INFO_V1(geom_from_gml)
Ability to parse GML geometry fragment and to return an LWGEOM or an error message.
static bool is_xlink(xmlNodePtr node)
Return true if current node contains a simple XLink Return false otherwise.
#define GML32_NS
Definition: lwgeom_in_gml.c:77
#define XLINK_NS
Definition: lwgeom_in_gml.c:75
static LWGEOM * parse_gml_patch(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML PolygonPatch (3.1.1)
static LWGEOM * parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiSurface (3.1.1)
static LWGEOM * parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML.
static LWGEOM * parse_gml_psurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML PolyhedralSurface (3.1.1) Nota: It's not part of SF-2.
static LWGEOM * parse_gml_coll(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiGeometry (2.1.2, 3.1.1)
static POINTARRAY * gml_reproject_pa(POINTARRAY *pa, int32_t epsg_in, int32_t epsg_out)
Use Proj to reproject a given POINTARRAY.
static double parse_gml_double(char *d, bool space_before, bool space_after)
Parse a string supposed to be a double.
static int gml_is_srs_axis_order_gis_friendly(int32_t srid)
Return 1 if the SRS definition from the authority has a GIS friendly order, that is easting,...
static LWGEOM * parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiCurve (3.1.1)
Datum geom_from_gml(PG_FUNCTION_ARGS)
Definition: lwgeom_in_gml.c:97
static LWGEOM * lwgeom_from_gml(const char *wkt, int xml_size)
Read GML.
static xmlChar * gmlGetProp(xmlNodePtr xnode, const char *charProp)
Retrieve a GML property from a node or NULL otherwise Respect namespaces if presents in the node elem...
static bool is_gml_namespace(xmlNodePtr xnode, bool is_strict)
Return false if current element namespace is not a GML one Return true otherwise.
static void parse_gml_srs(xmlNodePtr xnode, gmlSrs *srs)
Parse gml srsName attribute.
static LWGEOM * parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Polygon (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_coordinates(xmlNodePtr xnode, bool *hasz)
Parse gml:coordinates.
static LWGEOM * parse_gml_line(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML lineString (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_data(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse data coordinates.
static LWGEOM * parse_gml_mpoly(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiPolygon (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_coord(xmlNodePtr xnode, bool *hasz)
Parse gml:coord.
static LWGEOM * parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Curve (3.1.1)
static void gml_lwpgerror(char *msg, __attribute__((__unused__)) int error_code)
Definition: lwgeom_in_gml.c:81
static LWGEOM * parse_gml_mpoint(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse gml:MultiPoint (2.1.2, 3.1.1)
static LWGEOM * parse_gml_point(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML point (2.1.2, 3.1.1)
static LWGEOM * parse_gml_tin(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Tin (and TriangulatedSurface) (3.1.1)
static LWGEOM * parse_gml_triangle(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Triangle (3.1.1)
static LWGEOM * parse_gml_mline(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse gml:MultiLineString (2.1.2, 3.1.1)
static POINTARRAY * parse_gml_poslist(xmlNodePtr xnode, bool *hasz)
Parse gml:posList.
static bool is_gml_element(xmlNodePtr xn, const char *gml_name)
static LWGEOM * parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML LinearRing (3.1.1)
void * malloc(YYSIZE_T)
void free(void *)
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:77
int value
Definition: genraster.py:62
int32_t srid
Definition: liblwgeom.h:475
PJ * pj
Definition: liblwgeom.h:61
double m
Definition: liblwgeom.h:429
double x
Definition: liblwgeom.h:429
double z
Definition: liblwgeom.h:429
double y
Definition: liblwgeom.h:429
uint32_t npoints
Definition: liblwgeom.h:442