PostGIS  2.1.10dev-r@@SVN_REVISION@@
lwgeom_in_gml.c
Go to the documentation of this file.
1 /**********************************************************************
2  * $Id: lwgeom_in_gml.c 13339 2015-03-16 18:35:17Z pramsey $
3  *
4  * PostGIS - Spatial Types for PostgreSQL
5  * http://postgis.net
6  * Copyright 2009 - 2010 Oslandia
7  *
8  * This is free software; you can redistribute and/or modify it under
9  * the terms of the GNU General Public Licence. See the COPYING file.
10  *
11  **********************************************************************/
12 
37 #include <libxml/tree.h>
38 #include <libxml/parser.h>
39 #include <libxml/xpath.h>
40 #include <libxml/xpathInternals.h>
41 
42 #include "postgres.h"
43 #include "executor/spi.h"
44 
45 #include "../postgis_config.h"
46 #include "lwgeom_pg.h"
47 #include "liblwgeom.h"
48 #include "lwgeom_transform.h"
49 
50 
51 Datum geom_from_gml(PG_FUNCTION_ARGS);
52 static LWGEOM* lwgeom_from_gml(const char *wkt);
53 static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid);
54 
55 typedef struct struct_gmlSrs
56 {
57  int srid;
59 }
60 gmlSrs;
61 
62 #define XLINK_NS ((char *) "http://www.w3.org/1999/xlink")
63 #define GML_NS ((char *) "http://www.opengis.net/gml")
64 #define GML32_NS ((char *) "http://www.opengis.net/gml/3.2")
65 
66 
67 
68 static void gml_lwerror(char *msg, int error_code)
69 {
70  POSTGIS_DEBUGF(3, "ST_GeomFromGML ERROR %i", error_code);
71  lwerror("%s", msg);
72 }
73 
84 Datum geom_from_gml(PG_FUNCTION_ARGS)
85 {
86  GSERIALIZED *geom;
87  text *xml_input;
88  LWGEOM *lwgeom;
89  char *xml;
90  int root_srid=SRID_UNKNOWN;
91 
92 
93  /* Get the GML stream */
94  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
95  xml_input = PG_GETARG_TEXT_P(0);
96  xml = text2cstring(xml_input);
97 
98  /* Zero for undefined */
99  root_srid = PG_GETARG_INT32(1);
100 
101  lwgeom = lwgeom_from_gml(xml);
102  if ( root_srid != SRID_UNKNOWN )
103  lwgeom->srid = root_srid;
104 
105  geom = geometry_serialize(lwgeom);
106  lwgeom_free(lwgeom);
107 
108  PG_RETURN_POINTER(geom);
109 }
110 
111 
116 static bool is_gml_namespace(xmlNodePtr xnode, bool is_strict)
117 {
118  xmlNsPtr *ns, *p;
119 
120  ns = xmlGetNsList(xnode->doc, xnode);
121  /*
122  * If no namespace is available we could return true anyway
123  * (because we work only on GML fragment, we don't want to
124  * 'oblige' to add namespace on the geometry root node)
125  */
126  if (ns == NULL) { return !is_strict; }
127 
128  /*
129  * Handle namespaces:
130  * - http://www.opengis.net/gml (GML 3.1.1 and priors)
131  * - http://www.opengis.net/gml/3.2 (GML 3.2.1)
132  */
133  for (p=ns ; *p ; p++)
134  {
135  if ((*p)->href == NULL || (*p)->prefix == NULL ||
136  xnode->ns == NULL || xnode->ns->prefix == NULL) continue;
137 
138  if (!xmlStrcmp(xnode->ns->prefix, (*p)->prefix))
139  {
140  if ( !strcmp((char *) (*p)->href, GML_NS)
141  || !strcmp((char *) (*p)->href, GML32_NS))
142  {
143  xmlFree(ns);
144  return true;
145  } else {
146  xmlFree(ns);
147  return false;
148  }
149  }
150  }
151 
152  xmlFree(ns);
153  return !is_strict; /* Same reason here to not return false */
154 }
155 
156 
161 static xmlChar *gmlGetProp(xmlNodePtr xnode, xmlChar *prop)
162 {
163  xmlChar *value;
164 
165  if (!is_gml_namespace(xnode, true))
166  return xmlGetProp(xnode, prop);
167  /*
168  * Handle namespaces:
169  * - http://www.opengis.net/gml (GML 3.1.1 and priors)
170  * - http://www.opengis.net/gml/3.2 (GML 3.2.1)
171  */
172  value = xmlGetNsProp(xnode, prop, (xmlChar *) GML_NS);
173  if (value == NULL) value = xmlGetNsProp(xnode, prop, (xmlChar *) GML32_NS);
174 
175  /* In last case try without explicit namespace */
176  if (value == NULL) value = xmlGetNoNsProp(xnode, prop);
177 
178  return value;
179 }
180 
181 
186 static bool is_xlink(xmlNodePtr node)
187 {
188  xmlChar *prop;
189 
190  prop = xmlGetNsProp(node, (xmlChar *)"type", (xmlChar *) XLINK_NS);
191  if (prop == NULL) return false;
192  if (strcmp((char *) prop, "simple"))
193  {
194  xmlFree(prop);
195  return false;
196  }
197 
198  prop = xmlGetNsProp(node, (xmlChar *)"href", (xmlChar *) XLINK_NS);
199  if (prop == NULL) return false;
200  if (prop[0] != '#')
201  {
202  xmlFree(prop);
203  return false;
204  }
205  xmlFree(prop);
206 
207  return true;
208 }
209 
210 
214 static xmlNodePtr get_xlink_node(xmlNodePtr xnode)
215 {
216  char *id;
217  xmlNsPtr *ns, *n;
218  xmlXPathContext *ctx;
219  xmlXPathObject *xpath;
220  xmlNodePtr node, ret_node;
221  xmlChar *href, *p, *node_id;
222 
223  href = xmlGetNsProp(xnode, (xmlChar *)"href", (xmlChar *) XLINK_NS);
224  id = lwalloc((xmlStrlen(xnode->ns->prefix) * 2 + xmlStrlen(xnode->name)
225  + xmlStrlen(href) + sizeof("//:[@:id='']") + 1));
226  p = href;
227  p++; /* ignore '#' first char */
228 
229  /* XPath pattern look like: //gml:point[@gml:id='p1'] */
230  sprintf(id, "//%s:%s[@%s:id='%s']", (char *) xnode->ns->prefix,
231  (char *) xnode->name,
232  (char *) xnode->ns->prefix,
233  (char *) p);
234 
235  ctx = xmlXPathNewContext(xnode->doc);
236  if (ctx == NULL)
237  {
238  xmlFree(href);
239  lwfree(id);
240  return NULL;
241  }
242 
243  /* Handle namespaces */
244  ns = xmlGetNsList(xnode->doc, xnode);
245  for (n=ns ; *n; n++) xmlXPathRegisterNs(ctx, (*n)->prefix, (*n)->href);
246  xmlFree(ns);
247 
248  /* Execute XPath expression */
249  xpath = xmlXPathEvalExpression((xmlChar *) id, ctx);
250  lwfree(id);
251  if (xpath == NULL || xpath->nodesetval == NULL || xpath->nodesetval->nodeNr != 1)
252  {
253  xmlFree(href);
254  xmlXPathFreeObject(xpath);
255  xmlXPathFreeContext(ctx);
256  return NULL;
257  }
258  ret_node = xpath->nodesetval->nodeTab[0];
259  xmlXPathFreeObject(xpath);
260  xmlXPathFreeContext(ctx);
261 
262  /* Protection against circular calls */
263  for (node = xnode ; node != NULL ; node = node->parent)
264  {
265  if (node->type != XML_ELEMENT_NODE) continue;
266  node_id = gmlGetProp(node, (xmlChar *) "id");
267  if (node_id != NULL)
268  {
269  if (!xmlStrcmp(node_id, p))
270  gml_lwerror("invalid GML representation", 2);
271  xmlFree(node_id);
272  }
273  }
274 
275  xmlFree(href);
276  return ret_node;
277 }
278 
279 
283 static POINTARRAY* gml_reproject_pa(POINTARRAY *pa, int srid_in, int srid_out)
284 {
285  int i;
286  POINT4D p;
287  projPJ in_pj, out_pj;
288  char *text_in, *text_out;
289 
290  if (srid_in == SRID_UNKNOWN) return pa; /* nothing to do */
291  if (srid_out == SRID_UNKNOWN) gml_lwerror("invalid GML representation", 3);
292 
293  text_in = GetProj4StringSPI(srid_in);
294  text_out = GetProj4StringSPI(srid_out);
295 
296  in_pj = lwproj_from_string(text_in);
297  out_pj = lwproj_from_string(text_out);
298 
299  lwfree(text_in);
300  lwfree(text_out);
301 
302  for (i=0 ; i < pa->npoints ; i++)
303  {
304  getPoint4d_p(pa, i, &p);
305  point4d_transform(&p, in_pj, out_pj);
306  ptarray_set_point4d(pa, i, &p);
307  }
308 
309  pj_free(in_pj);
310  pj_free(out_pj);
311 
312  return pa;
313 }
314 
315 
320 static int gml_is_srid_planar(int srid)
321 {
322  char *result;
323  char query[256];
324  int is_planar, err;
325 
326  if (SPI_OK_CONNECT != SPI_connect ())
327  lwerror("gml_is_srid_planar: could not connect to SPI manager");
328 
329  /* A way to find if this projection is planar or geocentric */
330  sprintf(query, "SELECT position('+units=m ' in proj4text) \
331  FROM spatial_ref_sys WHERE srid='%d'", srid);
332 
333  err = SPI_exec(query, 1);
334  if (err < 0) lwerror("gml_is_srid_planar: error executing query %d", err);
335 
336  /* No entry in spatial_ref_sys */
337  if (SPI_processed <= 0)
338  {
339  SPI_finish();
340  return -1;
341  }
342 
343  result = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
344  is_planar = atoi(result);
345  SPI_finish();
346 
347  return is_planar;
348 }
349 
350 
354 static void parse_gml_srs(xmlNodePtr xnode, gmlSrs *srs)
355 {
356  char *p;
357  int is_planar;
358  xmlNodePtr node;
359  xmlChar *srsname;
360  bool latlon = false;
361  char sep = ':';
362 
363  node = xnode;
364  srsname = gmlGetProp(node, (xmlChar *) "srsName");
365  /*printf("srsname %s\n",srsname);*/
366  if (!srsname)
367  {
368  if (node->parent == NULL)
369  {
370  srs->srid = SRID_UNKNOWN;
371  srs->reverse_axis = false;
372  return;
373  }
374  parse_gml_srs(node->parent, srs);
375  }
376  else
377  {
378  /* Severals srsName formats are available...
379  * cf WFS 1.1.0 -> 9.2 (p36)
380  * cf ISO 19142:2009 -> 7.9.2.4.4 (p34)
381  * cf RFC 5165 <http://tools.ietf.org/html/rfc5165>
382  * cf CITE WFS-1.1 (GetFeature-tc17.2)
383  */
384 
385  /* SRS pattern like: EPSG:4326
386  urn:EPSG:geographicCRS:4326
387  urn:ogc:def:crs:EPSG:4326
388  urn:ogc:def:crs:EPSG::4326
389  urn:ogc:def:crs:EPSG:6.6:4326
390  urn:x-ogc:def:crs:EPSG:6.6:4326
391  http://www.opengis.net/gml/srs/epsg.xml#4326
392  http://www.epsg.org/6.11.2/4326
393  */
394 
395  if (!strncmp((char *) srsname, "EPSG:", 5))
396  {
397  sep = ':';
398  latlon = false;
399  }
400  else if (!strncmp((char *) srsname, "urn:ogc:def:crs:EPSG:", 21)
401  || !strncmp((char *) srsname, "urn:x-ogc:def:crs:EPSG:", 23)
402  || !strncmp((char *) srsname, "urn:EPSG:geographicCRS:", 23))
403  {
404  sep = ':';
405  latlon = true;
406  }
407  else if (!strncmp((char *) srsname,
408  "http://www.opengis.net/gml/srs/epsg.xml#", 40))
409  {
410  sep = '#';
411  latlon = false;
412  }
413  else gml_lwerror("unknown spatial reference system", 4);
414 
415  /* retrieve the last ':' or '#' char */
416  for (p = (char *) srsname ; *p ; p++);
417  for (--p ; *p != sep ; p--)
418  if (!isdigit(*p)) gml_lwerror("unknown spatial reference system", 5);
419 
420  srs->srid = atoi(++p);
421 
422  /* Check into spatial_ref_sys that this SRID really exist */
423  is_planar = gml_is_srid_planar(srs->srid);
424  if (srs->srid == SRID_UNKNOWN || is_planar == -1)
425  gml_lwerror("unknown spatial reference system", 6);
426 
427  /* About lat/lon issue, Cf: http://tinyurl.com/yjpr55z */
428  srs->reverse_axis = !is_planar && latlon;
429 
430  xmlFree(srsname);
431  return;
432  }
433 }
434 
435 
439 static double parse_gml_double(char *d, bool space_before, bool space_after)
440 {
441  char *p;
442  int st;
443  enum states
444  {
445  INIT = 0,
446  NEED_DIG = 1,
447  DIG = 2,
448  NEED_DIG_DEC = 3,
449  DIG_DEC = 4,
450  EXP = 5,
451  NEED_DIG_EXP = 6,
452  DIG_EXP = 7,
453  END = 8
454  };
455 
456  /*
457  * Double pattern
458  * [-|\+]?[0-9]+(\.)?([0-9]+)?([Ee](\+|-)?[0-9]+)?
459  * We could also meet spaces before and/or after
460  * this pattern upon parameters
461  */
462 
463  if (space_before) while (isspace(*d)) d++;
464  for (st = INIT, p = d ; *p ; p++)
465  {
466 
467  if (isdigit(*p))
468  {
469  if (st == INIT || st == NEED_DIG) st = DIG;
470  else if (st == NEED_DIG_DEC) st = DIG_DEC;
471  else if (st == NEED_DIG_EXP || st == EXP) st = DIG_EXP;
472  else if (st == DIG || st == DIG_DEC || st == DIG_EXP);
473  else gml_lwerror("invalid GML representation", 7);
474  }
475  else if (*p == '.')
476  {
477  if (st == DIG) st = NEED_DIG_DEC;
478  else gml_lwerror("invalid GML representation", 8);
479  }
480  else if (*p == '-' || *p == '+')
481  {
482  if (st == INIT) st = NEED_DIG;
483  else if (st == EXP) st = NEED_DIG_EXP;
484  else gml_lwerror("invalid GML representation", 9);
485  }
486  else if (*p == 'e' || *p == 'E')
487  {
488  if (st == DIG || st == DIG_DEC) st = EXP;
489  else gml_lwerror("invalid GML representation", 10);
490  }
491  else if (isspace(*p))
492  {
493  if (!space_after) gml_lwerror("invalid GML representation", 11);
494  if (st == DIG || st == DIG_DEC || st == DIG_EXP)st = END;
495  else if (st == NEED_DIG_DEC) st = END;
496  else if (st == END);
497  else gml_lwerror("invalid GML representation", 12);
498  }
499  else gml_lwerror("invalid GML representation", 13);
500  }
501 
502  if (st != DIG && st != NEED_DIG_DEC && st != DIG_DEC && st != DIG_EXP && st != END)
503  gml_lwerror("invalid GML representation", 14);
504 
505  return atof(d);
506 }
507 
508 
512 static POINTARRAY* parse_gml_coordinates(xmlNodePtr xnode, bool *hasz)
513 {
514  xmlChar *gml_coord, *gml_ts, *gml_cs, *gml_dec;
515  char cs, ts, dec;
516  POINTARRAY *dpa;
517  int gml_dims;
518  char *p, *q;
519  bool digit;
520  POINT4D pt;
521 
522  /* We begin to retrieve coordinates string */
523  gml_coord = xmlNodeGetContent(xnode);
524  p = (char *) gml_coord;
525 
526  /* Default GML coordinates pattern: x1,y1 x2,y2
527  * x1,y1,z1 x2,y2,z2
528  *
529  * Cf GML 2.1.2 -> 4.3.1 (p18)
530  */
531 
532  /* Retrieve separator between coordinates tuples */
533  gml_ts = gmlGetProp(xnode, (xmlChar *) "ts");
534  if (gml_ts == NULL) ts = ' ';
535  else
536  {
537  if (xmlStrlen(gml_ts) > 1 || isdigit(gml_ts[0]))
538  gml_lwerror("invalid GML representation", 15);
539  ts = gml_ts[0];
540  xmlFree(gml_ts);
541  }
542 
543  /* Retrieve separator between each coordinate */
544  gml_cs = gmlGetProp(xnode, (xmlChar *) "cs");
545  if (gml_cs == NULL) cs = ',';
546  else
547  {
548  if (xmlStrlen(gml_cs) > 1 || isdigit(gml_cs[0]))
549  gml_lwerror("invalid GML representation", 16);
550  cs = gml_cs[0];
551  xmlFree(gml_cs);
552  }
553 
554  /* Retrieve decimal separator */
555  gml_dec = gmlGetProp(xnode, (xmlChar *) "decimal");
556  if (gml_dec == NULL) dec = '.';
557  else
558  {
559  if (xmlStrlen(gml_dec) > 1 || isdigit(gml_dec[0]))
560  gml_lwerror("invalid GML representation", 17);
561  dec = gml_dec[0];
562  xmlFree(gml_dec);
563  }
564 
565  if (cs == ts || cs == dec || ts == dec)
566  gml_lwerror("invalid GML representation", 18);
567 
568  /* HasZ, !HasM, 1 Point */
569  dpa = ptarray_construct_empty(1, 0, 1);
570 
571  while (isspace(*p)) p++; /* Eat extra whitespaces if any */
572  for (q = p, gml_dims=0, digit = false ; *p ; p++)
573  {
574 
575  if (isdigit(*p)) digit = true; /* One state parser */
576 
577  /* Coordinate Separator */
578  if (*p == cs)
579  {
580  *p = '\0';
581  gml_dims++;
582 
583  if (*(p+1) == '\0') gml_lwerror("invalid GML representation", 19);
584 
585  if (gml_dims == 1) pt.x = parse_gml_double(q, false, true);
586  else if (gml_dims == 2) pt.y = parse_gml_double(q, false, true);
587 
588  q = p+1;
589 
590  /* Tuple Separator (or end string) */
591  }
592  else if (digit && (*p == ts || *(p+1) == '\0'))
593  {
594  if (*p == ts) *p = '\0';
595  gml_dims++;
596 
597  if (gml_dims < 2 || gml_dims > 3)
598  gml_lwerror("invalid GML representation", 20);
599 
600  if (gml_dims == 3)
601  pt.z = parse_gml_double(q, false, true);
602  else
603  {
604  pt.y = parse_gml_double(q, false, true);
605  *hasz = false;
606  }
607 
608  ptarray_append_point(dpa, &pt, LW_TRUE);
609  digit = false;
610 
611  q = p+1;
612  gml_dims = 0;
613 
614  /* Need to put standard decimal separator to atof handle */
615  }
616  else if (*p == dec && dec != '.') *p = '.';
617  }
618 
619  xmlFree(gml_coord);
620 
621  return dpa; /* ptarray_clone_deep(dpa); */
622 }
623 
624 
628 static POINTARRAY* parse_gml_coord(xmlNodePtr xnode, bool *hasz)
629 {
630  xmlNodePtr xyz;
631  POINTARRAY *dpa;
632  bool x,y,z;
633  xmlChar *c;
634  POINT4D p;
635 
636  /* HasZ?, !HasM, 1 Point */
637  dpa = ptarray_construct_empty(1, 0, 1);
638 
639  x = y = z = false;
640  for (xyz = xnode->children ; xyz != NULL ; xyz = xyz->next)
641  {
642  if (xyz->type != XML_ELEMENT_NODE) continue;
643  if (!is_gml_namespace(xyz, false)) continue;
644 
645  if (!strcmp((char *) xyz->name, "X"))
646  {
647  if (x) gml_lwerror("invalid GML representation", 21);
648  c = xmlNodeGetContent(xyz);
649  p.x = parse_gml_double((char *) c, true, true);
650  x = true;
651  xmlFree(c);
652  }
653  else if (!strcmp((char *) xyz->name, "Y"))
654  {
655  if (y) gml_lwerror("invalid GML representation", 22);
656  c = xmlNodeGetContent(xyz);
657  p.y = parse_gml_double((char *) c, true, true);
658  y = true;
659  xmlFree(c);
660  }
661  else if (!strcmp((char *) xyz->name, "Z"))
662  {
663  if (z) gml_lwerror("invalid GML representation", 23);
664  c = xmlNodeGetContent(xyz);
665  p.z = parse_gml_double((char *) c, true, true);
666  z = true;
667  xmlFree(c);
668  }
669  }
670  /* Check dimension consistancy */
671  if (!x || !y) gml_lwerror("invalid GML representation", 24);
672  if (!z) *hasz = false;
673 
674  ptarray_append_point(dpa, &p, LW_FALSE);
675  x = y = z = false;
676 
677  return ptarray_clone_deep(dpa);
678 }
679 
680 
684 static POINTARRAY* parse_gml_pos(xmlNodePtr xnode, bool *hasz)
685 {
686  xmlChar *dimension, *gmlpos;
687  int dim, gml_dim;
688  POINTARRAY *dpa;
689  char *pos, *p;
690  bool digit;
691  POINT4D pt;
692 
693  /* HasZ, !HasM, 1 Point */
694  dpa = ptarray_construct_empty(1, 0, 1);
695 
696  dimension = gmlGetProp(xnode, (xmlChar *) "srsDimension");
697  if (dimension == NULL) /* in GML 3.0.0 it was dimension */
698  dimension = gmlGetProp(xnode, (xmlChar *) "dimension");
699  if (dimension == NULL) dim = 2; /* We assume that we are in 2D */
700  else
701  {
702  dim = atoi((char *) dimension);
703  xmlFree(dimension);
704  if (dim < 2 || dim > 3)
705  gml_lwerror("invalid GML representation", 25);
706  }
707  if (dim == 2) *hasz = false;
708 
709  /* We retrieve gml:pos string */
710  gmlpos = xmlNodeGetContent(xnode);
711  pos = (char *) gmlpos;
712  while (isspace(*pos)) pos++; /* Eat extra whitespaces if any */
713 
714  /* gml:pos pattern: x1 y1
715  * x1 y1 z1
716  */
717  for (p=pos, gml_dim=0, digit=false ; *pos ; pos++)
718  {
719  if (isdigit(*pos)) digit = true;
720  if (digit && (*pos == ' ' || *(pos+1) == '\0'))
721  {
722  if (*pos == ' ') *pos = '\0';
723  gml_dim++;
724  if (gml_dim == 1)
725  pt.x = parse_gml_double(p, true, true);
726  else if (gml_dim == 2)
727  pt.y = parse_gml_double(p, true, true);
728  else if (gml_dim == 3)
729  pt.z = parse_gml_double(p, true, true);
730 
731  p = pos+1;
732  digit = false;
733  }
734  }
735  xmlFree(gmlpos);
736 
737  /* Test again coherent dimensions on each coord */
738  if (gml_dim == 2) *hasz = false;
739  if (gml_dim < 2 || gml_dim > 3 || gml_dim != dim)
740  gml_lwerror("invalid GML representation", 26);
741 
742  ptarray_append_point(dpa, &pt, LW_FALSE);
743 
744  return ptarray_clone_deep(dpa);
745 }
746 
747 
751 static POINTARRAY* parse_gml_poslist(xmlNodePtr xnode, bool *hasz)
752 {
753  xmlChar *dimension, *gmlposlist;
754  char *poslist, *p;
755  int dim, gml_dim;
756  POINTARRAY *dpa;
757  POINT4D pt;
758  bool digit;
759 
760  /* Retrieve gml:srsDimension attribute if any */
761  dimension = gmlGetProp(xnode, (xmlChar *) "srsDimension");
762  if (dimension == NULL) /* in GML 3.0.0 it was dimension */
763  dimension = gmlGetProp(xnode, (xmlChar *) "dimension");
764  if (dimension == NULL) dim = 2; /* We assume that we are in common 2D */
765  else
766  {
767  dim = atoi((char *) dimension);
768  xmlFree(dimension);
769  if (dim < 2 || dim > 3) gml_lwerror("invalid GML representation", 27);
770  }
771  if (dim == 2) *hasz = false;
772 
773  /* Retrieve gml:posList string */
774  gmlposlist = xmlNodeGetContent(xnode);
775  poslist = (char *) gmlposlist;
776 
777  /* HasZ?, !HasM, 1 point */
778  dpa = ptarray_construct_empty(1, 0, 1);
779 
780  /* gml:posList pattern: x1 y1 x2 y2
781  * x1 y1 z1 x2 y2 z2
782  */
783  while (isspace(*poslist)) poslist++; /* Eat extra whitespaces if any */
784  for (p=poslist, gml_dim=0, digit=false ; *poslist ; poslist++)
785  {
786  if (isdigit(*poslist)) digit = true;
787  if (digit && (*poslist == ' ' || *(poslist+1) == '\0'))
788  {
789  if (*poslist == ' ') *poslist = '\0';
790 
791  gml_dim++;
792  if (gml_dim == 1) pt.x = parse_gml_double(p, true, true);
793  else if (gml_dim == 2) pt.y = parse_gml_double(p, true, true);
794  else if (gml_dim == 3) pt.z = parse_gml_double(p, true, true);
795 
796  if (gml_dim == dim)
797  {
798  ptarray_append_point(dpa, &pt, LW_FALSE);
799  gml_dim = 0;
800  }
801  else if (*(poslist+1) == '\0')
802  gml_lwerror("invalid GML representation", 28);
803 
804  p = poslist+1;
805  digit = false;
806  }
807  }
808 
809  xmlFree(gmlposlist);
810 
811  return ptarray_clone_deep(dpa);
812 }
813 
814 
827 static POINTARRAY* parse_gml_data(xmlNodePtr xnode, bool *hasz, int *root_srid)
828 {
829  POINTARRAY *pa = 0, *tmp_pa = 0;
830  xmlNodePtr xa, xb;
831  gmlSrs srs;
832  bool found;
833 
834  pa = NULL;
835 
836  for (xa = xnode ; xa != NULL ; xa = xa->next)
837  {
838  if (xa->type != XML_ELEMENT_NODE) continue;
839  if (!is_gml_namespace(xa, false)) continue;
840  if (xa->name == NULL) continue;
841 
842  if (!strcmp((char *) xa->name, "pos"))
843  {
844  tmp_pa = parse_gml_pos(xa, hasz);
845  if (pa == NULL) pa = tmp_pa;
846  else pa = ptarray_merge(pa, tmp_pa);
847 
848  }
849  else if (!strcmp((char *) xa->name, "posList"))
850  {
851  tmp_pa = parse_gml_poslist(xa, hasz);
852  if (pa == NULL) pa = tmp_pa;
853  else pa = ptarray_merge(pa, tmp_pa);
854 
855  }
856  else if (!strcmp((char *) xa->name, "coordinates"))
857  {
858  tmp_pa = parse_gml_coordinates(xa, hasz);
859  if (pa == NULL) pa = tmp_pa;
860  else pa = ptarray_merge(pa, tmp_pa);
861 
862  }
863  else if (!strcmp((char *) xa->name, "coord"))
864  {
865  tmp_pa = parse_gml_coord(xa, hasz);
866  if (pa == NULL) pa = tmp_pa;
867  else pa = ptarray_merge(pa, tmp_pa);
868 
869  }
870  else if (!strcmp((char *) xa->name, "pointRep") ||
871  !strcmp((char *) xa->name, "pointProperty"))
872  {
873 
874  found = false;
875  for (xb = xa->children ; xb != NULL ; xb = xb->next)
876  {
877  if (xb->type != XML_ELEMENT_NODE) continue;
878  if (!is_gml_namespace(xb, false)) continue;
879  if (!strcmp((char *) xb->name, "Point"))
880  {
881  found = true;
882  break;
883  }
884  }
885  if (!found || xb == NULL)
886  gml_lwerror("invalid GML representation", 29);
887 
888  if (is_xlink(xb)) xb = get_xlink_node(xb);
889  if (xb == NULL || xb->children == NULL)
890  gml_lwerror("invalid GML representation", 30);
891 
892  tmp_pa = parse_gml_data(xb->children, hasz, root_srid);
893  if (tmp_pa->npoints != 1)
894  gml_lwerror("invalid GML representation", 31);
895 
896  parse_gml_srs(xb, &srs);
897  if (srs.reverse_axis) tmp_pa = ptarray_flip_coordinates(tmp_pa);
898  if (*root_srid == SRID_UNKNOWN) *root_srid = srs.srid;
899  else if (srs.srid != *root_srid)
900  gml_reproject_pa(tmp_pa, srs.srid, *root_srid);
901  if (pa == NULL) pa = tmp_pa;
902  else pa = ptarray_merge(pa, tmp_pa);
903  }
904  }
905 
906  if (pa == NULL) gml_lwerror("invalid GML representation", 32);
907 
908  return pa;
909 }
910 
911 
915 static LWGEOM* parse_gml_point(xmlNodePtr xnode, bool *hasz, int *root_srid)
916 {
917  gmlSrs srs;
918  LWGEOM *geom;
919  POINTARRAY *pa;
920 
921  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
922 
923  if (xnode->children == NULL)
924  return lwpoint_as_lwgeom(lwpoint_construct_empty(*root_srid, 0, 0));
925 
926  pa = parse_gml_data(xnode->children, hasz, root_srid);
927  if (pa->npoints != 1) gml_lwerror("invalid GML representation", 34);
928 
929  parse_gml_srs(xnode, &srs);
930  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
931  if (!*root_srid)
932  {
933  *root_srid = srs.srid;
934  geom = (LWGEOM *) lwpoint_construct(*root_srid, NULL, pa);
935  }
936  else
937  {
938  if (srs.srid != *root_srid)
939  gml_reproject_pa(pa, srs.srid, *root_srid);
940  geom = (LWGEOM *) lwpoint_construct(SRID_UNKNOWN, NULL, pa);
941  }
942 
943  return geom;
944 }
945 
946 
950 static LWGEOM* parse_gml_line(xmlNodePtr xnode, bool *hasz, int *root_srid)
951 {
952  gmlSrs srs;
953  LWGEOM *geom;
954  POINTARRAY *pa;
955 
956  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
957 
958  if (xnode->children == NULL)
959  return lwline_as_lwgeom(lwline_construct_empty(*root_srid, 0, 0));
960 
961  pa = parse_gml_data(xnode->children, hasz, root_srid);
962  if (pa->npoints < 2) gml_lwerror("invalid GML representation", 36);
963 
964  parse_gml_srs(xnode, &srs);
965  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
966  if (!*root_srid)
967  {
968  *root_srid = srs.srid;
969  geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
970  }
971  else
972  {
973  if (srs.srid != *root_srid)
974  gml_reproject_pa(pa, srs.srid, *root_srid);
975  geom = (LWGEOM *) lwline_construct(SRID_UNKNOWN, NULL, pa);
976  }
977 
978  return geom;
979 }
980 
981 
985 static LWGEOM* parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
986 {
987  xmlNodePtr xa;
988  int lss, last, i;
989  bool found=false;
990  gmlSrs srs;
991  LWGEOM *geom=NULL;
992  POINTARRAY *pa=NULL;
993  POINTARRAY **ppa=NULL;
994  uint32 npoints=0;
995  xmlChar *interpolation=NULL;
996 
997  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
998 
999  /* Looking for gml:segments */
1000  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1001  {
1002  if (xa->type != XML_ELEMENT_NODE) continue;
1003  if (!is_gml_namespace(xa, false)) continue;
1004  if (!strcmp((char *) xa->name, "segments"))
1005  {
1006  found = true;
1007  break;
1008  }
1009  }
1010  if (!found) gml_lwerror("invalid GML representation", 37);
1011 
1012  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1013 
1014  /* Processing each gml:LineStringSegment */
1015  for (xa = xa->children, lss=0; xa != NULL ; xa = xa->next)
1016  {
1017  if (xa->type != XML_ELEMENT_NODE) continue;
1018  if (!is_gml_namespace(xa, false)) continue;
1019  if (strcmp((char *) xa->name, "LineStringSegment")) continue;
1020 
1021  /* GML SF is resticted to linear interpolation */
1022  interpolation = gmlGetProp(xa, (xmlChar *) "interpolation");
1023  if (interpolation != NULL)
1024  {
1025  if (strcmp((char *) interpolation, "linear"))
1026  gml_lwerror("invalid GML representation", 38);
1027  xmlFree(interpolation);
1028  }
1029 
1030  if (lss > 0) ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1031  sizeof(POINTARRAY*) * (lss + 1));
1032 
1033  ppa[lss] = parse_gml_data(xa->children, hasz, root_srid);
1034  npoints += ppa[lss]->npoints;
1035  if (ppa[lss]->npoints < 2)
1036  gml_lwerror("invalid GML representation", 39);
1037  lss++;
1038  }
1039  if (lss == 0) gml_lwerror("invalid GML representation", 40);
1040 
1041  /* Most common case, a single segment */
1042  if (lss == 1) pa = ppa[0];
1043 
1044  /*
1045  * "The curve segments are connected to one another, with the end point
1046  * of each segment except the last being the start point of the next
1047  * segment" from ISO 19107:2003 -> 6.3.16.1 (p43)
1048  *
1049  * So we must aggregate all the segments into a single one and avoid
1050  * to copy the redundants points
1051  */
1052  if (lss > 1)
1053  {
1054  pa = ptarray_construct(1, 0, npoints - (lss - 1));
1055  for (last = npoints = i = 0; i < lss ; i++)
1056  {
1057  if (i + 1 == lss) last = 1;
1058  /* Check if segments are not disjoints */
1059  if (i > 0 && memcmp( getPoint_internal(pa, npoints),
1060  getPoint_internal(ppa[i], 0),
1061  *hasz?sizeof(POINT3D):sizeof(POINT2D)))
1062  gml_lwerror("invalid GML representation", 41);
1063 
1064  /* Aggregate stuff */
1065  memcpy( getPoint_internal(pa, npoints),
1066  getPoint_internal(ppa[i], 0),
1067  ptarray_point_size(ppa[i]) * (ppa[i]->npoints + last));
1068 
1069  npoints += ppa[i]->npoints - 1;
1070  lwfree(ppa[i]);
1071  }
1072  lwfree(ppa);
1073  }
1074 
1075  parse_gml_srs(xnode, &srs);
1076  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1077  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1078  gml_reproject_pa(pa, srs.srid, *root_srid);
1079  geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
1080 
1081  return geom;
1082 }
1083 
1084 
1088 static LWGEOM* parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid)
1089 {
1090  gmlSrs srs;
1091  LWGEOM *geom;
1092  POINTARRAY **ppa = NULL;
1093 
1094  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1095  parse_gml_srs(xnode, &srs);
1096 
1097  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1098  ppa[0] = parse_gml_data(xnode->children, hasz, root_srid);
1099 
1100  if (ppa[0]->npoints < 4
1101  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1102  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1103  gml_lwerror("invalid GML representation", 42);
1104 
1105  if (srs.reverse_axis)
1106  ppa[0] = ptarray_flip_coordinates(ppa[0]);
1107 
1108  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1109  gml_reproject_pa(ppa[0], srs.srid, *root_srid);
1110 
1111  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, 1, ppa);
1112 
1113  return geom;
1114 }
1115 
1116 
1120 static LWGEOM* parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
1121 {
1122  gmlSrs srs;
1123  int i, ring;
1124  LWGEOM *geom;
1125  xmlNodePtr xa, xb;
1126  POINTARRAY **ppa = NULL;
1127 
1128  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1129 
1130  if (xnode->children == NULL)
1131  return lwpoly_as_lwgeom(lwpoly_construct_empty(*root_srid, 0, 0));
1132 
1133  parse_gml_srs(xnode, &srs);
1134 
1135  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1136  {
1137  /* Polygon/outerBoundaryIs -> GML 2.1.2 */
1138  /* Polygon/exterior -> GML 3.1.1 */
1139  if (xa->type != XML_ELEMENT_NODE) continue;
1140  if (!is_gml_namespace(xa, false)) continue;
1141  if (strcmp((char *) xa->name, "outerBoundaryIs") &&
1142  strcmp((char *) xa->name, "exterior")) continue;
1143 
1144  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1145  {
1146  if (xb->type != XML_ELEMENT_NODE) continue;
1147  if (!is_gml_namespace(xb, false)) continue;
1148  if (strcmp((char *) xb->name, "LinearRing")) continue;
1149 
1150  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1151  ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
1152 
1153  if (ppa[0]->npoints < 4
1154  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1155  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1156  gml_lwerror("invalid GML representation", 43);
1157 
1158  if (srs.reverse_axis) ppa[0] = ptarray_flip_coordinates(ppa[0]);
1159  }
1160  }
1161 
1162  /* Found an <exterior> or <outerBoundaryIs> but no rings?!? We're outa here! */
1163  if ( ! ppa )
1164  gml_lwerror("invalid GML representation", 43);
1165 
1166  for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
1167  {
1168  /* Polygon/innerBoundaryIs -> GML 2.1.2 */
1169  /* Polygon/interior -> GML 3.1.1 */
1170  if (xa->type != XML_ELEMENT_NODE) continue;
1171  if (!is_gml_namespace(xa, false)) continue;
1172  if (strcmp((char *) xa->name, "innerBoundaryIs") &&
1173  strcmp((char *) xa->name, "interior")) continue;
1174 
1175  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1176  {
1177  if (xb->type != XML_ELEMENT_NODE) continue;
1178  if (!is_gml_namespace(xb, false)) continue;
1179  if (strcmp((char *) xb->name, "LinearRing")) continue;
1180 
1181  ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1182  sizeof(POINTARRAY*) * (ring + 1));
1183  ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
1184 
1185  if (ppa[ring]->npoints < 4
1186  || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
1187  || (*hasz && !ptarray_is_closed_3d(ppa[ring])))
1188  gml_lwerror("invalid GML representation", 43);
1189 
1190  if (srs.reverse_axis) ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
1191  ring++;
1192  }
1193  }
1194 
1195  /* Exterior Ring is mandatory */
1196  if (ppa == NULL || ppa[0] == NULL) gml_lwerror("invalid GML representation", 44);
1197 
1198  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1199  {
1200  for (i=0 ; i < ring ; i++)
1201  gml_reproject_pa(ppa[i], srs.srid, *root_srid);
1202  }
1203  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
1204 
1205  return geom;
1206 }
1207 
1208 
1212 static LWGEOM* parse_gml_triangle(xmlNodePtr xnode, bool *hasz, int *root_srid)
1213 {
1214  gmlSrs srs;
1215  LWGEOM *geom;
1216  xmlNodePtr xa, xb;
1217  POINTARRAY *pa = NULL;
1218  xmlChar *interpolation=NULL;
1219 
1220  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1221 
1222  if (xnode->children == NULL)
1223  return lwtriangle_as_lwgeom(lwtriangle_construct_empty(*root_srid, 0, 0));
1224 
1225  /* GML SF is resticted to planar interpolation
1226  NOTA: I know Triangle is not part of SF, but
1227  we have to be consistent with other surfaces */
1228  interpolation = gmlGetProp(xnode, (xmlChar *) "interpolation");
1229  if (interpolation != NULL)
1230  {
1231  if (strcmp((char *) interpolation, "planar"))
1232  gml_lwerror("invalid GML representation", 45);
1233  xmlFree(interpolation);
1234  }
1235 
1236  parse_gml_srs(xnode, &srs);
1237 
1238  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1239  {
1240  /* Triangle/exterior */
1241  if (xa->type != XML_ELEMENT_NODE) continue;
1242  if (!is_gml_namespace(xa, false)) continue;
1243  if (strcmp((char *) xa->name, "exterior")) continue;
1244 
1245  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1246  {
1247  /* Triangle/exterior/LinearRing */
1248  if (xb->type != XML_ELEMENT_NODE) continue;
1249  if (!is_gml_namespace(xb, false)) continue;
1250  if (strcmp((char *) xb->name, "LinearRing")) continue;
1251 
1252  pa = (POINTARRAY*) lwalloc(sizeof(POINTARRAY));
1253  pa = parse_gml_data(xb->children, hasz, root_srid);
1254 
1255  if (pa->npoints != 4
1256  || (!*hasz && !ptarray_is_closed_2d(pa))
1257  || (*hasz && !ptarray_is_closed_3d(pa)))
1258  gml_lwerror("invalid GML representation", 46);
1259 
1260  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1261  }
1262  }
1263 
1264  /* Exterior Ring is mandatory */
1265  if (pa == NULL) gml_lwerror("invalid GML representation", 47);
1266 
1267  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1268  gml_reproject_pa(pa, srs.srid, *root_srid);
1269 
1270  geom = (LWGEOM *) lwtriangle_construct(*root_srid, NULL, pa);
1271 
1272  return geom;
1273 }
1274 
1275 
1279 static LWGEOM* parse_gml_patch(xmlNodePtr xnode, bool *hasz, int *root_srid)
1280 {
1281  xmlChar *interpolation=NULL;
1282  POINTARRAY **ppa=NULL;
1283  LWGEOM *geom=NULL;
1284  xmlNodePtr xa, xb;
1285  int i, ring=0;
1286  gmlSrs srs;
1287 
1288  /* PolygonPatch */
1289  if (strcmp((char *) xnode->name, "PolygonPatch"))
1290  gml_lwerror("invalid GML representation", 48);
1291 
1292  /* GML SF is resticted to planar interpolation */
1293  interpolation = gmlGetProp(xnode, (xmlChar *) "interpolation");
1294  if (interpolation != NULL)
1295  {
1296  if (strcmp((char *) interpolation, "planar"))
1297  gml_lwerror("invalid GML representation", 48);
1298  xmlFree(interpolation);
1299  }
1300 
1301  parse_gml_srs(xnode, &srs);
1302 
1303  /* PolygonPatch/exterior */
1304  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1305  {
1306  if (!is_gml_namespace(xa, false)) continue;
1307  if (strcmp((char *) xa->name, "exterior")) continue;
1308 
1309  /* PolygonPatch/exterior/LinearRing */
1310  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1311  {
1312  if (xb->type != XML_ELEMENT_NODE) continue;
1313  if (!is_gml_namespace(xb, false)) continue;
1314  if (strcmp((char *) xb->name, "LinearRing")) continue;
1315 
1316  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1317  ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
1318 
1319  if (ppa[0]->npoints < 4
1320  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1321  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1322  gml_lwerror("invalid GML representation", 48);
1323 
1324  if (srs.reverse_axis)
1325  ppa[0] = ptarray_flip_coordinates(ppa[0]);
1326  }
1327  }
1328 
1329  /* Interior but no Exterior ! */
1330  if ( ! ppa )
1331  gml_lwerror("invalid GML representation", 48);
1332 
1333  /* PolygonPatch/interior */
1334  for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
1335  {
1336  if (xa->type != XML_ELEMENT_NODE) continue;
1337  if (!is_gml_namespace(xa, false)) continue;
1338  if (strcmp((char *) xa->name, "interior")) continue;
1339 
1340  /* PolygonPatch/interior/LinearRing */
1341  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1342  {
1343  if (xb->type != XML_ELEMENT_NODE) continue;
1344  if (strcmp((char *) xb->name, "LinearRing")) continue;
1345 
1346  ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1347  sizeof(POINTARRAY*) * (ring + 1));
1348  ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
1349 
1350  if (ppa[ring]->npoints < 4
1351  || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
1352  || ( *hasz && !ptarray_is_closed_3d(ppa[ring])))
1353  gml_lwerror("invalid GML representation", 49);
1354 
1355  if (srs.reverse_axis)
1356  ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
1357 
1358  ring++;
1359  }
1360  }
1361 
1362  /* Exterior Ring is mandatory */
1363  if (ppa == NULL || ppa[0] == NULL) gml_lwerror("invalid GML representation", 50);
1364 
1365  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1366  {
1367  for (i=0 ; i < ring ; i++)
1368  gml_reproject_pa(ppa[i], srs.srid, *root_srid);
1369  }
1370  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
1371 
1372  return geom;
1373 }
1374 
1375 
1379 static LWGEOM* parse_gml_surface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1380 {
1381  xmlNodePtr xa;
1382  int patch;
1383  LWGEOM *geom=NULL;
1384  bool found=false;
1385 
1386  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1387 
1388  /* Looking for gml:patches */
1389  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1390  {
1391  if (xa->type != XML_ELEMENT_NODE) continue;
1392  if (!is_gml_namespace(xa, false)) continue;
1393  if (!strcmp((char *) xa->name, "patches"))
1394  {
1395  found = true;
1396  break;
1397  }
1398  }
1399  if (!found) gml_lwerror("invalid GML representation", 51);
1400 
1401  /* Processing gml:PolygonPatch */
1402  for (patch=0, xa = xa->children ; xa != NULL ; xa = xa->next)
1403  {
1404  if (xa->type != XML_ELEMENT_NODE) continue;
1405  if (!is_gml_namespace(xa, false)) continue;
1406  if (strcmp((char *) xa->name, "PolygonPatch")) continue;
1407  patch++;
1408 
1409  /* SQL/MM define ST_CurvePolygon as a single patch only,
1410  cf ISO 13249-3:2009 -> 4.2.9 (p27) */
1411  if (patch > 1) gml_lwerror("invalid GML representation", 52);
1412 
1413  geom = parse_gml_patch(xa, hasz, root_srid);
1414  }
1415 
1416  if (!patch) gml_lwerror("invalid GML representation", 53);
1417 
1418  return geom;
1419 }
1420 
1421 
1431 static LWGEOM* parse_gml_tin(xmlNodePtr xnode, bool *hasz, int *root_srid)
1432 {
1433  gmlSrs srs;
1434  xmlNodePtr xa;
1435  LWGEOM *geom=NULL;
1436  bool found=false;
1437 
1438  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1439 
1440  parse_gml_srs(xnode, &srs);
1441  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1442  *root_srid = srs.srid;
1443 
1444  geom = (LWGEOM *)lwcollection_construct_empty(TINTYPE, *root_srid, 1, 0);
1445 
1446  if (xnode->children == NULL)
1447  return geom;
1448 
1449  /* Looking for gml:patches or gml:trianglePatches */
1450  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1451  {
1452  if (xa->type != XML_ELEMENT_NODE) continue;
1453  if (!is_gml_namespace(xa, false)) continue;
1454  if (!strcmp((char *) xa->name, "patches") ||
1455  !strcmp((char *) xa->name, "trianglePatches"))
1456  {
1457  found = true;
1458  break;
1459  }
1460  }
1461  if (!found) return geom; /* empty one */
1462 
1463  /* Processing each gml:Triangle */
1464  for (xa = xa->children ; xa != NULL ; xa = xa->next)
1465  {
1466  if (xa->type != XML_ELEMENT_NODE) continue;
1467  if (!is_gml_namespace(xa, false)) continue;
1468  if (strcmp((char *) xa->name, "Triangle")) continue;
1469 
1470  if (xa->children != NULL)
1471  geom = (LWGEOM*) lwtin_add_lwtriangle((LWTIN *) geom,
1472  (LWTRIANGLE *) parse_gml_triangle(xa, hasz, root_srid));
1473  }
1474 
1475  return geom;
1476 }
1477 
1478 
1482 static LWGEOM* parse_gml_mpoint(xmlNodePtr xnode, bool *hasz, int *root_srid)
1483 {
1484  gmlSrs srs;
1485  xmlNodePtr xa, xb;
1486  LWGEOM *geom = NULL;
1487 
1488  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1489 
1490  parse_gml_srs(xnode, &srs);
1491  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1492  *root_srid = srs.srid;
1493 
1494  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOINTTYPE, *root_srid, 1, 0);
1495 
1496  if (xnode->children == NULL)
1497  return geom;
1498 
1499  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1500  {
1501  /* MultiPoint/pointMember */
1502  if (xa->type != XML_ELEMENT_NODE) continue;
1503  if (!is_gml_namespace(xa, false)) continue;
1504  if (!strcmp((char *) xa->name, "pointMembers"))
1505  {
1506  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1507  {
1508  if (xb != NULL)
1509  geom = (LWGEOM*)lwmpoint_add_lwpoint((LWMPOINT*)geom,
1510  (LWPOINT*)parse_gml(xb, hasz, root_srid));
1511  }
1512  }
1513  else if (!strcmp((char *) xa->name, "pointMember"))
1514  {
1515  if (xa->children != NULL)
1516  geom = (LWGEOM*)lwmpoint_add_lwpoint((LWMPOINT*)geom,
1517  (LWPOINT*)parse_gml(xa->children, hasz, root_srid));
1518  }
1519  }
1520 
1521  return geom;
1522 }
1523 
1524 
1528 static LWGEOM* parse_gml_mline(xmlNodePtr xnode, bool *hasz, int *root_srid)
1529 {
1530  gmlSrs srs;
1531  xmlNodePtr xa;
1532  LWGEOM *geom = NULL;
1533 
1534  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1535 
1536  parse_gml_srs(xnode, &srs);
1537  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1538  *root_srid = srs.srid;
1539 
1540  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
1541 
1542  if (xnode->children == NULL)
1543  return geom;
1544 
1545  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1546  {
1547  /* MultiLineString/lineStringMember */
1548  if (xa->type != XML_ELEMENT_NODE) continue;
1549  if (!is_gml_namespace(xa, false)) continue;
1550  if (strcmp((char *) xa->name, "lineStringMember")) continue;
1551  if (xa->children != NULL)
1552  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1553  (LWLINE*)parse_gml(xa->children, hasz, root_srid));
1554  }
1555 
1556  return geom;
1557 }
1558 
1559 
1563 static LWGEOM* parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
1564 {
1565  gmlSrs srs;
1566  xmlNodePtr xa, xb;
1567  LWGEOM *geom = NULL;
1568 
1569  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1570 
1571  parse_gml_srs(xnode, &srs);
1572  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1573  *root_srid = srs.srid;
1574 
1575  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
1576 
1577  if (xnode->children == NULL)
1578  return geom;
1579 
1580  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1581  {
1582 
1583  /* MultiCurve/curveMember */
1584  if (xa->type != XML_ELEMENT_NODE) continue;
1585  if (!is_gml_namespace(xa, false)) continue;
1586  if (!strcmp((char *) xa->name, "curveMembers"))
1587  {
1588  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1589  {
1590  if (xb != NULL)
1591  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1592  (LWLINE*)parse_gml(xb, hasz, root_srid));
1593  }
1594  }
1595  else if (!strcmp((char *) xa->name, "curveMember"))
1596  {
1597  if (xa->children != NULL)
1598  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1599  (LWLINE*)parse_gml(xa->children, hasz, root_srid));
1600  }
1601  }
1602 
1603  return geom;
1604 }
1605 
1606 
1610 static LWGEOM* parse_gml_mpoly(xmlNodePtr xnode, bool *hasz, int *root_srid)
1611 {
1612  gmlSrs srs;
1613  xmlNodePtr xa;
1614  LWGEOM *geom = NULL;
1615 
1616  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1617 
1618  parse_gml_srs(xnode, &srs);
1619  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1620  *root_srid = srs.srid;
1621 
1622  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
1623 
1624  if (xnode->children == NULL)
1625  return geom;
1626 
1627  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1628  {
1629  /* MultiPolygon/polygonMember */
1630  if (xa->type != XML_ELEMENT_NODE) continue;
1631  if (!is_gml_namespace(xa, false)) continue;
1632  if (strcmp((char *) xa->name, "polygonMember")) continue;
1633  if (xa->children != NULL)
1634  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1635  (LWPOLY*)parse_gml(xa->children, hasz, root_srid));
1636  }
1637 
1638  return geom;
1639 }
1640 
1641 
1645 static LWGEOM* parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1646 {
1647  gmlSrs srs;
1648  xmlNodePtr xa, xb;
1649  LWGEOM *geom = NULL;
1650 
1651  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1652 
1653  parse_gml_srs(xnode, &srs);
1654  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1655  *root_srid = srs.srid;
1656 
1657  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
1658 
1659  if (xnode->children == NULL)
1660  return geom;
1661 
1662  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1663  {
1664  /* MultiSurface/surfaceMember */
1665  if (xa->type != XML_ELEMENT_NODE) continue;
1666  if (!is_gml_namespace(xa, false)) continue;
1667  if (!strcmp((char *) xa->name, "surfaceMembers"))
1668  {
1669  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1670  {
1671  if (xb != NULL)
1672  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1673  (LWPOLY*)parse_gml(xb, hasz, root_srid));
1674  }
1675  }
1676  else if (!strcmp((char *) xa->name, "surfaceMember"))
1677  {
1678  if (xa->children != NULL)
1679  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1680  (LWPOLY*)parse_gml(xa->children, hasz, root_srid));
1681  }
1682  }
1683 
1684  return geom;
1685 }
1686 
1687 
1692 static LWGEOM* parse_gml_psurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1693 {
1694  gmlSrs srs;
1695  xmlNodePtr xa;
1696  bool found = false;
1697  LWGEOM *geom = NULL;
1698 
1699  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1700 
1701  parse_gml_srs(xnode, &srs);
1702  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1703  *root_srid = srs.srid;
1704 
1705  geom = (LWGEOM *)lwcollection_construct_empty(POLYHEDRALSURFACETYPE, *root_srid, 1, 0);
1706 
1707  if (xnode->children == NULL)
1708  return geom;
1709 
1710  /* Looking for gml:polygonPatches */
1711  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1712  {
1713  if (xa->type != XML_ELEMENT_NODE) continue;
1714  if (!is_gml_namespace(xa, false)) continue;
1715  if (!strcmp((char *) xa->name, "polygonPatches"))
1716  {
1717  found = true;
1718  break;
1719  }
1720  }
1721  if (!found) return geom;
1722 
1723  for (xa = xa->children ; xa != NULL ; xa = xa->next)
1724  {
1725  /* PolyhedralSurface/polygonPatches/PolygonPatch */
1726  if (xa->type != XML_ELEMENT_NODE) continue;
1727  if (!is_gml_namespace(xa, false)) continue;
1728  if (strcmp((char *) xa->name, "PolygonPatch")) continue;
1729 
1730  geom = (LWGEOM*)lwpsurface_add_lwpoly((LWPSURFACE*)geom,
1731  (LWPOLY*)parse_gml_patch(xa, hasz, root_srid));
1732  }
1733 
1734  return geom;
1735 }
1736 
1737 
1741 static LWGEOM* parse_gml_coll(xmlNodePtr xnode, bool *hasz, int *root_srid)
1742 {
1743  gmlSrs srs;
1744  xmlNodePtr xa;
1745  LWGEOM *geom = NULL;
1746 
1747  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1748 
1749  parse_gml_srs(xnode, &srs);
1750  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1751  *root_srid = srs.srid;
1752 
1753  geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, *root_srid, 1, 0);
1754 
1755  if (xnode->children == NULL)
1756  return geom;
1757 
1758  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1759  {
1760  if (xa->type != XML_ELEMENT_NODE) continue;
1761  if (!is_gml_namespace(xa, false)) continue;
1762 
1763  /*
1764  * In GML 2.1.2 pointMember, lineStringMember and
1765  * polygonMember are parts of geometryMember
1766  * substitution group
1767  */
1768  if ( !strcmp((char *) xa->name, "pointMember")
1769  || !strcmp((char *) xa->name, "lineStringMember")
1770  || !strcmp((char *) xa->name, "polygonMember")
1771  || !strcmp((char *) xa->name, "geometryMember"))
1772  {
1773  if (xa->children == NULL) break;
1774  geom = (LWGEOM*)lwcollection_add_lwgeom((LWCOLLECTION *)geom,
1775  parse_gml(xa->children, hasz, root_srid));
1776  }
1777  }
1778 
1779  return geom;
1780 }
1781 
1785 static LWGEOM* lwgeom_from_gml(const char* xml)
1786 {
1787  xmlDocPtr xmldoc;
1788  xmlNodePtr xmlroot=NULL;
1789  int xml_size = strlen(xml);
1790  LWGEOM *lwgeom;
1791  bool hasz=true;
1792  int root_srid=SRID_UNKNOWN;
1793 
1794  /* Begin to Parse XML doc */
1795  xmlInitParser();
1796  xmldoc = xmlReadMemory(xml, xml_size, NULL, NULL, XML_PARSE_SAX1);
1797  if (!xmldoc || (xmlroot = xmlDocGetRootElement(xmldoc)) == NULL)
1798  {
1799  xmlFreeDoc(xmldoc);
1800  xmlCleanupParser();
1801  gml_lwerror("invalid GML representation", 1);
1802  }
1803 
1804  lwgeom = parse_gml(xmlroot, &hasz, &root_srid);
1805 
1806  xmlFreeDoc(xmldoc);
1807  xmlCleanupParser();
1808  /* shouldn't we be releasing xmldoc too here ? */
1809 
1810 
1811  if ( root_srid != SRID_UNKNOWN )
1812  lwgeom->srid = root_srid;
1813 
1814  /* Should we really do this here ? */
1815  lwgeom_add_bbox(lwgeom);
1816 
1817  /* GML geometries could be either 2 or 3D and can be nested mixed.
1818  * Missing Z dimension is even tolerated inside some GML coords
1819  *
1820  * So we deal with 3D in all structures allocation, and flag hasz
1821  * to false if we met once a missing Z dimension
1822  * In this case, we force recursive 2D.
1823  */
1824  if (!hasz)
1825  {
1826  LWGEOM *tmp = lwgeom_force_2d(lwgeom);
1827  lwgeom_free(lwgeom);
1828  lwgeom = tmp;
1829  }
1830 
1831  return lwgeom;
1832 }
1833 
1834 
1838 static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid)
1839 {
1840  xmlNodePtr xa = xnode;
1841  gmlSrs srs;
1842 
1843  while (xa != NULL && (xa->type != XML_ELEMENT_NODE
1844  || !is_gml_namespace(xa, false))) xa = xa->next;
1845 
1846  if (xa == NULL) gml_lwerror("invalid GML representation", 55);
1847 
1848  parse_gml_srs(xa, &srs);
1849  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1850  {
1851  *root_srid = srs.srid;
1852  }
1853 
1854  if (!strcmp((char *) xa->name, "Point"))
1855  return parse_gml_point(xa, hasz, root_srid);
1856 
1857  if (!strcmp((char *) xa->name, "LineString"))
1858  return parse_gml_line(xa, hasz, root_srid);
1859 
1860  if (!strcmp((char *) xa->name, "Curve"))
1861  return parse_gml_curve(xa, hasz, root_srid);
1862 
1863  if (!strcmp((char *) xa->name, "LinearRing"))
1864  return parse_gml_linearring(xa, hasz, root_srid);
1865 
1866  if (!strcmp((char *) xa->name, "Polygon"))
1867  return parse_gml_polygon(xa, hasz, root_srid);
1868 
1869  if (!strcmp((char *) xa->name, "Triangle"))
1870  return parse_gml_triangle(xa, hasz, root_srid);
1871 
1872  if (!strcmp((char *) xa->name, "Surface"))
1873  return parse_gml_surface(xa, hasz, root_srid);
1874 
1875  if (!strcmp((char *) xa->name, "MultiPoint"))
1876  return parse_gml_mpoint(xa, hasz, root_srid);
1877 
1878  if (!strcmp((char *) xa->name, "MultiLineString"))
1879  return parse_gml_mline(xa, hasz, root_srid);
1880 
1881  if (!strcmp((char *) xa->name, "MultiCurve"))
1882  return parse_gml_mcurve(xa, hasz, root_srid);
1883 
1884  if (!strcmp((char *) xa->name, "MultiPolygon"))
1885  return parse_gml_mpoly(xa, hasz, root_srid);
1886 
1887  if (!strcmp((char *) xa->name, "MultiSurface"))
1888  return parse_gml_msurface(xa, hasz, root_srid);
1889 
1890  if (!strcmp((char *) xa->name, "PolyhedralSurface"))
1891  return parse_gml_psurface(xa, hasz, root_srid);
1892 
1893  if ((!strcmp((char *) xa->name, "Tin")) ||
1894  !strcmp((char *) xa->name, "TriangulatedSurface" ))
1895  return parse_gml_tin(xa, hasz, root_srid);
1896 
1897  if (!strcmp((char *) xa->name, "MultiGeometry"))
1898  return parse_gml_coll(xa, hasz, root_srid);
1899 
1900  gml_lwerror("invalid GML representation", 56);
1901  return NULL; /* Never reach */
1902 }
void ptarray_set_point4d(POINTARRAY *pa, int n, const POINT4D *p4d)
Definition: lwgeom_api.c:501
double x
Definition: liblwgeom.h:308
static LWGEOM * parse_gml_triangle(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Triangle (3.1.1)
static LWGEOM * parse_gml_mpoly(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiPolygon (2.1.2, 3.1.1)
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:49
LWTIN * lwtin_add_lwtriangle(LWTIN *mobj, const LWTRIANGLE *obj)
Definition: lwtin.c:21
LWLINE * lwline_construct_empty(int srid, char hasz, char hasm)
Definition: lwline.c:51
void lwfree(void *mem)
Definition: lwutil.c:190
LWTRIANGLE * lwtriangle_construct_empty(int srid, char hasz, char hasm)
Definition: lwtriangle.c:45
static POINTARRAY * parse_gml_poslist(xmlNodePtr xnode, bool *hasz)
Parse gml:posList.
static LWGEOM * parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML LinearRing (3.1.1)
int npoints
Definition: liblwgeom.h:327
static void parse_gml_srs(xmlNodePtr xnode, gmlSrs *srs)
Parse gml srsName attribute.
int ptarray_is_closed_3d(const POINTARRAY *pa)
Definition: ptarray.c:678
LWPSURFACE * lwpsurface_add_lwpoly(LWPSURFACE *mobj, const LWPOLY *obj)
Definition: lwpsurface.c:20
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_patch(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML PolygonPatch (3.1.1)
#define GML32_NS
Definition: lwgeom_in_gml.c:64
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:57
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1006
static xmlChar * gmlGetProp(xmlNodePtr xnode, xmlChar *prop)
Retrieve a GML propertie from a node or NULL otherwise Respect namespaces if presents in the node ele...
#define MULTIPOINTTYPE
Definition: liblwgeom.h:63
static POINTARRAY * parse_gml_coordinates(xmlNodePtr xnode, bool *hasz)
Parse gml:coordinates.
static int gml_is_srid_planar(int srid)
Return 1 if given srid is planar (0 otherwise, i.e geocentric srid) Return -1 if srid is not in spati...
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:72
static LWGEOM * parse_gml_tin(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Tin (and TriangulatedSurface) (3.1.1)
static LWGEOM * parse_gml_coll(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiGeometry (2.1.2, 3.1.1)
static double parse_gml_double(char *d, bool space_before, bool space_after)
Parse a string supposed to be a double.
static LWGEOM * parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML.
LWMLINE * lwmline_add_lwline(LWMLINE *mobj, const LWLINE *obj)
Definition: lwmline.c:33
LWPOINT * lwpoint_construct_empty(int srid, char hasz, char hasm)
Definition: lwpoint.c:118
int ptarray_is_closed_2d(const POINTARRAY *pa)
Definition: ptarray.c:672
char ** result
Definition: liblwgeom.h:218
Datum geom_from_gml(PG_FUNCTION_ARGS)
Definition: lwgeom_in_gml.c:84
int32_t srid
Definition: liblwgeom.h:355
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:239
static POINTARRAY * parse_gml_coord(xmlNodePtr xnode, bool *hasz)
Parse gml:coord.
static POINTARRAY * gml_reproject_pa(POINTARRAY *pa, int srid_in, int srid_out)
Use Proj4 to reproject a given POINTARRAY.
POINTARRAY * ptarray_flip_coordinates(POINTARRAY *pa)
Reverse X and Y axis on a given POINTARRAY.
Definition: ptarray.c:354
static xmlNodePtr get_xlink_node(xmlNodePtr xnode)
Return a xmlNodePtr on a node referenced by a XLink or NULL otherwise.
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:67
#define XLINK_NS
Definition: lwgeom_in_gml.c:62
unsigned int uint32
Definition: shpopen.c:274
static LWGEOM * parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiCurve (3.1.1)
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:249
static LWGEOM * parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiSurface (3.1.1)
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_TRUE, then a duplicate point will not be added.
Definition: ptarray.c:141
projPJ lwproj_from_string(const char *txt)
Get a projection from a string representation.
#define LW_FALSE
Definition: liblwgeom.h:52
LWPOLY * lwpoly_construct(int srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition: lwpoly.c:29
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:51
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:29
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:154
#define TINTYPE
Definition: liblwgeom.h:74
struct struct_gmlSrs gmlSrs
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:646
uint8_t * getPoint_internal(const POINTARRAY *pa, int n)
Definition: ptarray.c:1645
PG_FUNCTION_INFO_V1(geom_from_gml)
Ability to parse GML geometry fragment and to return an LWGEOM or an error message.
char * text2cstring(const text *textptr)
int ptarray_point_size(const POINTARRAY *pa)
Definition: ptarray.c:41
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
Definition: ptarray.c:619
static POINTARRAY * parse_gml_pos(xmlNodePtr xnode, bool *hasz)
Parse gml:pos.
static LWGEOM * parse_gml_mpoint(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse gml:MultiPoint (2.1.2, 3.1.1)
LWGEOM * lwtriangle_as_lwgeom(const LWTRIANGLE *obj)
Definition: lwgeom.c:244
#define GML_NS
Definition: lwgeom_in_gml.c:63
static bool is_xlink(xmlNodePtr node)
Return true if current node contains a simple XLink Return false otherwise.
double z
Definition: liblwgeom.h:308
tuple x
Definition: pixval.py:53
LWTRIANGLE * lwtriangle_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwtriangle.c:27
int point4d_transform(POINT4D *pt, projPJ srcpj, projPJ dstpj)
static POINTARRAY * parse_gml_data(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse data coordinates.
static LWGEOM * parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Curve (3.1.1)
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:65
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
LWMPOINT * lwmpoint_add_lwpoint(LWMPOINT *mobj, const LWPOINT *obj)
Definition: lwmpoint.c:32
static bool is_gml_namespace(xmlNodePtr xnode, bool is_strict)
Return false if current element namespace is not a GML one Return true otherwise. ...
void * lwrealloc(void *mem, size_t size)
Definition: lwutil.c:183
LWPOLY * lwpoly_construct_empty(int srid, char hasz, char hasm)
Definition: lwpoly.c:66
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:555
static void gml_lwerror(char *msg, int error_code)
Definition: lwgeom_in_gml.c:68
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:254
static LWGEOM * parse_gml_surface(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Surface (3.1.1)
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.
LWPOINT * lwpoint_construct(int srid, GBOX *bbox, POINTARRAY *point)
Definition: lwpoint.c:96
void * lwalloc(size_t size)
Definition: lwutil.c:175
static LWGEOM * parse_gml_mline(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse gml:MultiLineString (2.1.2, 3.1.1)
double y
Definition: liblwgeom.h:308
#define MULTILINETYPE
Definition: liblwgeom.h:64
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:81
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:174
LWMPOLY * lwmpoly_add_lwpoly(LWMPOLY *mobj, const LWPOLY *obj)
Definition: lwmpoly.c:34
static LWGEOM * parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Polygon (2.1.2, 3.1.1)
static LWGEOM * lwgeom_from_gml(const char *wkt)
Read GML.
tuple y
Definition: pixval.py:54
static LWGEOM * parse_gml_line(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML lineString (2.1.2, 3.1.1)
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)
Definition: lwgeom_api.c:217
#define COLLECTIONTYPE
Definition: liblwgeom.h:66
This library is the generic geometry handling section of PostGIS.
POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2)
Merge two given POINTARRAY and returns a pointer on the new aggregate one.
Definition: ptarray.c:588