PostGIS  2.5.0beta1dev-r@@SVN_REVISION@@
lwgeom_in_gml.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright 2009 - 2010 Oslandia
22  *
23  **********************************************************************/
24 
25 
50 #include <libxml/tree.h>
51 #include <libxml/parser.h>
52 #include <libxml/xpath.h>
53 #include <libxml/xpathInternals.h>
54 
55 #include "postgres.h"
56 #include "executor/spi.h"
57 #include "utils/builtins.h"
58 
59 #include "../postgis_config.h"
60 #include "lwgeom_pg.h"
61 #include "liblwgeom.h"
62 #include "lwgeom_transform.h"
63 
64 
65 Datum geom_from_gml(PG_FUNCTION_ARGS);
66 static LWGEOM* lwgeom_from_gml(const char *wkt);
67 static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid);
68 
69 typedef struct struct_gmlSrs
70 {
71  int srid;
73 }
74 gmlSrs;
75 
76 #define XLINK_NS ((char *) "http://www.w3.org/1999/xlink")
77 #define GML_NS ((char *) "http://www.opengis.net/gml")
78 #define GML32_NS ((char *) "http://www.opengis.net/gml/3.2")
79 
80 
81 
82 static void gml_lwpgerror(char *msg, __attribute__((__unused__)) int error_code)
83 {
84  POSTGIS_DEBUGF(3, "ST_GeomFromGML ERROR %i", error_code);
85  lwpgerror("%s", msg);
86 }
87 
98 Datum geom_from_gml(PG_FUNCTION_ARGS)
99 {
100  GSERIALIZED *geom;
101  text *xml_input;
102  LWGEOM *lwgeom;
103  char *xml;
104  int root_srid=SRID_UNKNOWN;
105 
106 
107  /* Get the GML stream */
108  if (PG_ARGISNULL(0)) PG_RETURN_NULL();
109  xml_input = PG_GETARG_TEXT_P(0);
110  xml = text_to_cstring(xml_input);
111 
112  /* Zero for undefined */
113  root_srid = PG_GETARG_INT32(1);
114 
115  lwgeom = lwgeom_from_gml(xml);
116  if ( root_srid != SRID_UNKNOWN )
117  lwgeom->srid = root_srid;
118 
119  geom = geometry_serialize(lwgeom);
120  lwgeom_free(lwgeom);
121 
122  PG_RETURN_POINTER(geom);
123 }
124 
125 
130 static bool is_gml_namespace(xmlNodePtr xnode, bool is_strict)
131 {
132  xmlNsPtr *ns, *p;
133 
134  ns = xmlGetNsList(xnode->doc, xnode);
135  /*
136  * If no namespace is available we could return true anyway
137  * (because we work only on GML fragment, we don't want to
138  * 'oblige' to add namespace on the geometry root node)
139  */
140  if (ns == NULL) { return !is_strict; }
141 
142  /*
143  * Handle namespaces:
144  * - http://www.opengis.net/gml (GML 3.1.1 and priors)
145  * - http://www.opengis.net/gml/3.2 (GML 3.2.1)
146  */
147  for (p=ns ; *p ; p++)
148  {
149  if ((*p)->href == NULL || (*p)->prefix == NULL ||
150  xnode->ns == NULL || xnode->ns->prefix == NULL) continue;
151 
152  if (!xmlStrcmp(xnode->ns->prefix, (*p)->prefix))
153  {
154  if ( !strcmp((char *) (*p)->href, GML_NS)
155  || !strcmp((char *) (*p)->href, GML32_NS))
156  {
157  xmlFree(ns);
158  return true;
159  } else {
160  xmlFree(ns);
161  return false;
162  }
163  }
164  }
165 
166  xmlFree(ns);
167  return !is_strict; /* Same reason here to not return false */
168 }
169 
170 
175 static xmlChar *gmlGetProp(xmlNodePtr xnode, xmlChar *prop)
176 {
177  xmlChar *value;
178 
179  if (!is_gml_namespace(xnode, true))
180  return xmlGetProp(xnode, prop);
181  /*
182  * Handle namespaces:
183  * - http://www.opengis.net/gml (GML 3.1.1 and priors)
184  * - http://www.opengis.net/gml/3.2 (GML 3.2.1)
185  */
186  value = xmlGetNsProp(xnode, prop, (xmlChar *) GML_NS);
187  if (value == NULL) value = xmlGetNsProp(xnode, prop, (xmlChar *) GML32_NS);
188 
189  /* In last case try without explicit namespace */
190  if (value == NULL) value = xmlGetNoNsProp(xnode, prop);
191 
192  return value;
193 }
194 
195 
200 static bool is_xlink(xmlNodePtr node)
201 {
202  xmlChar *prop;
203 
204  prop = xmlGetNsProp(node, (xmlChar *)"type", (xmlChar *) XLINK_NS);
205  if (prop == NULL) return false;
206  if (strcmp((char *) prop, "simple"))
207  {
208  xmlFree(prop);
209  return false;
210  }
211 
212  prop = xmlGetNsProp(node, (xmlChar *)"href", (xmlChar *) XLINK_NS);
213  if (prop == NULL) return false;
214  if (prop[0] != '#')
215  {
216  xmlFree(prop);
217  return false;
218  }
219  xmlFree(prop);
220 
221  return true;
222 }
223 
224 
228 static xmlNodePtr get_xlink_node(xmlNodePtr xnode)
229 {
230  char *id;
231  xmlNsPtr *ns, *n;
232  xmlXPathContext *ctx;
233  xmlXPathObject *xpath;
234  xmlNodePtr node, ret_node;
235  xmlChar *href, *p, *node_id;
236 
237  href = xmlGetNsProp(xnode, (xmlChar *)"href", (xmlChar *) XLINK_NS);
238  id = lwalloc((xmlStrlen(xnode->ns->prefix) * 2 + xmlStrlen(xnode->name)
239  + xmlStrlen(href) + sizeof("//:[@:id='']") + 1));
240  p = href;
241  p++; /* ignore '#' first char */
242 
243  /* XPath pattern look like: //gml:point[@gml:id='p1'] */
244  sprintf(id, "//%s:%s[@%s:id='%s']", (char *) xnode->ns->prefix,
245  (char *) xnode->name,
246  (char *) xnode->ns->prefix,
247  (char *) p);
248 
249  ctx = xmlXPathNewContext(xnode->doc);
250  if (ctx == NULL)
251  {
252  xmlFree(href);
253  lwfree(id);
254  return NULL;
255  }
256 
257  /* Handle namespaces */
258  ns = xmlGetNsList(xnode->doc, xnode);
259  for (n=ns ; *n; n++) xmlXPathRegisterNs(ctx, (*n)->prefix, (*n)->href);
260  xmlFree(ns);
261 
262  /* Execute XPath expression */
263  xpath = xmlXPathEvalExpression((xmlChar *) id, ctx);
264  lwfree(id);
265  if (xpath == NULL || xpath->nodesetval == NULL || xpath->nodesetval->nodeNr != 1)
266  {
267  xmlFree(href);
268  xmlXPathFreeObject(xpath);
269  xmlXPathFreeContext(ctx);
270  return NULL;
271  }
272  ret_node = xpath->nodesetval->nodeTab[0];
273  xmlXPathFreeObject(xpath);
274  xmlXPathFreeContext(ctx);
275 
276  /* Protection against circular calls */
277  for (node = xnode ; node != NULL ; node = node->parent)
278  {
279  if (node->type != XML_ELEMENT_NODE) continue;
280  node_id = gmlGetProp(node, (xmlChar *) "id");
281  if (node_id != NULL)
282  {
283  if (!xmlStrcmp(node_id, p))
284  gml_lwpgerror("invalid GML representation", 2);
285  xmlFree(node_id);
286  }
287  }
288 
289  xmlFree(href);
290  return ret_node;
291 }
292 
293 
297 static POINTARRAY* gml_reproject_pa(POINTARRAY *pa, int srid_in, int srid_out)
298 {
299  projPJ in_pj, out_pj;
300  char *text_in, *text_out;
301 
302  if (srid_in == SRID_UNKNOWN) return pa; /* nothing to do */
303  if (srid_out == SRID_UNKNOWN) gml_lwpgerror("invalid GML representation", 3);
304 
305  text_in = GetProj4StringSPI(srid_in);
306  text_out = GetProj4StringSPI(srid_out);
307 
308  in_pj = lwproj_from_string(text_in);
309  out_pj = lwproj_from_string(text_out);
310 
311  lwfree(text_in);
312  lwfree(text_out);
313 
314  if ( ptarray_transform(pa, in_pj, out_pj) == LW_FAILURE )
315  {
316  elog(ERROR, "gml_reproject_pa: reprojection failed");
317  }
318 
319  pj_free(in_pj);
320  pj_free(out_pj);
321 
322  return pa;
323 }
324 
325 
330 static int gml_is_srid_planar(int srid)
331 {
332  char *result;
333  char query[256];
334  int is_planar, err;
335 
336  if (SPI_OK_CONNECT != SPI_connect ())
337  lwpgerror("gml_is_srid_planar: could not connect to SPI manager");
338 
339  /* A way to find if this projection is planar or geocentric */
340  sprintf(query, "SELECT position('+units=m ' in proj4text) \
341  FROM spatial_ref_sys WHERE srid='%d'", srid);
342 
343  err = SPI_exec(query, 1);
344  if (err < 0) lwpgerror("gml_is_srid_planar: error executing query %d", err);
345 
346  /* No entry in spatial_ref_sys */
347  if (SPI_processed <= 0)
348  {
349  SPI_finish();
350  return -1;
351  }
352 
353  result = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
354  is_planar = atoi(result);
355  SPI_finish();
356 
357  return is_planar;
358 }
359 
360 
364 static void parse_gml_srs(xmlNodePtr xnode, gmlSrs *srs)
365 {
366  char *p;
367  int is_planar;
368  xmlNodePtr node;
369  xmlChar *srsname;
370  bool latlon = false;
371  char sep = ':';
372 
373  node = xnode;
374  srsname = gmlGetProp(node, (xmlChar *) "srsName");
375  /*printf("srsname %s\n",srsname);*/
376  if (!srsname)
377  {
378  if (node->parent == NULL)
379  {
380  srs->srid = SRID_UNKNOWN;
381  srs->reverse_axis = false;
382  return;
383  }
384  parse_gml_srs(node->parent, srs);
385  }
386  else
387  {
388  /* Severals srsName formats are available...
389  * cf WFS 1.1.0 -> 9.2 (p36)
390  * cf ISO 19142:2009 -> 7.9.2.4.4 (p34)
391  * cf RFC 5165 <http://tools.ietf.org/html/rfc5165>
392  * cf CITE WFS-1.1 (GetFeature-tc17.2)
393  */
394 
395  /* SRS pattern like: EPSG:4326
396  urn:EPSG:geographicCRS:4326
397  urn:ogc:def:crs:EPSG:4326
398  urn:ogc:def:crs:EPSG::4326
399  urn:ogc:def:crs:EPSG:6.6:4326
400  urn:x-ogc:def:crs:EPSG:6.6:4326
401  http://www.opengis.net/gml/srs/epsg.xml#4326
402  http://www.epsg.org/6.11.2/4326
403  */
404 
405  if (!strncmp((char *) srsname, "EPSG:", 5))
406  {
407  sep = ':';
408  latlon = false;
409  }
410  else if (!strncmp((char *) srsname, "urn:ogc:def:crs:EPSG:", 21)
411  || !strncmp((char *) srsname, "urn:x-ogc:def:crs:EPSG:", 23)
412  || !strncmp((char *) srsname, "urn:EPSG:geographicCRS:", 23))
413  {
414  sep = ':';
415  latlon = true;
416  }
417  else if (!strncmp((char *) srsname,
418  "http://www.opengis.net/gml/srs/epsg.xml#", 40))
419  {
420  sep = '#';
421  latlon = false;
422  }
423  else gml_lwpgerror("unknown spatial reference system", 4);
424 
425  /* retrieve the last ':' or '#' char */
426  for (p = (char *) srsname ; *p ; p++);
427  for (--p ; *p != sep ; p--)
428  if (!isdigit(*p)) gml_lwpgerror("unknown spatial reference system", 5);
429 
430  srs->srid = atoi(++p);
431 
432  /* Check into spatial_ref_sys that this SRID really exist */
433  is_planar = gml_is_srid_planar(srs->srid);
434  if (srs->srid == SRID_UNKNOWN || is_planar == -1)
435  gml_lwpgerror("unknown spatial reference system", 6);
436 
437  /* About lat/lon issue, Cf: http://tinyurl.com/yjpr55z */
438  srs->reverse_axis = !is_planar && latlon;
439 
440  xmlFree(srsname);
441  return;
442  }
443 }
444 
445 
449 static double parse_gml_double(char *d, bool space_before, bool space_after)
450 {
451  char *p;
452  int st;
453  enum states
454  {
455  INIT = 0,
456  NEED_DIG = 1,
457  DIG = 2,
458  NEED_DIG_DEC = 3,
459  DIG_DEC = 4,
460  EXP = 5,
461  NEED_DIG_EXP = 6,
462  DIG_EXP = 7,
463  END = 8
464  };
465 
466  /*
467  * Double pattern
468  * [-|\+]?[0-9]+(\.)?([0-9]+)?([Ee](\+|-)?[0-9]+)?
469  * We could also meet spaces before and/or after
470  * this pattern upon parameters
471  */
472 
473  if (space_before) while (isspace(*d)) d++;
474  for (st = INIT, p = d ; *p ; p++)
475  {
476 
477  if (isdigit(*p))
478  {
479  if (st == INIT || st == NEED_DIG) st = DIG;
480  else if (st == NEED_DIG_DEC) st = DIG_DEC;
481  else if (st == NEED_DIG_EXP || st == EXP) st = DIG_EXP;
482  else if (st == DIG || st == DIG_DEC || st == DIG_EXP);
483  else gml_lwpgerror("invalid GML representation", 7);
484  }
485  else if (*p == '.')
486  {
487  if (st == DIG) st = NEED_DIG_DEC;
488  else gml_lwpgerror("invalid GML representation", 8);
489  }
490  else if (*p == '-' || *p == '+')
491  {
492  if (st == INIT) st = NEED_DIG;
493  else if (st == EXP) st = NEED_DIG_EXP;
494  else gml_lwpgerror("invalid GML representation", 9);
495  }
496  else if (*p == 'e' || *p == 'E')
497  {
498  if (st == DIG || st == DIG_DEC) st = EXP;
499  else gml_lwpgerror("invalid GML representation", 10);
500  }
501  else if (isspace(*p))
502  {
503  if (!space_after) gml_lwpgerror("invalid GML representation", 11);
504  if (st == DIG || st == DIG_DEC || st == DIG_EXP)st = END;
505  else if (st == NEED_DIG_DEC) st = END;
506  else if (st == END);
507  else gml_lwpgerror("invalid GML representation", 12);
508  }
509  else gml_lwpgerror("invalid GML representation", 13);
510  }
511 
512  if (st != DIG && st != NEED_DIG_DEC && st != DIG_DEC && st != DIG_EXP && st != END)
513  gml_lwpgerror("invalid GML representation", 14);
514 
515  return atof(d);
516 }
517 
518 
522 static POINTARRAY* parse_gml_coordinates(xmlNodePtr xnode, bool *hasz)
523 {
524  xmlChar *gml_coord, *gml_ts, *gml_cs, *gml_dec;
525  char cs, ts, dec;
526  POINTARRAY *dpa;
527  int gml_dims;
528  char *p, *q;
529  bool digit;
530  POINT4D pt;
531 
532  /* We begin to retrieve coordinates string */
533  gml_coord = xmlNodeGetContent(xnode);
534  p = (char *) gml_coord;
535 
536  /* Default GML coordinates pattern: x1,y1 x2,y2
537  * x1,y1,z1 x2,y2,z2
538  *
539  * Cf GML 2.1.2 -> 4.3.1 (p18)
540  */
541 
542  /* Retrieve separator between coordinates tuples */
543  gml_ts = gmlGetProp(xnode, (xmlChar *) "ts");
544  if (gml_ts == NULL) ts = ' ';
545  else
546  {
547  if (xmlStrlen(gml_ts) > 1 || isdigit(gml_ts[0]))
548  gml_lwpgerror("invalid GML representation", 15);
549  ts = gml_ts[0];
550  xmlFree(gml_ts);
551  }
552 
553  /* Retrieve separator between each coordinate */
554  gml_cs = gmlGetProp(xnode, (xmlChar *) "cs");
555  if (gml_cs == NULL) cs = ',';
556  else
557  {
558  if (xmlStrlen(gml_cs) > 1 || isdigit(gml_cs[0]))
559  gml_lwpgerror("invalid GML representation", 16);
560  cs = gml_cs[0];
561  xmlFree(gml_cs);
562  }
563 
564  /* Retrieve decimal separator */
565  gml_dec = gmlGetProp(xnode, (xmlChar *) "decimal");
566  if (gml_dec == NULL) dec = '.';
567  else
568  {
569  if (xmlStrlen(gml_dec) > 1 || isdigit(gml_dec[0]))
570  gml_lwpgerror("invalid GML representation", 17);
571  dec = gml_dec[0];
572  xmlFree(gml_dec);
573  }
574 
575  if (cs == ts || cs == dec || ts == dec)
576  gml_lwpgerror("invalid GML representation", 18);
577 
578  /* HasZ, !HasM, 1 Point */
579  dpa = ptarray_construct_empty(1, 0, 1);
580 
581  while (isspace(*p)) p++; /* Eat extra whitespaces if any */
582  for (q = p, gml_dims=0, digit = false ; *p ; p++)
583  {
584 
585  if (isdigit(*p)) digit = true; /* One state parser */
586 
587  /* Coordinate Separator */
588  if (*p == cs)
589  {
590  *p = '\0';
591  gml_dims++;
592 
593  if (*(p+1) == '\0') gml_lwpgerror("invalid GML representation", 19);
594 
595  if (gml_dims == 1) pt.x = parse_gml_double(q, false, true);
596  else if (gml_dims == 2) pt.y = parse_gml_double(q, false, true);
597 
598  q = p+1;
599 
600  /* Tuple Separator (or end string) */
601  }
602  else if (digit && (*p == ts || *(p+1) == '\0'))
603  {
604  if (*p == ts) *p = '\0';
605  gml_dims++;
606 
607  if (gml_dims < 2 || gml_dims > 3)
608  gml_lwpgerror("invalid GML representation", 20);
609 
610  if (gml_dims == 3)
611  pt.z = parse_gml_double(q, false, true);
612  else
613  {
614  pt.y = parse_gml_double(q, false, true);
615  *hasz = false;
616  }
617 
618  ptarray_append_point(dpa, &pt, LW_TRUE);
619  digit = false;
620 
621  q = p+1;
622  gml_dims = 0;
623 
624  /* Need to put standard decimal separator to atof handle */
625  }
626  else if (*p == dec && dec != '.') *p = '.';
627  }
628 
629  xmlFree(gml_coord);
630 
631  return dpa; /* ptarray_clone_deep(dpa); */
632 }
633 
634 
638 static POINTARRAY* parse_gml_coord(xmlNodePtr xnode, bool *hasz)
639 {
640  xmlNodePtr xyz;
641  POINTARRAY *dpa;
642  bool x,y,z;
643  xmlChar *c;
644  POINT4D p;
645 
646  /* HasZ?, !HasM, 1 Point */
647  dpa = ptarray_construct_empty(1, 0, 1);
648 
649  x = y = z = false;
650  for (xyz = xnode->children ; xyz != NULL ; xyz = xyz->next)
651  {
652  if (xyz->type != XML_ELEMENT_NODE) continue;
653  if (!is_gml_namespace(xyz, false)) continue;
654 
655  if (!strcmp((char *) xyz->name, "X"))
656  {
657  if (x) gml_lwpgerror("invalid GML representation", 21);
658  c = xmlNodeGetContent(xyz);
659  p.x = parse_gml_double((char *) c, true, true);
660  x = true;
661  xmlFree(c);
662  }
663  else if (!strcmp((char *) xyz->name, "Y"))
664  {
665  if (y) gml_lwpgerror("invalid GML representation", 22);
666  c = xmlNodeGetContent(xyz);
667  p.y = parse_gml_double((char *) c, true, true);
668  y = true;
669  xmlFree(c);
670  }
671  else if (!strcmp((char *) xyz->name, "Z"))
672  {
673  if (z) gml_lwpgerror("invalid GML representation", 23);
674  c = xmlNodeGetContent(xyz);
675  p.z = parse_gml_double((char *) c, true, true);
676  z = true;
677  xmlFree(c);
678  }
679  }
680  /* Check dimension consistancy */
681  if (!x || !y) gml_lwpgerror("invalid GML representation", 24);
682  if (!z) *hasz = false;
683 
684  ptarray_append_point(dpa, &p, LW_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 restricted 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 redundant 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 restricted 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 restricted 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  geom = (LWGEOM*)lwmpoint_add_lwpoint(
1518  (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:354
char * text_to_cstring(const text *textptr)
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)
static void gml_lwpgerror(char *msg, __attribute__((__unused__)) int error_code)
Definition: lwgeom_in_gml.c:82
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 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 __attribute__(x)
Definition: liblwgeom.h:200
#define GML32_NS
Definition: lwgeom_in_gml.c:78
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:1144
static xmlChar * gmlGetProp(xmlNodePtr xnode, xmlChar *prop)
Retrieve a GML property from a node or NULL otherwise Respect namespaces if presents in the node elem...
#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:98
int32_t srid
Definition: liblwgeom.h:401
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:320
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:76
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:330
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:784
PG_FUNCTION_INFO_V1(geom_from_gml)
Ability to parse GML geometry fragment and to return an LWGEOM or an error message.
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:325
#define GML_NS
Definition: lwgeom_in_gml.c:77
static bool is_xlink(xmlNodePtr node)
Return true if current node contains a simple XLink Return false otherwise.
double z
Definition: liblwgeom.h:354
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:161
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:686
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:335
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:354
#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.
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:373
POINTARRAY * ptarray_merge(POINTARRAY *pa1, POINTARRAY *pa2)
Merge two given POINTARRAY and returns a pointer on the new aggregate one.
Definition: ptarray.c:597