PostGIS  2.4.9dev-r@@SVN_REVISION@@
lwgeom_in_gml.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright 2009 - 2010 Oslandia
22  *
23  **********************************************************************/
24 
25 
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  x = y = z = false;
685 
686  return dpa; /* ptarray_clone_deep(dpa); */
687 }
688 
689 
693 static POINTARRAY* parse_gml_pos(xmlNodePtr xnode, bool *hasz)
694 {
695  xmlChar *dimension, *gmlpos;
696  int dim, gml_dim;
697  POINTARRAY *dpa;
698  char *pos, *p;
699  bool digit;
700  POINT4D pt;
701 
702  /* HasZ, !HasM, 1 Point */
703  dpa = ptarray_construct_empty(1, 0, 1);
704 
705  dimension = gmlGetProp(xnode, (xmlChar *) "srsDimension");
706  if (dimension == NULL) /* in GML 3.0.0 it was dimension */
707  dimension = gmlGetProp(xnode, (xmlChar *) "dimension");
708  if (dimension == NULL) dim = 2; /* We assume that we are in 2D */
709  else
710  {
711  dim = atoi((char *) dimension);
712  xmlFree(dimension);
713  if (dim < 2 || dim > 3)
714  gml_lwpgerror("invalid GML representation", 25);
715  }
716  if (dim == 2) *hasz = false;
717 
718  /* We retrieve gml:pos string */
719  gmlpos = xmlNodeGetContent(xnode);
720  pos = (char *) gmlpos;
721  while (isspace(*pos)) pos++; /* Eat extra whitespaces if any */
722 
723  /* gml:pos pattern: x1 y1
724  * x1 y1 z1
725  */
726  for (p=pos, gml_dim=0, digit=false ; *pos ; pos++)
727  {
728  if (isdigit(*pos)) digit = true;
729  if (digit && (*pos == ' ' || *(pos+1) == '\0'))
730  {
731  if (*pos == ' ') *pos = '\0';
732  gml_dim++;
733  if (gml_dim == 1)
734  pt.x = parse_gml_double(p, true, true);
735  else if (gml_dim == 2)
736  pt.y = parse_gml_double(p, true, true);
737  else if (gml_dim == 3)
738  pt.z = parse_gml_double(p, true, true);
739 
740  p = pos+1;
741  digit = false;
742  }
743  }
744  xmlFree(gmlpos);
745 
746  /* Test again coherent dimensions on each coord */
747  if (gml_dim == 2) *hasz = false;
748  if (gml_dim < 2 || gml_dim > 3 || gml_dim != dim)
749  gml_lwpgerror("invalid GML representation", 26);
750 
751  ptarray_append_point(dpa, &pt, LW_FALSE);
752 
753  return dpa; /* ptarray_clone_deep(dpa); */
754 }
755 
756 
760 static POINTARRAY* parse_gml_poslist(xmlNodePtr xnode, bool *hasz)
761 {
762  xmlChar *dimension, *gmlposlist;
763  char *poslist, *p;
764  int dim, gml_dim;
765  POINTARRAY *dpa;
766  POINT4D pt;
767  bool digit;
768 
769  /* Retrieve gml:srsDimension attribute if any */
770  dimension = gmlGetProp(xnode, (xmlChar *) "srsDimension");
771  if (dimension == NULL) /* in GML 3.0.0 it was dimension */
772  dimension = gmlGetProp(xnode, (xmlChar *) "dimension");
773  if (dimension == NULL) dim = 2; /* We assume that we are in common 2D */
774  else
775  {
776  dim = atoi((char *) dimension);
777  xmlFree(dimension);
778  if (dim < 2 || dim > 3) gml_lwpgerror("invalid GML representation", 27);
779  }
780  if (dim == 2) *hasz = false;
781 
782  /* Retrieve gml:posList string */
783  gmlposlist = xmlNodeGetContent(xnode);
784  poslist = (char *) gmlposlist;
785 
786  /* HasZ?, !HasM, 1 point */
787  dpa = ptarray_construct_empty(1, 0, 1);
788 
789  /* gml:posList pattern: x1 y1 x2 y2
790  * x1 y1 z1 x2 y2 z2
791  */
792  while (isspace(*poslist)) poslist++; /* Eat extra whitespaces if any */
793  for (p=poslist, gml_dim=0, digit=false ; *poslist ; poslist++)
794  {
795  if (isdigit(*poslist)) digit = true;
796  if (digit && (*poslist == ' ' || *(poslist+1) == '\0'))
797  {
798  if (*poslist == ' ') *poslist = '\0';
799 
800  gml_dim++;
801  if (gml_dim == 1) pt.x = parse_gml_double(p, true, true);
802  else if (gml_dim == 2) pt.y = parse_gml_double(p, true, true);
803  else if (gml_dim == 3) pt.z = parse_gml_double(p, true, true);
804 
805  if (gml_dim == dim)
806  {
807  ptarray_append_point(dpa, &pt, LW_FALSE);
808  gml_dim = 0;
809  }
810  else if (*(poslist+1) == '\0')
811  gml_lwpgerror("invalid GML representation", 28);
812 
813  p = poslist+1;
814  digit = false;
815  }
816  }
817 
818  xmlFree(gmlposlist);
819 
820  return dpa; /* ptarray_clone_deep(dpa); */
821 }
822 
823 
836 static POINTARRAY* parse_gml_data(xmlNodePtr xnode, bool *hasz, int *root_srid)
837 {
838  POINTARRAY *pa = 0, *tmp_pa = 0;
839  xmlNodePtr xa, xb;
840  gmlSrs srs;
841  bool found;
842 
843  pa = NULL;
844 
845  for (xa = xnode ; xa != NULL ; xa = xa->next)
846  {
847  if (xa->type != XML_ELEMENT_NODE) continue;
848  if (!is_gml_namespace(xa, false)) continue;
849  if (xa->name == NULL) continue;
850 
851  if (!strcmp((char *) xa->name, "pos"))
852  {
853  tmp_pa = parse_gml_pos(xa, hasz);
854  if (pa == NULL) pa = tmp_pa;
855  else pa = ptarray_merge(pa, tmp_pa);
856 
857  }
858  else if (!strcmp((char *) xa->name, "posList"))
859  {
860  tmp_pa = parse_gml_poslist(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, "coordinates"))
866  {
867  tmp_pa = parse_gml_coordinates(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, "coord"))
873  {
874  tmp_pa = parse_gml_coord(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, "pointRep") ||
880  !strcmp((char *) xa->name, "pointProperty"))
881  {
882 
883  found = false;
884  for (xb = xa->children ; xb != NULL ; xb = xb->next)
885  {
886  if (xb->type != XML_ELEMENT_NODE) continue;
887  if (!is_gml_namespace(xb, false)) continue;
888  if (!strcmp((char *) xb->name, "Point"))
889  {
890  found = true;
891  break;
892  }
893  }
894  if (!found || xb == NULL)
895  gml_lwpgerror("invalid GML representation", 29);
896 
897  if (is_xlink(xb)) xb = get_xlink_node(xb);
898  if (xb == NULL || xb->children == NULL)
899  gml_lwpgerror("invalid GML representation", 30);
900 
901  tmp_pa = parse_gml_data(xb->children, hasz, root_srid);
902  if (tmp_pa->npoints != 1)
903  gml_lwpgerror("invalid GML representation", 31);
904 
905  parse_gml_srs(xb, &srs);
906  if (srs.reverse_axis) tmp_pa = ptarray_flip_coordinates(tmp_pa);
907  if (*root_srid == SRID_UNKNOWN) *root_srid = srs.srid;
908  else if (srs.srid != *root_srid)
909  gml_reproject_pa(tmp_pa, srs.srid, *root_srid);
910  if (pa == NULL) pa = tmp_pa;
911  else pa = ptarray_merge(pa, tmp_pa);
912  }
913  }
914 
915  if (pa == NULL) gml_lwpgerror("invalid GML representation", 32);
916 
917  return pa;
918 }
919 
920 
924 static LWGEOM* parse_gml_point(xmlNodePtr xnode, bool *hasz, int *root_srid)
925 {
926  gmlSrs srs;
927  LWGEOM *geom;
928  POINTARRAY *pa;
929 
930  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
931 
932  if (xnode->children == NULL)
933  return lwpoint_as_lwgeom(lwpoint_construct_empty(*root_srid, 0, 0));
934 
935  pa = parse_gml_data(xnode->children, hasz, root_srid);
936  if (pa->npoints != 1) gml_lwpgerror("invalid GML representation", 34);
937 
938  parse_gml_srs(xnode, &srs);
939  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
940  if (!*root_srid)
941  {
942  *root_srid = srs.srid;
943  geom = (LWGEOM *) lwpoint_construct(*root_srid, NULL, pa);
944  }
945  else
946  {
947  if (srs.srid != *root_srid)
948  gml_reproject_pa(pa, srs.srid, *root_srid);
949  geom = (LWGEOM *) lwpoint_construct(SRID_UNKNOWN, NULL, pa);
950  }
951 
952  return geom;
953 }
954 
955 
959 static LWGEOM* parse_gml_line(xmlNodePtr xnode, bool *hasz, int *root_srid)
960 {
961  gmlSrs srs;
962  LWGEOM *geom;
963  POINTARRAY *pa;
964 
965  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
966 
967  if (xnode->children == NULL)
968  return lwline_as_lwgeom(lwline_construct_empty(*root_srid, 0, 0));
969 
970  pa = parse_gml_data(xnode->children, hasz, root_srid);
971  if (pa->npoints < 2) gml_lwpgerror("invalid GML representation", 36);
972 
973  parse_gml_srs(xnode, &srs);
974  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
975  if (!*root_srid)
976  {
977  *root_srid = srs.srid;
978  geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
979  }
980  else
981  {
982  if (srs.srid != *root_srid)
983  gml_reproject_pa(pa, srs.srid, *root_srid);
984  geom = (LWGEOM *) lwline_construct(SRID_UNKNOWN, NULL, pa);
985  }
986 
987  return geom;
988 }
989 
990 
994 static LWGEOM* parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
995 {
996  xmlNodePtr xa;
997  int lss, last, i;
998  bool found=false;
999  gmlSrs srs;
1000  LWGEOM *geom=NULL;
1001  POINTARRAY *pa=NULL;
1002  POINTARRAY **ppa=NULL;
1003  uint32 npoints=0;
1004  xmlChar *interpolation=NULL;
1005 
1006  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1007 
1008  /* Looking for gml:segments */
1009  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1010  {
1011  if (xa->type != XML_ELEMENT_NODE) continue;
1012  if (!is_gml_namespace(xa, false)) continue;
1013  if (!strcmp((char *) xa->name, "segments"))
1014  {
1015  found = true;
1016  break;
1017  }
1018  }
1019  if (!found) gml_lwpgerror("invalid GML representation", 37);
1020 
1021  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1022 
1023  /* Processing each gml:LineStringSegment */
1024  for (xa = xa->children, lss=0; xa != NULL ; xa = xa->next)
1025  {
1026  if (xa->type != XML_ELEMENT_NODE) continue;
1027  if (!is_gml_namespace(xa, false)) continue;
1028  if (strcmp((char *) xa->name, "LineStringSegment")) continue;
1029 
1030  /* GML SF is resticted to linear interpolation */
1031  interpolation = gmlGetProp(xa, (xmlChar *) "interpolation");
1032  if (interpolation != NULL)
1033  {
1034  if (strcmp((char *) interpolation, "linear"))
1035  gml_lwpgerror("invalid GML representation", 38);
1036  xmlFree(interpolation);
1037  }
1038 
1039  if (lss > 0) ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1040  sizeof(POINTARRAY*) * (lss + 1));
1041 
1042  ppa[lss] = parse_gml_data(xa->children, hasz, root_srid);
1043  npoints += ppa[lss]->npoints;
1044  if (ppa[lss]->npoints < 2)
1045  gml_lwpgerror("invalid GML representation", 39);
1046  lss++;
1047  }
1048  if (lss == 0) gml_lwpgerror("invalid GML representation", 40);
1049 
1050  /* Most common case, a single segment */
1051  if (lss == 1) pa = ppa[0];
1052 
1053  /*
1054  * "The curve segments are connected to one another, with the end point
1055  * of each segment except the last being the start point of the next
1056  * segment" from ISO 19107:2003 -> 6.3.16.1 (p43)
1057  *
1058  * So we must aggregate all the segments into a single one and avoid
1059  * to copy the redundants points
1060  */
1061  if (lss > 1)
1062  {
1063  pa = ptarray_construct(1, 0, npoints - (lss - 1));
1064  for (last = npoints = i = 0; i < lss ; i++)
1065  {
1066  if (i + 1 == lss) last = 1;
1067  /* Check if segments are not disjoints */
1068  if (i > 0 && memcmp( getPoint_internal(pa, npoints),
1069  getPoint_internal(ppa[i], 0),
1070  *hasz ? sizeof(POINT3D) : sizeof(POINT2D)))
1071  gml_lwpgerror("invalid GML representation", 41);
1072 
1073  /* Aggregate stuff */
1074  memcpy( getPoint_internal(pa, npoints),
1075  getPoint_internal(ppa[i], 0),
1076  ptarray_point_size(ppa[i]) * (ppa[i]->npoints + last));
1077 
1078  npoints += ppa[i]->npoints - 1;
1079  lwfree(ppa[i]);
1080  }
1081  lwfree(ppa);
1082  }
1083 
1084  parse_gml_srs(xnode, &srs);
1085  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1086  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1087  gml_reproject_pa(pa, srs.srid, *root_srid);
1088  geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
1089 
1090  return geom;
1091 }
1092 
1093 
1097 static LWGEOM* parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid)
1098 {
1099  gmlSrs srs;
1100  LWGEOM *geom;
1101  POINTARRAY **ppa = NULL;
1102 
1103  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1104  parse_gml_srs(xnode, &srs);
1105 
1106  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1107  ppa[0] = parse_gml_data(xnode->children, hasz, root_srid);
1108 
1109  if (ppa[0]->npoints < 4
1110  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1111  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1112  gml_lwpgerror("invalid GML representation", 42);
1113 
1114  if (srs.reverse_axis)
1115  ppa[0] = ptarray_flip_coordinates(ppa[0]);
1116 
1117  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1118  gml_reproject_pa(ppa[0], srs.srid, *root_srid);
1119 
1120  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, 1, ppa);
1121 
1122  return geom;
1123 }
1124 
1125 
1129 static LWGEOM* parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
1130 {
1131  gmlSrs srs;
1132  int i, ring;
1133  LWGEOM *geom;
1134  xmlNodePtr xa, xb;
1135  POINTARRAY **ppa = NULL;
1136 
1137  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1138 
1139  if (xnode->children == NULL)
1140  return lwpoly_as_lwgeom(lwpoly_construct_empty(*root_srid, 0, 0));
1141 
1142  parse_gml_srs(xnode, &srs);
1143 
1144  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1145  {
1146  /* Polygon/outerBoundaryIs -> GML 2.1.2 */
1147  /* Polygon/exterior -> GML 3.1.1 */
1148  if (xa->type != XML_ELEMENT_NODE) continue;
1149  if (!is_gml_namespace(xa, false)) continue;
1150  if (strcmp((char *) xa->name, "outerBoundaryIs") &&
1151  strcmp((char *) xa->name, "exterior")) continue;
1152 
1153  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1154  {
1155  if (xb->type != XML_ELEMENT_NODE) continue;
1156  if (!is_gml_namespace(xb, false)) continue;
1157  if (strcmp((char *) xb->name, "LinearRing")) continue;
1158 
1159  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1160  ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
1161 
1162  if (ppa[0]->npoints < 4
1163  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1164  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1165  gml_lwpgerror("invalid GML representation", 43);
1166 
1167  if (srs.reverse_axis) ppa[0] = ptarray_flip_coordinates(ppa[0]);
1168  }
1169  }
1170 
1171  /* Found an <exterior> or <outerBoundaryIs> but no rings?!? We're outa here! */
1172  if ( ! ppa )
1173  gml_lwpgerror("invalid GML representation", 43);
1174 
1175  for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
1176  {
1177  /* Polygon/innerBoundaryIs -> GML 2.1.2 */
1178  /* Polygon/interior -> GML 3.1.1 */
1179  if (xa->type != XML_ELEMENT_NODE) continue;
1180  if (!is_gml_namespace(xa, false)) continue;
1181  if (strcmp((char *) xa->name, "innerBoundaryIs") &&
1182  strcmp((char *) xa->name, "interior")) continue;
1183 
1184  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1185  {
1186  if (xb->type != XML_ELEMENT_NODE) continue;
1187  if (!is_gml_namespace(xb, false)) continue;
1188  if (strcmp((char *) xb->name, "LinearRing")) continue;
1189 
1190  ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1191  sizeof(POINTARRAY*) * (ring + 1));
1192  ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
1193 
1194  if (ppa[ring]->npoints < 4
1195  || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
1196  || (*hasz && !ptarray_is_closed_3d(ppa[ring])))
1197  gml_lwpgerror("invalid GML representation", 43);
1198 
1199  if (srs.reverse_axis) ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
1200  ring++;
1201  }
1202  }
1203 
1204  /* Exterior Ring is mandatory */
1205  if (ppa == NULL || ppa[0] == NULL) gml_lwpgerror("invalid GML representation", 44);
1206 
1207  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1208  {
1209  for (i=0 ; i < ring ; i++)
1210  gml_reproject_pa(ppa[i], srs.srid, *root_srid);
1211  }
1212  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
1213 
1214  return geom;
1215 }
1216 
1217 
1221 static LWGEOM* parse_gml_triangle(xmlNodePtr xnode, bool *hasz, int *root_srid)
1222 {
1223  gmlSrs srs;
1224  LWGEOM *geom;
1225  xmlNodePtr xa, xb;
1226  POINTARRAY *pa = NULL;
1227  xmlChar *interpolation=NULL;
1228 
1229  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1230 
1231  if (xnode->children == NULL)
1232  return lwtriangle_as_lwgeom(lwtriangle_construct_empty(*root_srid, 0, 0));
1233 
1234  /* GML SF is resticted to planar interpolation
1235  NOTA: I know Triangle is not part of SF, but
1236  we have to be consistent with other surfaces */
1237  interpolation = gmlGetProp(xnode, (xmlChar *) "interpolation");
1238  if (interpolation != NULL)
1239  {
1240  if (strcmp((char *) interpolation, "planar"))
1241  gml_lwpgerror("invalid GML representation", 45);
1242  xmlFree(interpolation);
1243  }
1244 
1245  parse_gml_srs(xnode, &srs);
1246 
1247  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1248  {
1249  /* Triangle/exterior */
1250  if (xa->type != XML_ELEMENT_NODE) continue;
1251  if (!is_gml_namespace(xa, false)) continue;
1252  if (strcmp((char *) xa->name, "exterior")) continue;
1253 
1254  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1255  {
1256  /* Triangle/exterior/LinearRing */
1257  if (xb->type != XML_ELEMENT_NODE) continue;
1258  if (!is_gml_namespace(xb, false)) continue;
1259  if (strcmp((char *) xb->name, "LinearRing")) continue;
1260 
1261  pa = (POINTARRAY*) lwalloc(sizeof(POINTARRAY));
1262  pa = parse_gml_data(xb->children, hasz, root_srid);
1263 
1264  if (pa->npoints != 4
1265  || (!*hasz && !ptarray_is_closed_2d(pa))
1266  || (*hasz && !ptarray_is_closed_3d(pa)))
1267  gml_lwpgerror("invalid GML representation", 46);
1268 
1269  if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
1270  }
1271  }
1272 
1273  /* Exterior Ring is mandatory */
1274  if (pa == NULL) gml_lwpgerror("invalid GML representation", 47);
1275 
1276  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1277  gml_reproject_pa(pa, srs.srid, *root_srid);
1278 
1279  geom = (LWGEOM *) lwtriangle_construct(*root_srid, NULL, pa);
1280 
1281  return geom;
1282 }
1283 
1284 
1288 static LWGEOM* parse_gml_patch(xmlNodePtr xnode, bool *hasz, int *root_srid)
1289 {
1290  xmlChar *interpolation=NULL;
1291  POINTARRAY **ppa=NULL;
1292  LWGEOM *geom=NULL;
1293  xmlNodePtr xa, xb;
1294  int i, ring=0;
1295  gmlSrs srs;
1296 
1297  /* PolygonPatch */
1298  if (strcmp((char *) xnode->name, "PolygonPatch"))
1299  gml_lwpgerror("invalid GML representation", 48);
1300 
1301  /* GML SF is resticted to planar interpolation */
1302  interpolation = gmlGetProp(xnode, (xmlChar *) "interpolation");
1303  if (interpolation != NULL)
1304  {
1305  if (strcmp((char *) interpolation, "planar"))
1306  gml_lwpgerror("invalid GML representation", 48);
1307  xmlFree(interpolation);
1308  }
1309 
1310  parse_gml_srs(xnode, &srs);
1311 
1312  /* PolygonPatch/exterior */
1313  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1314  {
1315  if (!is_gml_namespace(xa, false)) continue;
1316  if (strcmp((char *) xa->name, "exterior")) continue;
1317 
1318  /* PolygonPatch/exterior/LinearRing */
1319  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1320  {
1321  if (xb->type != XML_ELEMENT_NODE) continue;
1322  if (!is_gml_namespace(xb, false)) continue;
1323  if (strcmp((char *) xb->name, "LinearRing")) continue;
1324 
1325  ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
1326  ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
1327 
1328  if (ppa[0]->npoints < 4
1329  || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
1330  || (*hasz && !ptarray_is_closed_3d(ppa[0])))
1331  gml_lwpgerror("invalid GML representation", 48);
1332 
1333  if (srs.reverse_axis)
1334  ppa[0] = ptarray_flip_coordinates(ppa[0]);
1335  }
1336  }
1337 
1338  /* Interior but no Exterior ! */
1339  if ( ! ppa )
1340  gml_lwpgerror("invalid GML representation", 48);
1341 
1342  /* PolygonPatch/interior */
1343  for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
1344  {
1345  if (xa->type != XML_ELEMENT_NODE) continue;
1346  if (!is_gml_namespace(xa, false)) continue;
1347  if (strcmp((char *) xa->name, "interior")) continue;
1348 
1349  /* PolygonPatch/interior/LinearRing */
1350  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1351  {
1352  if (xb->type != XML_ELEMENT_NODE) continue;
1353  if (strcmp((char *) xb->name, "LinearRing")) continue;
1354 
1355  ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
1356  sizeof(POINTARRAY*) * (ring + 1));
1357  ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
1358 
1359  if (ppa[ring]->npoints < 4
1360  || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
1361  || ( *hasz && !ptarray_is_closed_3d(ppa[ring])))
1362  gml_lwpgerror("invalid GML representation", 49);
1363 
1364  if (srs.reverse_axis)
1365  ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
1366 
1367  ring++;
1368  }
1369  }
1370 
1371  /* Exterior Ring is mandatory */
1372  if (ppa == NULL || ppa[0] == NULL) gml_lwpgerror("invalid GML representation", 50);
1373 
1374  if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
1375  {
1376  for (i=0 ; i < ring ; i++)
1377  gml_reproject_pa(ppa[i], srs.srid, *root_srid);
1378  }
1379  geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
1380 
1381  return geom;
1382 }
1383 
1384 
1388 static LWGEOM* parse_gml_surface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1389 {
1390  xmlNodePtr xa;
1391  int patch;
1392  LWGEOM *geom=NULL;
1393  bool found=false;
1394 
1395  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1396 
1397  /* Looking for gml:patches */
1398  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1399  {
1400  if (xa->type != XML_ELEMENT_NODE) continue;
1401  if (!is_gml_namespace(xa, false)) continue;
1402  if (!strcmp((char *) xa->name, "patches"))
1403  {
1404  found = true;
1405  break;
1406  }
1407  }
1408  if (!found) gml_lwpgerror("invalid GML representation", 51);
1409 
1410  /* Processing gml:PolygonPatch */
1411  for (patch=0, xa = xa->children ; xa != NULL ; xa = xa->next)
1412  {
1413  if (xa->type != XML_ELEMENT_NODE) continue;
1414  if (!is_gml_namespace(xa, false)) continue;
1415  if (strcmp((char *) xa->name, "PolygonPatch")) continue;
1416  patch++;
1417 
1418  /* SQL/MM define ST_CurvePolygon as a single patch only,
1419  cf ISO 13249-3:2009 -> 4.2.9 (p27) */
1420  if (patch > 1) gml_lwpgerror("invalid GML representation", 52);
1421 
1422  geom = parse_gml_patch(xa, hasz, root_srid);
1423  }
1424 
1425  if (!patch) gml_lwpgerror("invalid GML representation", 53);
1426 
1427  return geom;
1428 }
1429 
1430 
1440 static LWGEOM* parse_gml_tin(xmlNodePtr xnode, bool *hasz, int *root_srid)
1441 {
1442  gmlSrs srs;
1443  xmlNodePtr xa;
1444  LWGEOM *geom=NULL;
1445  bool found=false;
1446 
1447  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1448 
1449  parse_gml_srs(xnode, &srs);
1450  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1451  *root_srid = srs.srid;
1452 
1453  geom = (LWGEOM *)lwcollection_construct_empty(TINTYPE, *root_srid, 1, 0);
1454 
1455  if (xnode->children == NULL)
1456  return geom;
1457 
1458  /* Looking for gml:patches or gml:trianglePatches */
1459  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1460  {
1461  if (xa->type != XML_ELEMENT_NODE) continue;
1462  if (!is_gml_namespace(xa, false)) continue;
1463  if (!strcmp((char *) xa->name, "patches") ||
1464  !strcmp((char *) xa->name, "trianglePatches"))
1465  {
1466  found = true;
1467  break;
1468  }
1469  }
1470  if (!found) return geom; /* empty one */
1471 
1472  /* Processing each gml:Triangle */
1473  for (xa = xa->children ; xa != NULL ; xa = xa->next)
1474  {
1475  if (xa->type != XML_ELEMENT_NODE) continue;
1476  if (!is_gml_namespace(xa, false)) continue;
1477  if (strcmp((char *) xa->name, "Triangle")) continue;
1478 
1479  if (xa->children != NULL)
1480  geom = (LWGEOM*) lwtin_add_lwtriangle((LWTIN *) geom,
1481  (LWTRIANGLE *) parse_gml_triangle(xa, hasz, root_srid));
1482  }
1483 
1484  return geom;
1485 }
1486 
1487 
1491 static LWGEOM* parse_gml_mpoint(xmlNodePtr xnode, bool *hasz, int *root_srid)
1492 {
1493  gmlSrs srs;
1494  xmlNodePtr xa, xb;
1495  LWGEOM *geom = NULL;
1496 
1497  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1498 
1499  parse_gml_srs(xnode, &srs);
1500  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1501  *root_srid = srs.srid;
1502 
1503  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOINTTYPE, *root_srid, 1, 0);
1504 
1505  if (xnode->children == NULL)
1506  return geom;
1507 
1508  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1509  {
1510  /* MultiPoint/pointMember */
1511  if (xa->type != XML_ELEMENT_NODE) continue;
1512  if (!is_gml_namespace(xa, false)) continue;
1513  if (!strcmp((char *) xa->name, "pointMembers"))
1514  {
1515  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1516  {
1517  if (xb != NULL)
1518  geom = (LWGEOM*)lwmpoint_add_lwpoint((LWMPOINT*)geom,
1519  (LWPOINT*)parse_gml(xb, hasz, root_srid));
1520  }
1521  }
1522  else if (!strcmp((char *) xa->name, "pointMember"))
1523  {
1524  if (xa->children != NULL)
1525  geom = (LWGEOM*)lwmpoint_add_lwpoint((LWMPOINT*)geom,
1526  (LWPOINT*)parse_gml(xa->children, hasz, root_srid));
1527  }
1528  }
1529 
1530  return geom;
1531 }
1532 
1533 
1537 static LWGEOM* parse_gml_mline(xmlNodePtr xnode, bool *hasz, int *root_srid)
1538 {
1539  gmlSrs srs;
1540  xmlNodePtr xa;
1541  LWGEOM *geom = NULL;
1542 
1543  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1544 
1545  parse_gml_srs(xnode, &srs);
1546  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1547  *root_srid = srs.srid;
1548 
1549  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
1550 
1551  if (xnode->children == NULL)
1552  return geom;
1553 
1554  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1555  {
1556  /* MultiLineString/lineStringMember */
1557  if (xa->type != XML_ELEMENT_NODE) continue;
1558  if (!is_gml_namespace(xa, false)) continue;
1559  if (strcmp((char *) xa->name, "lineStringMember")) continue;
1560  if (xa->children != NULL)
1561  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1562  (LWLINE*)parse_gml(xa->children, hasz, root_srid));
1563  }
1564 
1565  return geom;
1566 }
1567 
1568 
1572 static LWGEOM* parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
1573 {
1574  gmlSrs srs;
1575  xmlNodePtr xa, xb;
1576  LWGEOM *geom = NULL;
1577 
1578  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1579 
1580  parse_gml_srs(xnode, &srs);
1581  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1582  *root_srid = srs.srid;
1583 
1584  geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
1585 
1586  if (xnode->children == NULL)
1587  return geom;
1588 
1589  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1590  {
1591 
1592  /* MultiCurve/curveMember */
1593  if (xa->type != XML_ELEMENT_NODE) continue;
1594  if (!is_gml_namespace(xa, false)) continue;
1595  if (!strcmp((char *) xa->name, "curveMembers"))
1596  {
1597  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1598  {
1599  if (xb != NULL)
1600  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1601  (LWLINE*)parse_gml(xb, hasz, root_srid));
1602  }
1603  }
1604  else if (!strcmp((char *) xa->name, "curveMember"))
1605  {
1606  if (xa->children != NULL)
1607  geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
1608  (LWLINE*)parse_gml(xa->children, hasz, root_srid));
1609  }
1610  }
1611 
1612  return geom;
1613 }
1614 
1615 
1619 static LWGEOM* parse_gml_mpoly(xmlNodePtr xnode, bool *hasz, int *root_srid)
1620 {
1621  gmlSrs srs;
1622  xmlNodePtr xa;
1623  LWGEOM *geom = NULL;
1624 
1625  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1626 
1627  parse_gml_srs(xnode, &srs);
1628  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1629  *root_srid = srs.srid;
1630 
1631  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
1632 
1633  if (xnode->children == NULL)
1634  return geom;
1635 
1636  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1637  {
1638  /* MultiPolygon/polygonMember */
1639  if (xa->type != XML_ELEMENT_NODE) continue;
1640  if (!is_gml_namespace(xa, false)) continue;
1641  if (strcmp((char *) xa->name, "polygonMember")) continue;
1642  if (xa->children != NULL)
1643  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1644  (LWPOLY*)parse_gml(xa->children, hasz, root_srid));
1645  }
1646 
1647  return geom;
1648 }
1649 
1650 
1654 static LWGEOM* parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1655 {
1656  gmlSrs srs;
1657  xmlNodePtr xa, xb;
1658  LWGEOM *geom = NULL;
1659 
1660  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1661 
1662  parse_gml_srs(xnode, &srs);
1663  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1664  *root_srid = srs.srid;
1665 
1666  geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
1667 
1668  if (xnode->children == NULL)
1669  return geom;
1670 
1671  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1672  {
1673  /* MultiSurface/surfaceMember */
1674  if (xa->type != XML_ELEMENT_NODE) continue;
1675  if (!is_gml_namespace(xa, false)) continue;
1676  if (!strcmp((char *) xa->name, "surfaceMembers"))
1677  {
1678  for (xb = xa->children ; xb != NULL ; xb = xb->next)
1679  {
1680  if (xb != NULL)
1681  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1682  (LWPOLY*)parse_gml(xb, hasz, root_srid));
1683  }
1684  }
1685  else if (!strcmp((char *) xa->name, "surfaceMember"))
1686  {
1687  if (xa->children != NULL)
1688  geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
1689  (LWPOLY*)parse_gml(xa->children, hasz, root_srid));
1690  }
1691  }
1692 
1693  return geom;
1694 }
1695 
1696 
1701 static LWGEOM* parse_gml_psurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
1702 {
1703  gmlSrs srs;
1704  xmlNodePtr xa;
1705  bool found = false;
1706  LWGEOM *geom = NULL;
1707 
1708  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1709 
1710  parse_gml_srs(xnode, &srs);
1711  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1712  *root_srid = srs.srid;
1713 
1714  geom = (LWGEOM *)lwcollection_construct_empty(POLYHEDRALSURFACETYPE, *root_srid, 1, 0);
1715 
1716  if (xnode->children == NULL)
1717  return geom;
1718 
1719  /* Looking for gml:polygonPatches */
1720  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1721  {
1722  if (xa->type != XML_ELEMENT_NODE) continue;
1723  if (!is_gml_namespace(xa, false)) continue;
1724  if (!strcmp((char *) xa->name, "polygonPatches"))
1725  {
1726  found = true;
1727  break;
1728  }
1729  }
1730  if (!found) return geom;
1731 
1732  for (xa = xa->children ; xa != NULL ; xa = xa->next)
1733  {
1734  /* PolyhedralSurface/polygonPatches/PolygonPatch */
1735  if (xa->type != XML_ELEMENT_NODE) continue;
1736  if (!is_gml_namespace(xa, false)) continue;
1737  if (strcmp((char *) xa->name, "PolygonPatch")) continue;
1738 
1739  geom = (LWGEOM*)lwpsurface_add_lwpoly((LWPSURFACE*)geom,
1740  (LWPOLY*)parse_gml_patch(xa, hasz, root_srid));
1741  }
1742 
1743  return geom;
1744 }
1745 
1746 
1750 static LWGEOM* parse_gml_coll(xmlNodePtr xnode, bool *hasz, int *root_srid)
1751 {
1752  gmlSrs srs;
1753  xmlNodePtr xa;
1754  LWGEOM *geom = NULL;
1755 
1756  if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
1757 
1758  parse_gml_srs(xnode, &srs);
1759  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1760  *root_srid = srs.srid;
1761 
1762  geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, *root_srid, 1, 0);
1763 
1764  if (xnode->children == NULL)
1765  return geom;
1766 
1767  for (xa = xnode->children ; xa != NULL ; xa = xa->next)
1768  {
1769  if (xa->type != XML_ELEMENT_NODE) continue;
1770  if (!is_gml_namespace(xa, false)) continue;
1771 
1772  /*
1773  * In GML 2.1.2 pointMember, lineStringMember and
1774  * polygonMember are parts of geometryMember
1775  * substitution group
1776  */
1777  if ( !strcmp((char *) xa->name, "pointMember")
1778  || !strcmp((char *) xa->name, "lineStringMember")
1779  || !strcmp((char *) xa->name, "polygonMember")
1780  || !strcmp((char *) xa->name, "geometryMember"))
1781  {
1782  if (xa->children == NULL) break;
1783  geom = (LWGEOM*)lwcollection_add_lwgeom((LWCOLLECTION *)geom,
1784  parse_gml(xa->children, hasz, root_srid));
1785  }
1786  }
1787 
1788  return geom;
1789 }
1790 
1794 static LWGEOM* lwgeom_from_gml(const char* xml)
1795 {
1796  xmlDocPtr xmldoc;
1797  xmlNodePtr xmlroot=NULL;
1798  int xml_size = strlen(xml);
1799  LWGEOM *lwgeom;
1800  bool hasz=true;
1801  int root_srid=SRID_UNKNOWN;
1802 
1803  /* Begin to Parse XML doc */
1804  xmlInitParser();
1805  xmldoc = xmlReadMemory(xml, xml_size, NULL, NULL, XML_PARSE_SAX1);
1806  if (!xmldoc || (xmlroot = xmlDocGetRootElement(xmldoc)) == NULL)
1807  {
1808  xmlFreeDoc(xmldoc);
1809  xmlCleanupParser();
1810  gml_lwpgerror("invalid GML representation", 1);
1811  }
1812 
1813  lwgeom = parse_gml(xmlroot, &hasz, &root_srid);
1814 
1815  xmlFreeDoc(xmldoc);
1816  xmlCleanupParser();
1817  /* shouldn't we be releasing xmldoc too here ? */
1818 
1819 
1820  if ( root_srid != SRID_UNKNOWN )
1821  lwgeom->srid = root_srid;
1822 
1823  /* Should we really do this here ? */
1824  lwgeom_add_bbox(lwgeom);
1825 
1826  /* GML geometries could be either 2 or 3D and can be nested mixed.
1827  * Missing Z dimension is even tolerated inside some GML coords
1828  *
1829  * So we deal with 3D in all structures allocation, and flag hasz
1830  * to false if we met once a missing Z dimension
1831  * In this case, we force recursive 2D.
1832  */
1833  if (!hasz)
1834  {
1835  LWGEOM *tmp = lwgeom_force_2d(lwgeom);
1836  lwgeom_free(lwgeom);
1837  lwgeom = tmp;
1838  }
1839 
1840  return lwgeom;
1841 }
1842 
1843 
1847 static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid)
1848 {
1849  xmlNodePtr xa = xnode;
1850  gmlSrs srs;
1851 
1852  while (xa != NULL && (xa->type != XML_ELEMENT_NODE
1853  || !is_gml_namespace(xa, false))) xa = xa->next;
1854 
1855  if (xa == NULL) gml_lwpgerror("invalid GML representation", 55);
1856 
1857  parse_gml_srs(xa, &srs);
1858  if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
1859  {
1860  *root_srid = srs.srid;
1861  }
1862 
1863  if (!strcmp((char *) xa->name, "Point"))
1864  return parse_gml_point(xa, hasz, root_srid);
1865 
1866  if (!strcmp((char *) xa->name, "LineString"))
1867  return parse_gml_line(xa, hasz, root_srid);
1868 
1869  if (!strcmp((char *) xa->name, "Curve"))
1870  return parse_gml_curve(xa, hasz, root_srid);
1871 
1872  if (!strcmp((char *) xa->name, "LinearRing"))
1873  return parse_gml_linearring(xa, hasz, root_srid);
1874 
1875  if (!strcmp((char *) xa->name, "Polygon"))
1876  return parse_gml_polygon(xa, hasz, root_srid);
1877 
1878  if (!strcmp((char *) xa->name, "Triangle"))
1879  return parse_gml_triangle(xa, hasz, root_srid);
1880 
1881  if (!strcmp((char *) xa->name, "Surface"))
1882  return parse_gml_surface(xa, hasz, root_srid);
1883 
1884  if (!strcmp((char *) xa->name, "MultiPoint"))
1885  return parse_gml_mpoint(xa, hasz, root_srid);
1886 
1887  if (!strcmp((char *) xa->name, "MultiLineString"))
1888  return parse_gml_mline(xa, hasz, root_srid);
1889 
1890  if (!strcmp((char *) xa->name, "MultiCurve"))
1891  return parse_gml_mcurve(xa, hasz, root_srid);
1892 
1893  if (!strcmp((char *) xa->name, "MultiPolygon"))
1894  return parse_gml_mpoly(xa, hasz, root_srid);
1895 
1896  if (!strcmp((char *) xa->name, "MultiSurface"))
1897  return parse_gml_msurface(xa, hasz, root_srid);
1898 
1899  if (!strcmp((char *) xa->name, "PolyhedralSurface"))
1900  return parse_gml_psurface(xa, hasz, root_srid);
1901 
1902  if ((!strcmp((char *) xa->name, "Tin")) ||
1903  !strcmp((char *) xa->name, "TriangulatedSurface" ))
1904  return parse_gml_tin(xa, hasz, root_srid);
1905 
1906  if (!strcmp((char *) xa->name, "MultiGeometry"))
1907  return parse_gml_coll(xa, hasz, root_srid);
1908 
1909  gml_lwpgerror("invalid GML representation", 56);
1910  return NULL; /* Never reach */
1911 }
double x
Definition: liblwgeom.h:352
static LWGEOM * parse_gml_triangle(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML Triangle (3.1.1)
static LWGEOM * parse_gml_mpoly(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML MultiPolygon (2.1.2, 3.1.1)
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
Definition: ptarray.c:62
LWTIN * lwtin_add_lwtriangle(LWTIN *mobj, const LWTRIANGLE *obj)
Definition: lwtin.c: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
static POINTARRAY * parse_gml_poslist(xmlNodePtr xnode, bool *hasz)
Parse gml:posList.
static LWGEOM * parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid)
Parse GML LinearRing (3.1.1)
int npoints
Definition: liblwgeom.h:371
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:710
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:1099
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:88
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:97
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:697
Datum geom_from_gml(PG_FUNCTION_ARGS)
Definition: lwgeom_in_gml.c:97
int32_t srid
Definition: liblwgeom.h:399
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:288
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:79
POINTARRAY * ptarray_flip_coordinates(POINTARRAY *pa)
Reverse X and Y axis on a given POINTARRAY.
Definition: ptarray.c:369
static xmlNodePtr get_xlink_node(xmlNodePtr xnode)
Return a xmlNodePtr on a node referenced by a XLink or NULL otherwise.
#define XLINK_NS
Definition: lwgeom_in_gml.c: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:298
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:77
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:76
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:188
#define TINTYPE
Definition: liblwgeom.h:99
struct struct_gmlSrs gmlSrs
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:739
uint8_t * getPoint_internal(const POINTARRAY *pa, int n)
Definition: ptarray.c:1753
PG_FUNCTION_INFO_V1(geom_from_gml)
Ability to parse GML geometry fragment and to return an LWGEOM or an error message.
char * text2cstring(const text *textptr)
int ptarray_point_size(const POINTARRAY *pa)
Definition: ptarray.c:54
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:293
#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:352
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:90
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
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:161
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:648
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:303
int value
Definition: genraster.py:61
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&#39;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:352
#define MULTILINETYPE
Definition: liblwgeom.h:89
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:94
int ptarray_transform(POINTARRAY *geom, projPJ inpj, projPJ outpj)
Transform given POINTARRAY from inpj projection to outpj projection.
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c: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.
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:91
This library is the generic geometry handling section of PostGIS.
POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2)
Merge two given POINTARRAY and returns a pointer on the new aggregate one.
Definition: ptarray.c:599