Permalink
Browse files

WFS 2.0: various fixes and enhancements to pass wfs-2.0-r12-SNAPSHOT …

…CITE tests (Simple WFS and Basic WFS conformance levels)
  • Loading branch information...
rouault committed Nov 13, 2013
1 parent df08e5b commit 346268e9e4700ae64bb3b0b1d2472115289bd9ec
Showing with 586 additions and 94 deletions.
  1. +24 −4 mapgml.c
  2. +239 −4 mapogcfilter.c
  3. +5 −0 mapogcfilter.h
  4. +16 −4 mapows.c
  5. +10 −0 mapproject.c
  6. +254 −73 mapwfs.c
  7. +6 −0 mapwfs11.c
  8. +31 −8 mapwfs20.c
  9. +1 −1 msautotest
View
@@ -1483,6 +1483,7 @@ int msGMLWriteWFSQuery(mapObj *map, FILE *stream, const char *default_namespace_
const char *value;
int featureIdIndex=-1; /* no feature id */
char* srs = NULL;
int bOutputGMLIdOnly = MS_FALSE;
/* setup namespace, a layer can override the default */
namespace_prefix = msOWSLookupMetadata(&(lp->metadata), "OFG", "namespace_prefix");
@@ -1513,7 +1514,13 @@ int msGMLWriteWFSQuery(mapObj *map, FILE *stream, const char *default_namespace_
msSetError(MS_MISCERR, "Unable to populate item and group metadata structures", "msGMLWriteWFSQuery()");
return MS_FAILURE;
}
if( bGetPropertyValueRequest )
{
const char* value = msOWSLookupMetadata(&(lp->metadata), "G", "include_items");
if( value != NULL && strcmp(value, "@gml:id") == 0 )
bOutputGMLIdOnly = MS_TRUE;
}
if (namespace_prefix) {
layerName = (char *) msSmallMalloc(strlen(namespace_prefix)+strlen(lp->name)+2);
@@ -1557,6 +1564,22 @@ int msGMLWriteWFSQuery(mapObj *map, FILE *stream, const char *default_namespace_
msProjectShape(&lp->projection, &map->projection, &shape);
#endif
if(featureIdIndex != -1) {
pszFID = (char*) msSmallMalloc( strlen(lp->name) + 1 + strlen(shape.values[featureIdIndex]) + 1 );
sprintf(pszFID, "%s.%s", lp->name, shape.values[featureIdIndex]);
}
else
pszFID = msStrdup("");
if( bOutputGMLIdOnly )
{
msIO_fprintf(stream, " <wfs:member>%s</wfs:member>\n", pszFID);
msFree(pszFID);
msFreeShape(&shape); /* init too */
continue;
}
/*
** start this feature
*/
@@ -1567,8 +1590,6 @@ int msGMLWriteWFSQuery(mapObj *map, FILE *stream, const char *default_namespace_
if(msIsXMLTagValid(layerName) == MS_FALSE)
msIO_fprintf(stream, "<!-- WARNING: The value '%s' is not valid in a XML tag context. -->\n", layerName);
if(featureIdIndex != -1) {
pszFID = (char*) msSmallMalloc( strlen(lp->name) + 1 + strlen(shape.values[featureIdIndex]) + 1 );
sprintf(pszFID, "%s.%s", lp->name, shape.values[featureIdIndex]);
if( !bGetPropertyValueRequest )
{
if(outputformat == OWS_GML2)
@@ -1577,7 +1598,6 @@ int msGMLWriteWFSQuery(mapObj *map, FILE *stream, const char *default_namespace_
msIO_fprintf(stream, " <%s gml:id=\"%s\">\n", layerName, pszFID);
}
} else {
pszFID = msStrdup("");
if( !bGetPropertyValueRequest )
msIO_fprintf(stream, " <%s>\n", layerName);
}
View
@@ -1428,6 +1428,28 @@ void FLTInsertElementInNode(FilterEncodingNode *psFilterNode,
psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED;
}
else if (strcasecmp(psXMLNode->pszValue, "PropertyIsNull") == 0) {
const char* pszPropertyName = FLTGetPropertyName(psXMLNode);
if( pszPropertyName != NULL )
{
psFilterNode->psLeftNode = FLTCreateFilterEncodingNode();
psFilterNode->psLeftNode->pszValue = msStrdup(pszPropertyName);
psFilterNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME;
} else
psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED;
}
else if (strcasecmp(psXMLNode->pszValue, "PropertyIsNil") == 0) {
const char* pszPropertyName = FLTGetPropertyName(psXMLNode);
if( pszPropertyName != NULL )
{
psFilterNode->psLeftNode = FLTCreateFilterEncodingNode();
psFilterNode->psLeftNode->pszValue = msStrdup(pszPropertyName);
psFilterNode->psLeftNode->eType = FILTER_NODE_TYPE_PROPERTYNAME;
} else
psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED;
}
}
/* -------------------------------------------------------------------- */
/* FeatureId Filter */
@@ -1598,7 +1620,9 @@ int FLTIsComparisonFilterType(const char *pszValue)
if (pszValue) {
if (FLTIsBinaryComparisonFilterType(pszValue) ||
strcasecmp(pszValue, "PropertyIsLike") == 0 ||
strcasecmp(pszValue, "PropertyIsBetween") == 0)
strcasecmp(pszValue, "PropertyIsBetween") == 0 ||
strcasecmp(pszValue, "PropertyIsNull") == 0 ||
strcasecmp(pszValue, "PropertyIsNil") == 0)
return MS_TRUE;
}
@@ -2137,7 +2161,12 @@ char *FLTGetSQLExpression(FilterEncodingNode *psFilterNode, layerObj *lp)
pszEscapedStr = msLayerEscapeSQLParam(lp, pszId);
if (bString)
snprintf(szTmp, sizeof(szTmp), "(%s = '%s')" , pszAttribute, pszEscapedStr);
{
if( lp->connectiontype == MS_OGR || lp->connectiontype == MS_POSTGIS )
snprintf(szTmp, sizeof(szTmp), "(CAST(%s AS CHARACTER(255)) = '%s')" , pszAttribute, pszEscapedStr);
else
snprintf(szTmp, sizeof(szTmp), "(%s = '%s')" , pszAttribute, pszEscapedStr);
}
else
snprintf(szTmp, sizeof(szTmp), "(%s = %s)" , pszAttribute, pszEscapedStr);
@@ -3330,7 +3359,8 @@ void FLTDoAxisSwappingIfNecessary(FilterEncodingNode *psFilterNode,
static void FLTReplacePropertyName(FilterEncodingNode *psFilterNode,
const char *pszOldName, char *pszNewName)
const char *pszOldName,
const char *pszNewName)
{
if (psFilterNode && pszOldName && pszNewName) {
if (psFilterNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) {
@@ -3356,6 +3386,17 @@ static void FLTStripNameSpacesFromPropertyName(FilterEncodingNode *psFilterNode)
int n=0;
if (psFilterNode) {
if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON &&
(strcmp(psFilterNode->pszValue, "PropertyIsNull") == 0 ||
strcmp(psFilterNode->pszValue, "PropertyIsNil") == 0) &&
psFilterNode->psLeftNode != NULL &&
psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_PROPERTYNAME &&
strcmp(psFilterNode->psLeftNode->pszValue, "gml:name") == 0 )
{
return;
}
if (psFilterNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) {
if (psFilterNode->pszValue &&
strstr(psFilterNode->pszValue, ":")) {
@@ -3382,6 +3423,7 @@ static void FLTRemoveGroupName(FilterEncodingNode *psFilterNode,
int i;
if (psFilterNode) {
if (psFilterNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) {
if( psFilterNode->pszValue != NULL )
{
@@ -3410,6 +3452,7 @@ static void FLTRemoveGroupName(FilterEncodingNode *psFilterNode,
}
}
}
if (psFilterNode->psLeftNode)
FLTRemoveGroupName(psFilterNode->psLeftNode, groupList);
if (psFilterNode->psRightNode)
@@ -3443,7 +3486,7 @@ void FLTPreParseFilterForAliasAndGroup(FilterEncodingNode *psFilterNode,
if (msLayerOpen(lp) == MS_SUCCESS && msLayerGetItems(lp) == MS_SUCCESS) {
/* Remove group names from property names if using groupname/itemname syntax */
gmlGroupListObj* groupList = msGMLGetGroups(lp, "G");
gmlGroupListObj* groupList = msGMLGetGroups(lp, namespaces);
if( groupList && groupList->numgroups > 0 )
FLTRemoveGroupName(psFilterNode, groupList);
msGMLFreeGroups(groupList);
@@ -3519,6 +3562,198 @@ int FLTCheckFeatureIdFilters(FilterEncodingNode *psFilterNode,
return status;
}
/************************************************************************/
/* FLTCheckInvalidOperand */
/* */
/* Check that the operand of a comparison operator is valid */
/* Currently only detects use of boundedBy in a binary comparison */
/************************************************************************/
int FLTCheckInvalidOperand(FilterEncodingNode *psFilterNode)
{
int status = MS_SUCCESS;
if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON &&
psFilterNode->psLeftNode != NULL &&
psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_PROPERTYNAME)
{
if( strcmp(psFilterNode->psLeftNode->pszValue, "boundedBy") == 0 )
{
msSetError(MS_MISCERR, "Operand '%s' is invalid in comparison.",
"FLTCheckInvalidOperand()", psFilterNode->psLeftNode->pszValue);
return MS_FAILURE;
}
}
if (psFilterNode->psLeftNode)
{
status = FLTCheckInvalidOperand(psFilterNode->psLeftNode);
if( status == MS_SUCCESS )
{
if (psFilterNode->psRightNode)
status = FLTCheckInvalidOperand(psFilterNode->psRightNode);
}
}
return status;
}
/************************************************************************/
/* FLTCheckInvalidProperty */
/* */
/* Check that property names are known */
/************************************************************************/
int FLTCheckInvalidProperty(FilterEncodingNode *psFilterNode,
mapObj *map, int i)
{
int status = MS_SUCCESS;
if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON &&
psFilterNode->psLeftNode != NULL &&
psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_PROPERTYNAME)
{
layerObj* lp;
int layerWasOpened;
int bFound = MS_FALSE;
if ((strcmp(psFilterNode->pszValue, "PropertyIsNull") == 0 ||
strcmp(psFilterNode->pszValue, "PropertyIsNil") == 0) &&
strcmp(psFilterNode->psLeftNode->pszValue, "gml:name") == 0 )
{
return MS_SUCCESS;
}
lp = GET_LAYER(map, i);
layerWasOpened = msLayerIsOpen(lp);
if ((layerWasOpened || msLayerOpen(lp) == MS_SUCCESS)
&& msLayerGetItems(lp) == MS_SUCCESS) {
int i;
gmlItemListObj* items = msGMLGetItems(lp, "G");
for(i=0; i<items->numitems; i++) {
if (!items->items[i].name || strlen(items->items[i].name) <= 0 ||
!items->items[i].visible)
continue;
if (strcasecmp(items->items[i].name, psFilterNode->psLeftNode->pszValue) == 0) {
bFound = MS_TRUE;
break;
}
}
msGMLFreeItems(items);
}
if (!layerWasOpened) /* do not close the layer if it has been opened somewhere else (paging?) */
msLayerClose(lp);
if( !bFound )
{
msSetError(MS_MISCERR, "Property '%s' is unknown.",
"FLTCheckInvalidProperty()", psFilterNode->psLeftNode->pszValue);
return MS_FAILURE;
}
}
if (psFilterNode->psLeftNode)
{
status = FLTCheckInvalidProperty(psFilterNode->psLeftNode, map, i);
if( status == MS_SUCCESS )
{
if (psFilterNode->psRightNode)
status = FLTCheckInvalidProperty(psFilterNode->psRightNode, map, i);
}
}
return status;
}
/************************************************************************/
/* FLTSimplify */
/* */
/* Simplify the expression by removing parts that evaluate to */
/* constants. */
/* The passed psFilterNode is potentially consumed by the function */
/* and replaced by the returned value. */
/* If the function returns NULL, *pnEvaluation = 0 means that */
/* the filter evaluates to FALSE, or 1 that it evaluates to TRUE */
/************************************************************************/
FilterEncodingNode* FLTSimplify(FilterEncodingNode *psFilterNode,
int* pnEvaluation)
{
*pnEvaluation = -1;
/* There are no nullable or nillable property in WFS currently */
if( psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON &&
(strcmp(psFilterNode->pszValue, "PropertyIsNull") == 0 ||
strcmp(psFilterNode->pszValue, "PropertyIsNil") == 0 ) &&
psFilterNode->psLeftNode != NULL &&
psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_PROPERTYNAME )
{
*pnEvaluation = 0;
FLTFreeFilterEncodingNode(psFilterNode);
return NULL;
}
if( psFilterNode->eType == FILTER_NODE_TYPE_LOGICAL &&
strcasecmp(psFilterNode->pszValue, "NOT") == 0 &&
psFilterNode->psLeftNode != NULL )
{
int nEvaluation;
psFilterNode->psLeftNode = FLTSimplify(psFilterNode->psLeftNode,
&nEvaluation);
if( psFilterNode->psLeftNode == NULL )
{
*pnEvaluation = 1 - nEvaluation;
FLTFreeFilterEncodingNode(psFilterNode);
return NULL;
}
}
if( psFilterNode->eType == FILTER_NODE_TYPE_LOGICAL &&
(strcasecmp(psFilterNode->pszValue, "AND") == 0 ||
strcasecmp(psFilterNode->pszValue, "OR") == 0) &&
psFilterNode->psLeftNode != NULL &&
psFilterNode->psRightNode != NULL )
{
FilterEncodingNode* psOtherNode;
int nEvaluation;
int nExpectedValForFastExit;
psFilterNode->psLeftNode = FLTSimplify(psFilterNode->psLeftNode,
&nEvaluation);
if( strcasecmp(psFilterNode->pszValue, "AND") == 0 )
nExpectedValForFastExit = 0;
else
nExpectedValForFastExit = 1;
if( psFilterNode->psLeftNode == NULL )
{
if( nEvaluation == nExpectedValForFastExit )
{
*pnEvaluation = nEvaluation;
FLTFreeFilterEncodingNode(psFilterNode);
return NULL;
}
psOtherNode = psFilterNode->psRightNode;
psFilterNode->psRightNode = NULL;
FLTFreeFilterEncodingNode(psFilterNode);
return FLTSimplify(psOtherNode, pnEvaluation);
}
psFilterNode->psRightNode = FLTSimplify(psFilterNode->psRightNode,
&nEvaluation);
if( psFilterNode->psRightNode == NULL )
{
if( nEvaluation == nExpectedValForFastExit )
{
*pnEvaluation = nEvaluation;
FLTFreeFilterEncodingNode(psFilterNode);
return NULL;
}
psOtherNode = psFilterNode->psLeftNode;
psFilterNode->psLeftNode = NULL;
FLTFreeFilterEncodingNode(psFilterNode);
return FLTSimplify(psOtherNode, pnEvaluation);
}
}
return psFilterNode;
}
#ifdef USE_LIBXML2
View
@@ -143,6 +143,11 @@ void FLTPreParseFilterForAliasAndGroup(FilterEncodingNode *psFilterNode,
mapObj *map, int i, const char *namespaces);
int FLTCheckFeatureIdFilters(FilterEncodingNode *psFilterNode,
mapObj *map, int i);
int FLTCheckInvalidOperand(FilterEncodingNode *psFilterNode);
int FLTCheckInvalidProperty(FilterEncodingNode *psFilterNode,
mapObj *map, int i);
FilterEncodingNode* FLTSimplify(FilterEncodingNode *psFilterNode,
int* pnEvaluation);
#endif
Oops, something went wrong.

0 comments on commit 346268e

Please sign in to comment.