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