42 #include <libxml/tree.h>
43 #include <libxml/parser.h>
48 #include "utils/builtins.h"
50 #include "../postgis_config.h"
51 #include "lwgeom_pg.h"
67 #define KML_NS ((char *) "http://www.opengis.net/kml/2.2")
84 xmlNodePtr xmlroot=NULL;
88 if (PG_ARGISNULL(0)) PG_RETURN_NULL();
89 xml_input = PG_GETARG_TEXT_P(0);
91 xml_size = VARSIZE(xml_input) - VARHDRSZ;
95 xmldoc = xmlReadMemory(xml, xml_size, NULL, NULL, XML_PARSE_SAX1);
96 if (!xmldoc || (xmlroot = xmlDocGetRootElement(xmldoc)) == NULL)
100 lwpgerror(
"invalid KML representation");
134 PG_RETURN_POINTER(geom);
146 ns = xmlGetNsList(xnode->doc, xnode);
152 if (ns == NULL)
return !is_strict;
154 for (p=ns ; *p ; p++)
156 if ((*p)->href == NULL || (*p)->prefix == NULL ||
157 xnode->ns == NULL || xnode->ns->prefix == NULL)
continue;
159 if (!xmlStrcmp(xnode->ns->prefix, (*p)->prefix))
161 if (!strcmp((
char *) (*p)->href,
KML_NS))
183 static xmlChar *kmlGetProp(xmlNodePtr xnode, xmlChar *prop)
188 return xmlGetProp(xnode, prop);
190 value = xmlGetNsProp(xnode, prop, (xmlChar *)
KML_NS);
193 if (
value == NULL)
value = xmlGetNoNsProp(xnode, prop);
204 static double parse_kml_double(
char *d,
bool space_before,
bool space_after)
228 if (space_before)
while (isspace(*d)) d++;
229 for (st = INIT, p = d ; *p ; p++)
232 lwpgnotice(
"State: %d, *p=%c", st, *p);
236 if (st == INIT || st == NEED_DIG) st = DIG;
237 else if (st == NEED_DIG_DEC) st = DIG_DEC;
238 else if (st == NEED_DIG_EXP || st == EXP) st = DIG_EXP;
239 else if (st == DIG || st == DIG_DEC || st == DIG_EXP);
240 else lwpgerror(
"invalid KML representation");
244 if (st == DIG) st = NEED_DIG_DEC;
245 else lwpgerror(
"invalid KML representation");
247 else if (*p ==
'-' || *p ==
'+')
249 if (st == INIT) st = NEED_DIG;
250 else if (st == EXP) st = NEED_DIG_EXP;
251 else lwpgerror(
"invalid KML representation");
253 else if (*p ==
'e' || *p ==
'E')
255 if (st == DIG || st == DIG_DEC) st = EXP;
256 else lwpgerror(
"invalid KML representation");
258 else if (isspace(*p))
260 if (!space_after) lwpgerror(
"invalid KML representation");
261 if (st == DIG || st == DIG_DEC || st == DIG_EXP)st = END;
262 else if (st == NEED_DIG_DEC) st = END;
264 else lwpgerror(
"invalid KML representation");
266 else lwpgerror(
"invalid KML representation");
269 if (st != DIG && st != NEED_DIG_DEC && st != DIG_DEC && st != DIG_EXP && st != END)
270 lwpgerror(
"invalid KML representation");
285 int seen_kml_dims = 0;
291 if (xnode == NULL) lwpgerror(
"invalid KML representation");
293 for (found =
false ; xnode != NULL ; xnode = xnode->next)
295 if (xnode->type != XML_ELEMENT_NODE)
continue;
297 if (strcmp((
char *) xnode->name,
"coordinates"))
continue;
302 if (!found) lwpgerror(
"invalid KML representation");
305 kml_coord = xmlNodeGetContent(xnode);
306 p = (
char *) kml_coord;
316 while (*p && isspace(*p)) ++p;
317 for (kml_dims=0; *p ; p++)
320 if ( isdigit(*p) || *p ==
'+' || *p ==
'-' || *p ==
'.' ) {
322 errno = 0; d = strtod(p, &q);
325 lwpgerror(
"invalid KML representation");
327 if (kml_dims == 1) pt.
x = d;
328 else if (kml_dims == 2) pt.
y = d;
329 else if (kml_dims == 3) pt.
z = d;
331 lwpgerror(
"invalid KML representation");
337 if ( *q && ! isspace(*q) && *q !=
',' ) {
338 lwpgerror(
"invalid KML representation");
342 while (*q && isspace(*q)) ++q;
343 if ( isdigit(*q) || *q ==
'+' || *q ==
'-' || *q ==
'.' || ! *q ) {
344 if ( kml_dims < 2 ) lwpgerror(
"invalid KML representation");
345 else if ( kml_dims < 3 ) *hasz =
false;
346 if ( ! seen_kml_dims ) seen_kml_dims = kml_dims;
347 else if ( seen_kml_dims != kml_dims ) {
348 lwpgerror(
"invalid KML representation: mixed coordinates dimension");
355 }
else if ( *p !=
',' && ! isspace(*p) ) {
356 lwpgerror(
"invalid KML representation");
374 if (xnode->children == NULL) lwpgerror(
"invalid KML representation");
376 if (pa->
npoints != 1) lwpgerror(
"invalid KML representation");
389 if (xnode->children == NULL) lwpgerror(
"invalid KML representation");
391 if (pa->
npoints < 2) lwpgerror(
"invalid KML representation");
407 for (xa = xnode->children ; xa != NULL ; xa = xa->next)
411 if (xa->type != XML_ELEMENT_NODE)
continue;
413 if (strcmp((
char *) xa->name,
"outerBoundaryIs"))
continue;
415 for (xb = xa->children ; xb != NULL ; xb = xb->next)
418 if (xb->type != XML_ELEMENT_NODE)
continue;
420 if (strcmp((
char *) xb->name,
"LinearRing"))
continue;
425 if (ppa[0]->npoints < 4)
426 lwpgerror(
"invalid KML representation");
434 lwpgnotice(
"forced closure on an un-closed KML polygon");
440 if (outer_rings != 1)
441 lwpgerror(
"invalid KML representation");
443 for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
447 if (xa->type != XML_ELEMENT_NODE)
continue;
449 if (strcmp((
char *) xa->name,
"innerBoundaryIs"))
continue;
451 for (xb = xa->children ; xb != NULL ; xb = xb->next)
454 if (xb->type != XML_ELEMENT_NODE)
continue;
456 if (strcmp((
char *) xb->name,
"LinearRing"))
continue;
461 if (ppa[ring]->npoints < 4)
462 lwpgerror(
"invalid KML representation");
470 lwpgnotice(
"forced closure on an un-closed KML polygon");
478 if (ppa == NULL || ppa[0] == NULL) lwpgerror(
"invalid KML representation");
494 for (xa = xnode->children ; xa != NULL ; xa = xa->next)
497 if (xa->type != XML_ELEMENT_NODE)
continue;
500 if ( !strcmp((
char *) xa->name,
"Point")
501 || !strcmp((
char *) xa->name,
"LineString")
502 || !strcmp((
char *) xa->name,
"Polygon")
503 || !strcmp((
char *) xa->name,
"MultiGeometry"))
506 if (xa->children == NULL)
break;
520 xmlNodePtr xa = xnode;
522 while (xa != NULL && (xa->type != XML_ELEMENT_NODE
525 if (xa == NULL) lwpgerror(
"invalid KML representation");
527 if (!strcmp((
char *) xa->name,
"Point"))
530 if (!strcmp((
char *) xa->name,
"LineString"))
533 if (!strcmp((
char *) xa->name,
"Polygon"))
536 if (!strcmp((
char *) xa->name,
"MultiGeometry"))
539 lwpgerror(
"invalid KML representation");
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
void lwgeom_free(LWGEOM *geom)
int ptarray_is_closed_3d(const POINTARRAY *pa)
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
void * lwrealloc(void *mem, size_t size)
LWGEOM * lwgeom_homogenize(const LWGEOM *geom)
LWPOINT * lwpoint_construct(int srid, GBOX *bbox, POINTARRAY *point)
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
LWPOLY * lwpoly_construct(int srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
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,...
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
void * lwalloc(size_t size)
int ptarray_is_closed_2d(const POINTARRAY *pa)
#define LW_TRUE
Return types for functions with status returns.
void lwgeom_release(LWGEOM *lwgeom)
Free the containing LWGEOM and the associated BOX.
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
This library is the generic geometry handling section of PostGIS.
static LWGEOM * parse_kml(xmlNodePtr xnode, bool *hasz)
Parse KML.
static LWGEOM * parse_kml_line(xmlNodePtr xnode, bool *hasz)
Parse KML lineString.
static POINTARRAY * parse_kml_coordinates(xmlNodePtr xnode, bool *hasz)
Parse kml:coordinates.
PG_FUNCTION_INFO_V1(geom_from_kml)
Ability to parse KML geometry fragment and to return an LWGEOM or an error message.
static LWGEOM * parse_kml_multi(xmlNodePtr xnode, bool *hasz)
Parse KML MultiGeometry.
static LWGEOM * parse_kml_polygon(xmlNodePtr xnode, bool *hasz)
Parse KML Polygon.
static LWGEOM * parse_kml_point(xmlNodePtr xnode, bool *hasz)
Parse KML point.
Datum geom_from_kml(PG_FUNCTION_ARGS)
static bool is_kml_namespace(xmlNodePtr xnode, bool is_strict)
Return false if current element namespace is not a KML one Return true otherwise.
char * text_to_cstring(const text *textptr)
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)