From: Olivier Courtin Date: Tue, 3 Nov 2009 22:26:25 +0000 (+0000) Subject: Initial support of Xlink. Add related units tests. Few cleaning X-Git-Tag: 1.5.0b1~302 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=638856d1d82da1824f49958c3540fd1377f84028;p=postgis Initial support of Xlink. Add related units tests. Few cleaning git-svn-id: http://svn.osgeo.org/postgis/trunk@4731 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/postgis/lwgeom_in_gml.c b/postgis/lwgeom_in_gml.c index 8caaaee42..54725023a 100644 --- a/postgis/lwgeom_in_gml.c +++ b/postgis/lwgeom_in_gml.c @@ -19,13 +19,13 @@ * Cf: ISO 13249-3 -> 5.1.50 (p 134) * * GML versions supported: +* - GML 3.2.1 Namespace +* - GML 3.1.1 Simple Features profile +* - GML 3.1.0 and 3.0.0 SF elements and attributes * - GML 2.1.2 -* - GML 3.1.1 Simple Features profile (1.0.0) * Cf: * -* Current known limitations: -* - Support only GML SF profile geometries (i.e no PostGIS curves support) -* - Don't handle Xlink +* NOTA: this code doesn't (yet ?) support SQL/MM curves * * Written by Olivier Courtin - Oslandia * @@ -42,6 +42,9 @@ #if HAVE_LIBXML2 #include #include +#include +#include + Datum geom_from_gml(PG_FUNCTION_ARGS); @@ -54,6 +57,10 @@ typedef struct struct_gmlSrs } gmlSrs; +#define XLINK_NS ((char *) "http://www.w3.org/1999/xlink") +#define GML_NS ((char *) "http://www.opengis.net/gml") +#define GML32_NS ((char *) "http://www.opengis.net/gml/3.2") + /** * Ability to parse GML geometry fragment and to return an LWGEOM @@ -126,6 +133,85 @@ Datum geom_from_gml(PG_FUNCTION_ARGS) } +/** + * Return true if current node contains a simple xlink + * Return false otherwise. + */ +static bool is_xlink(xmlNodePtr node) +{ + xmlChar *prop; + + prop = xmlGetNsProp(node, (xmlChar *)"type", (xmlChar *) XLINK_NS); + if (prop == NULL) return false; + if (strcmp((char *) prop, "simple")) { + xmlFree(prop); + return false; + } + + prop = xmlGetNsProp(node, (xmlChar *)"href", (xmlChar *) XLINK_NS); + if (prop == NULL) return false; + if (prop[0] != '#') { + xmlFree(prop); + return false; + } + xmlFree(prop); + + return true; +} + + +/** + * Return a xmlNodePtr on a node referenced by a xlink or NULL otherwise + */ +static xmlNodePtr get_xlink_node(xmlNodePtr xnode) +{ + char *id; + xmlNodePtr node; + xmlNsPtr *ns, *n; + xmlChar *href, *p; + xmlXPathContext *ctx; + xmlXPathObject *xpath; + + href = xmlGetNsProp(xnode, (xmlChar *)"href", (xmlChar *) XLINK_NS); + id = lwalloc((xmlStrlen(xnode->ns->prefix) * 2 + xmlStrlen(xnode->name) + + xmlStrlen(href) + sizeof("//:[@:id='']") + 1)); + p = href; + p++; /* ignore '#' first char */ + + /* Xpath pattern look like: //gml:point[@gml:id='p1'] */ + sprintf(id, "//%s:%s[@%s:id='%s']", (char *) xnode->ns->prefix, + (char *) xnode->name, + (char *) xnode->ns->prefix, + (char *) p); + xmlFree(href); + + ctx = xmlXPathNewContext(xnode->doc); + if (ctx == NULL) { + lwfree(id); + return NULL; + } + + /* Handle namespaces */ + ns = xmlGetNsList(xnode->doc, xnode); + for (n=ns ; *n; n++) xmlXPathRegisterNs(ctx, (*n)->prefix, (*n)->href); + xmlFree(ns); + + /* Execute Xpath expression */ + xpath = xmlXPathEvalExpression((xmlChar *) id, ctx); + lwfree(id); + if (xpath == NULL || xpath->nodesetval == NULL || xpath->nodesetval->nodeNr != 1) { + xmlXPathFreeObject(xpath); + xmlXPathFreeContext(ctx); + return NULL; + } + node = xpath->nodesetval->nodeTab[0]; + xmlXPathFreeObject(xpath); + xmlXPathFreeContext(ctx); + + return node; +} + + /** * Return false if current element namespace is not a GML one * Return true otherwise. @@ -149,10 +235,11 @@ static bool is_gml_namespace(xmlNodePtr xnode, bool is_strict) */ for (p=ns ; *p ; p++) { if ((*p)->href == NULL) continue; - if (!strcmp((char *) (*p)->href, "http://www.opengis.net/gml") || - !strcmp((char *) (*p)->href, "http://www.opengis.net/gml/3.2")) { - if ((*p)->prefix == NULL || - !xmlStrcmp(xnode->ns->prefix, (*p)->prefix)) { + if (!strcmp((char *) (*p)->href, GML_NS) || + !strcmp((char *) (*p)->href, GML32_NS)) { + if ( (*p)->prefix == NULL || + !xmlStrcmp(xnode->ns->prefix, (*p)->prefix)) { + xmlFree(ns); return true; } @@ -171,8 +258,6 @@ static bool is_gml_namespace(xmlNodePtr xnode, bool is_strict) static xmlChar *gmlGetProp(xmlNodePtr xnode, xmlChar *prop) { xmlChar *value; - xmlChar gmlns[]="http://www.opengis.net/gml"; - xmlChar gmlns32[]="http://www.opengis.net/gml/3.2"; if (!is_gml_namespace(xnode, true)) return xmlGetProp(xnode, prop); @@ -180,16 +265,16 @@ static xmlChar *gmlGetProp(xmlNodePtr xnode, xmlChar *prop) /* We begin to try without explicit namespace */ value = xmlGetNoNsProp(xnode, prop); if (value != NULL && xnode->ns->href != NULL && - (!xmlStrcmp(xnode->ns->href, gmlns) || - !xmlStrcmp(xnode->ns->href, gmlns32))) return value; + (!strcmp((char *) xnode->ns->href, GML_NS) || + !strcmp((char *) xnode->ns->href, GML32_NS))) return value; /* * Handle namespaces: * - http://www.opengis.net/gml (GML 3.1.1 and priors) * - http://www.opengis.net/gml/3.2 (GML 3.2.1) */ - value = xmlGetNsProp(xnode, prop, gmlns); - if (value == NULL) value = xmlGetNsProp(xnode, prop, gmlns32); + value = xmlGetNsProp(xnode, prop, (xmlChar *) GML_NS); + if (value == NULL)value = xmlGetNsProp(xnode, prop, (xmlChar *) GML32_NS); return value; } @@ -794,14 +879,12 @@ static POINTARRAY* parse_gml_data(xmlNodePtr xnode, bool *hasz, int *root_srid) break; } } - if (!found) - lwerror("A invalid GML representation"); - if (xb == NULL) - lwerror("B invalid GML representation"); + if (!found || xb == NULL) lwerror("invalid GML representation"); - if (!found || xb == NULL || xb->children == NULL) - lwerror("C invalid GML representation"); + if (is_xlink(xb)) xb = get_xlink_node(xb); + if (xb == NULL || xb->children == NULL) + lwerror("invalid GML representation"); tmp_pa = parse_gml_data(xb->children, hasz, root_srid); if (tmp_pa->npoints != 1) lwerror("invalid GML representation"); diff --git a/regress/in_gml.sql b/regress/in_gml.sql index 61988c39b..ea0b0f9cd 100644 --- a/regress/in_gml.sql +++ b/regress/in_gml.sql @@ -729,8 +729,38 @@ SELECT 'data_1', ST_AsEWKT(ST_GeomFromGML('1 21 23 4 5 67 89,10')); --- TODO xlink pointProperty ---SELECT 'data_3', ST_AsEWKT(ST_GeomFromGML('1 2')); + + +-- +-- Xlink +-- + +-- Xlink on a point +SELECT 'xlink_1', ST_AsEWKT(ST_GeomFromGML('1 23 4')); + +-- ERROR: xlink:href destination is not defined +SELECT 'xlink_2', ST_AsEWKT(ST_GeomFromGML('1 23 4')); + +-- ERROR: no href +SELECT 'xlink_3', ST_AsEWKT(ST_GeomFromGML('1 23 4')); + +-- ERROR: empty href +SELECT 'xlink_4', ST_AsEWKT(ST_GeomFromGML('1 23 4')); + +-- ERROR: no sharp char in href +SELECT 'xlink_5', ST_AsEWKT(ST_GeomFromGML('1 23 4')); + +-- ERROR: no xlink namespace +SELECT 'xlink_6', ST_AsEWKT(ST_GeomFromGML('1 23 4')); + +-- ERROR: wrong xlink namespace +SELECT 'xlink_7', ST_AsEWKT(ST_GeomFromGML('1 23 4')); + +-- ERROR: no xlink:type +SELECT 'xlink_8', ST_AsEWKT(ST_GeomFromGML('1 23 4')); + +-- ERROR: xlink:type not simple +SELECT 'xlink_9', ST_AsEWKT(ST_GeomFromGML('1 23 4')); diff --git a/regress/in_gml_expected b/regress/in_gml_expected index be3b1a4db..aa7841cfd 100644 --- a/regress/in_gml_expected +++ b/regress/in_gml_expected @@ -226,6 +226,15 @@ poslist_17|LINESTRING(1 2,3 4) ERROR: invalid GML representation data_1|LINESTRING(1 2,3 4,5 6,7 8,9 10,11 12) data_2|LINESTRING(1 2,3 4,5 6,7 8,9 10) +xlink_1|LINESTRING(1 2,1 2,3 4) +ERROR: invalid GML representation +ERROR: invalid GML representation +ERROR: invalid GML representation +ERROR: invalid GML representation +ERROR: invalid GML representation +ERROR: invalid GML representation +ERROR: invalid GML representation +ERROR: invalid GML representation coord_1|POINT(1 2) coord_2|POINT(1 2 3) ERROR: invalid GML representation