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