Skip to content

Commit

Permalink
WFS 2.0: various fixes and enhancements to pass wfs-2.0-r12-SNAPSHOT …
Browse files Browse the repository at this point in the history
…CITE tests (Simple WFS and Basic WFS conformance levels)
  • Loading branch information
rouault committed Nov 13, 2013
1 parent df08e5b commit 346268e
Show file tree
Hide file tree
Showing 9 changed files with 586 additions and 94 deletions.
28 changes: 24 additions & 4 deletions mapgml.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
*/
Expand All @@ -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)
Expand All @@ -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);
}
Expand Down
243 changes: 239 additions & 4 deletions mapogcfilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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) {
Expand All @@ -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, ":")) {
Expand All @@ -3382,6 +3423,7 @@ static void FLTRemoveGroupName(FilterEncodingNode *psFilterNode,
int i;

if (psFilterNode) {

if (psFilterNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) {
if( psFilterNode->pszValue != NULL )
{
Expand Down Expand Up @@ -3410,6 +3452,7 @@ static void FLTRemoveGroupName(FilterEncodingNode *psFilterNode,
}
}
}

if (psFilterNode->psLeftNode)
FLTRemoveGroupName(psFilterNode->psLeftNode, groupList);
if (psFilterNode->psRightNode)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions mapogcfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading

0 comments on commit 346268e

Please sign in to comment.