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