CPLString WFS_TurnSQLFilterToOGCFilter( const swq_expr_node* poExpr, OGRDataSource* poDS, OGRFeatureDefn* poFDefn, int nVersion, int bPropertyIsNotEqualToSupported, int bUseFeatureId, int bGmlObjectIdNeedsGMLPrefix, const char* pszNSPrefix, int* pbOutNeedsNullCheck ) { CPLString osFilter; /* If the filter is only made of querying one or several gml_id */ /* (with OR operator), we turn this to <GmlObjectId> list */ if (!WFS_ExprDumpGmlObjectIdFilter(osFilter, poExpr, bUseFeatureId, bGmlObjectIdNeedsGMLPrefix, nVersion)) { ExprDumpFilterOptions sOptions; sOptions.nVersion = nVersion; sOptions.bPropertyIsNotEqualToSupported = bPropertyIsNotEqualToSupported; sOptions.bOutNeedsNullCheck = FALSE; sOptions.poDS = poDS; sOptions.poFDefn = poFDefn; sOptions.nUniqueGeomGMLId = 1; sOptions.poSRS = NULL; sOptions.pszNSPrefix = pszNSPrefix; osFilter = ""; if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr, TRUE, &sOptions)) osFilter = ""; /*else CPLDebug("WFS", "Filter %s", osFilter.c_str());*/ *pbOutNeedsNullCheck = sOptions.bOutNeedsNullCheck; } return osFilter; }
CPLString WFS_TurnSQLFilterToOGCFilter( const char * pszFilter, OGRFeatureDefn* poFDefn, int nVersion, int bPropertyIsNotEqualToSupported, int bUseFeatureId, int bGmlObjectIdNeedsGMLPrefix, int* pbOutNeedsNullCheck ) { char** papszTokens = WFS_ExprTokenize(pszFilter); if (papszTokens == NULL) return ""; char** papszTokens2 = papszTokens; ExprBuildContext sBuildContext; sBuildContext.bExpectVarName = TRUE; sBuildContext.bExpectComparisonOperator = FALSE; sBuildContext.bExpectLogicalOperator = FALSE; sBuildContext.bExpectValue = FALSE; sBuildContext.nParenthesisLevel = 0; Expr* expr = WFS_ExprBuildInternal(&papszTokens2, &sBuildContext); CSLDestroy(papszTokens); if (expr == NULL) return ""; CPLString osFilter; /* If the filter is only made of querying one or several gml_id */ /* (with OR operator), we turn this to <GmlObjectId> list */ if (!WFS_ExprDumpGmlObjectIdFilter(osFilter, expr, bUseFeatureId, bGmlObjectIdNeedsGMLPrefix, nVersion)) { ExprDumpFilterOptions sOptions; sOptions.nVersion = nVersion; sOptions.bPropertyIsNotEqualToSupported = bPropertyIsNotEqualToSupported; sOptions.bOutNeedsNullCheck = FALSE; sOptions.poFDefn = poFDefn; osFilter = ""; if (!WFS_ExprDumpAsOGCFilter(osFilter, expr, TRUE, &sOptions)) osFilter = ""; *pbOutNeedsNullCheck = sOptions.bOutNeedsNullCheck; } WFS_ExprFree(expr); return osFilter; }
static int WFS_ExprDumpAsOGCFilter(CPLString& osFilter, const swq_expr_node* poExpr, int bExpectBinary, ExprDumpFilterOptions* psOptions) { if( poExpr->eNodeType == SNT_COLUMN ) { if (bExpectBinary) return FALSE; /* Special fields not understood by server */ if (EQUAL(poExpr->string_value, "gml_id") || EQUAL(poExpr->string_value, "FID") || EQUAL(poExpr->string_value, "OGR_GEOMETRY") || EQUAL(poExpr->string_value, "OGR_GEOM_WKT") || EQUAL(poExpr->string_value, "OGR_GEOM_AREA") || EQUAL(poExpr->string_value, "OGR_STYLE")) { CPLDebug("WFS", "Attribute refers to a OGR special field. Cannot use server-side filtering"); return FALSE; } const char* pszFieldname = NULL; int nIndex; int bSameTable = psOptions->poFDefn != NULL && ( poExpr->table_name == NULL || EQUAL(poExpr->table_name, psOptions->poFDefn->GetName()) ); if( bSameTable ) { if( (nIndex = psOptions->poFDefn->GetFieldIndex(poExpr->string_value)) >= 0 ) { pszFieldname = psOptions->poFDefn->GetFieldDefn(nIndex)->GetNameRef(); } else if( (nIndex = psOptions->poFDefn->GetGeomFieldIndex(poExpr->string_value)) >= 0 ) { pszFieldname = psOptions->poFDefn->GetGeomFieldDefn(nIndex)->GetNameRef(); } } else if( psOptions->poDS != NULL ) { OGRLayer* poLayer = psOptions->poDS->GetLayerByName(poExpr->table_name); if( poLayer ) { OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn(); if( (nIndex = poFDefn->GetFieldIndex(poExpr->string_value)) >= 0 ) { pszFieldname = CPLSPrintf("%s/%s", poLayer->GetName(), poFDefn->GetFieldDefn(nIndex)->GetNameRef()); } else if( (nIndex = poFDefn->GetGeomFieldIndex(poExpr->string_value)) >= 0 ) { pszFieldname = CPLSPrintf("%s/%s", poLayer->GetName(), poFDefn->GetGeomFieldDefn(nIndex)->GetNameRef()); } } } if( psOptions->poFDefn == NULL && psOptions->poDS == NULL ) pszFieldname = poExpr->string_value; if( pszFieldname == NULL ) { if( poExpr->table_name != NULL ) CPLDebug("WFS", "Field \"%s\".\"%s\" unknown. Cannot use server-side filtering", poExpr->table_name, poExpr->string_value); else CPLDebug("WFS", "Field \"%s\" unknown. Cannot use server-side filtering", poExpr->string_value); return FALSE; } if (psOptions->nVersion >= 200) osFilter += CPLSPrintf("<%sValueReference>", psOptions->pszNSPrefix); else osFilter += CPLSPrintf("<%sPropertyName>", psOptions->pszNSPrefix); char* pszFieldnameXML = CPLEscapeString(pszFieldname, -1, CPLES_XML); osFilter += pszFieldnameXML; CPLFree(pszFieldnameXML); if (psOptions->nVersion >= 200) osFilter += CPLSPrintf("</%sValueReference>", psOptions->pszNSPrefix); else osFilter += CPLSPrintf("</%sPropertyName>", psOptions->pszNSPrefix); return TRUE; } if( poExpr->eNodeType == SNT_CONSTANT ) { if (bExpectBinary) return FALSE; osFilter += CPLSPrintf("<%sLiteral>", psOptions->pszNSPrefix); if( !WFS_ExprDumpRawLitteral(osFilter, poExpr) ) return FALSE; osFilter += CPLSPrintf("</%sLiteral>", psOptions->pszNSPrefix); return TRUE; } if( poExpr->eNodeType != SNT_OPERATION ) return FALSE; /* shouldn't happen */ if( poExpr->nOperation == SWQ_NOT ) { osFilter += CPLSPrintf("<%sNot>", psOptions->pszNSPrefix); if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], TRUE, psOptions)) return FALSE; osFilter += CPLSPrintf("</%sNot>", psOptions->pszNSPrefix); return TRUE; } if( poExpr->nOperation == SWQ_LIKE ) { CPLString osVal; char ch; char firstCh = 0; int i; if (psOptions->nVersion == 100) osFilter += CPLSPrintf("<%sPropertyIsLike wildCard='*' singleChar='_' escape='!'>", psOptions->pszNSPrefix); else osFilter += CPLSPrintf("<%sPropertyIsLike wildCard='*' singleChar='_' escapeChar='!'>", psOptions->pszNSPrefix); if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], FALSE, psOptions)) return FALSE; if (poExpr->papoSubExpr[1]->eNodeType != SNT_CONSTANT && poExpr->papoSubExpr[1]->field_type != SWQ_STRING) return FALSE; osFilter += CPLSPrintf("<%sLiteral>", psOptions->pszNSPrefix); /* Escape value according to above special characters */ /* For URL compatibility reason, we remap the OGR SQL '%' wildchard into '*' */ i = 0; ch = poExpr->papoSubExpr[1]->string_value[i]; if (ch == '\'' || ch == '"') { firstCh = ch; i ++; } for(;(ch = poExpr->papoSubExpr[1]->string_value[i]) != '\0';i++) { if (ch == '%') osVal += "*"; else if (ch == '!') osVal += "!!"; else if (ch == '*') osVal += "!*"; else if (ch == firstCh && poExpr->papoSubExpr[1]->string_value[i + 1] == 0) break; else { char ach[2]; ach[0] = ch; ach[1] = 0; osVal += ach; } } char* pszXML = CPLEscapeString(osVal, -1, CPLES_XML); osFilter += pszXML; CPLFree(pszXML); osFilter += CPLSPrintf("</%sLiteral>", psOptions->pszNSPrefix); osFilter += CPLSPrintf("</%sPropertyIsLike>", psOptions->pszNSPrefix); return TRUE; } if( poExpr->nOperation == SWQ_ISNULL ) { osFilter += CPLSPrintf("<%sPropertyIsNull>", psOptions->pszNSPrefix); if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], FALSE, psOptions)) return FALSE; osFilter += CPLSPrintf("</%sPropertyIsNull>", psOptions->pszNSPrefix); psOptions->bOutNeedsNullCheck = TRUE; return TRUE; } if( poExpr->nOperation == SWQ_EQ || poExpr->nOperation == SWQ_NE || poExpr->nOperation == SWQ_LE || poExpr->nOperation == SWQ_LT || poExpr->nOperation == SWQ_GE || poExpr->nOperation == SWQ_GT ) { int nOperation = poExpr->nOperation; int bAddClosingNot = FALSE; if (!psOptions->bPropertyIsNotEqualToSupported && nOperation == SWQ_NE) { osFilter += CPLSPrintf("<%sNot>", psOptions->pszNSPrefix); nOperation = SWQ_EQ; bAddClosingNot = TRUE; } const char* pszName = NULL; switch(nOperation) { case SWQ_EQ: pszName = "PropertyIsEqualTo"; break; case SWQ_NE: pszName = "PropertyIsNotEqualTo"; break; case SWQ_LE: pszName = "PropertyIsLessThanOrEqualTo"; break; case SWQ_LT: pszName = "PropertyIsLessThan"; break; case SWQ_GE: pszName = "PropertyIsGreaterThanOrEqualTo"; break; case SWQ_GT: pszName = "PropertyIsGreaterThan"; break; default: break; } osFilter += "<"; osFilter += psOptions->pszNSPrefix; osFilter += pszName; osFilter += ">"; if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], FALSE, psOptions)) return FALSE; if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[1], FALSE, psOptions)) return FALSE; osFilter += "</"; osFilter += psOptions->pszNSPrefix; osFilter += pszName; osFilter += ">"; if (bAddClosingNot) osFilter += CPLSPrintf("</%sNot>", psOptions->pszNSPrefix); return TRUE; } if( poExpr->nOperation == SWQ_AND || poExpr->nOperation == SWQ_OR ) { const char* pszName = (poExpr->nOperation == SWQ_AND) ? "And" : "Or"; osFilter += "<"; osFilter += psOptions->pszNSPrefix; osFilter += pszName; osFilter += ">"; if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], TRUE, psOptions)) return FALSE; if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[1], TRUE, psOptions)) return FALSE; osFilter += "</"; osFilter += psOptions->pszNSPrefix; osFilter += pszName; osFilter += ">"; return TRUE; } if( poExpr->nOperation == SWQ_CUSTOM_FUNC && EQUAL(poExpr->string_value, "ST_MakeEnvelope") ) { OGRSpatialReference oSRS; const char* pszSRSName = WFS_ExprGetSRSName( poExpr, 4, psOptions, oSRS ); int bAxisSwap = FALSE; osFilter += "<gml:Envelope"; if( pszSRSName ) { osFilter += " srsName=\""; osFilter += pszSRSName; osFilter += "\""; if( oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting() ) bAxisSwap = TRUE; } osFilter += ">"; osFilter += "<gml:lowerCorner>"; if (!WFS_ExprDumpRawLitteral(osFilter, poExpr->papoSubExpr[(bAxisSwap) ? 1 : 0])) return FALSE; osFilter += " "; if (!WFS_ExprDumpRawLitteral(osFilter, poExpr->papoSubExpr[(bAxisSwap) ? 0 : 1])) return FALSE; osFilter += "</gml:lowerCorner>"; osFilter += "<gml:upperCorner>"; if (!WFS_ExprDumpRawLitteral(osFilter, poExpr->papoSubExpr[(bAxisSwap) ? 3 : 2])) return FALSE; osFilter += " "; if (!WFS_ExprDumpRawLitteral(osFilter, poExpr->papoSubExpr[(bAxisSwap) ? 2 : 3])) return FALSE; osFilter += "</gml:upperCorner>"; osFilter += "</gml:Envelope>"; return TRUE; } if( poExpr->nOperation == SWQ_CUSTOM_FUNC && EQUAL(poExpr->string_value, "ST_GeomFromText") ) { OGRSpatialReference oSRS; const char* pszSRSName = WFS_ExprGetSRSName( poExpr, 1, psOptions, oSRS ); OGRGeometry* poGeom = NULL; char* pszWKT = (char*)poExpr->papoSubExpr[0]->string_value; OGRGeometryFactory::createFromWkt(&pszWKT, NULL, &poGeom); char** papszOptions = NULL; papszOptions = CSLSetNameValue(papszOptions, "FORMAT", "GML3"); if( pszSRSName != NULL ) { if( oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting() ) { OGR_SRSNode *poGEOGCS = oSRS.GetAttrNode( "GEOGCS" ); if( poGEOGCS != NULL ) poGEOGCS->StripNodes( "AXIS" ); OGR_SRSNode *poPROJCS = oSRS.GetAttrNode( "PROJCS" ); if (poPROJCS != NULL && oSRS.EPSGTreatsAsNorthingEasting()) poPROJCS->StripNodes( "AXIS" ); } if( EQUALN(pszSRSName, "urn:ogc:def:crs:EPSG::", strlen("urn:ogc:def:crs:EPSG::")) ) papszOptions = CSLSetNameValue(papszOptions, "GML3_LONGSRS", "YES"); else papszOptions = CSLSetNameValue(papszOptions, "GML3_LONGSRS", "NO"); poGeom->assignSpatialReference(&oSRS); } papszOptions = CSLSetNameValue(papszOptions, "GMLID", CPLSPrintf("id%d", psOptions->nUniqueGeomGMLId ++)); char* pszGML = OGR_G_ExportToGMLEx( (OGRGeometryH)poGeom, papszOptions ); osFilter += pszGML; CSLDestroy(papszOptions); delete poGeom; CPLFree(pszGML); return TRUE; } if( poExpr->nOperation == SWQ_CUSTOM_FUNC ) { const char* pszName = EQUAL(poExpr->string_value, "ST_Equals") ? "Equals" : EQUAL(poExpr->string_value, "ST_Disjoint") ? "Disjoint" : EQUAL(poExpr->string_value, "ST_Touches") ? "Touches" : EQUAL(poExpr->string_value, "ST_Contains") ? "Contains" : EQUAL(poExpr->string_value, "ST_Intersects") ? "Intersects" : EQUAL(poExpr->string_value, "ST_Within") ? "Within" : EQUAL(poExpr->string_value, "ST_Crosses") ? "Crosses" : EQUAL(poExpr->string_value, "ST_Overlaps") ? "Overlaps" : EQUAL(poExpr->string_value, "ST_DWithin") ? "DWithin" : EQUAL(poExpr->string_value, "ST_Beyond") ? "Beyond" : NULL; if( pszName == NULL ) return FALSE; osFilter += "<"; osFilter += psOptions->pszNSPrefix; osFilter += pszName; osFilter += ">"; for(int i=0;i<2;i++) { if( i == 1 && poExpr->papoSubExpr[0]->eNodeType == SNT_COLUMN && poExpr->papoSubExpr[1]->eNodeType == SNT_OPERATION && poExpr->papoSubExpr[1]->nOperation == SWQ_CUSTOM_FUNC && (EQUAL(poExpr->papoSubExpr[1]->string_value, "ST_GeomFromText") || EQUAL(poExpr->papoSubExpr[1]->string_value, "ST_MakeEnvelope")) ) { int bSameTable = psOptions->poFDefn != NULL && ( poExpr->papoSubExpr[0]->table_name == NULL || EQUAL(poExpr->papoSubExpr[0]->table_name, psOptions->poFDefn->GetName()) ); if( bSameTable ) { int nIndex; if( (nIndex = psOptions->poFDefn->GetGeomFieldIndex(poExpr->papoSubExpr[0]->string_value)) >= 0 ) { psOptions->poSRS = psOptions->poFDefn->GetGeomFieldDefn(nIndex)->GetSpatialRef(); } } else if( psOptions->poDS != NULL ) { OGRLayer* poLayer = psOptions->poDS->GetLayerByName(poExpr->papoSubExpr[0]->table_name); if( poLayer ) { OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn(); int nIndex; if( (nIndex = poFDefn->GetGeomFieldIndex(poExpr->papoSubExpr[0]->string_value)) >= 0 ) { psOptions->poSRS = poFDefn->GetGeomFieldDefn(nIndex)->GetSpatialRef(); } } } } int bRet = WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[i], FALSE, psOptions); psOptions->poSRS = NULL; if( !bRet ) return FALSE; } if( poExpr->nSubExprCount > 2 ) { osFilter += CPLSPrintf("<%sDistance unit=\"m\">", psOptions->pszNSPrefix); if (!WFS_ExprDumpRawLitteral(osFilter, poExpr->papoSubExpr[2]) ) return FALSE; osFilter += CPLSPrintf("</%sDistance>", psOptions->pszNSPrefix); } osFilter += "</"; osFilter += psOptions->pszNSPrefix; osFilter += pszName; osFilter += ">"; return TRUE; } return FALSE; }
static int WFS_ExprDumpAsOGCFilter(CPLString& osFilter, const Expr* expr, int bExpectBinary, ExprDumpFilterOptions* psOptions) { switch(expr->eType) { case TOKEN_VAR_NAME: { if (bExpectBinary) return FALSE; /* Special fields not understood by server */ if (EQUAL(expr->pszVal, "gml_id") || EQUAL(expr->pszVal, "FID") || EQUAL(expr->pszVal, "OGR_GEOMETRY") || EQUAL(expr->pszVal, "OGR_GEOM_WKT") || EQUAL(expr->pszVal, "OGR_GEOM_AREA") || EQUAL(expr->pszVal, "OGR_STYLE")) { CPLDebug("WFS", "Attribute refers to a OGR special field. Cannot use server-side filtering"); return FALSE; } const char* pszFieldname; CPLString osVal; if (expr->pszVal[0] == '\'' || expr->pszVal[0] == '"') { osVal = expr->pszVal + 1; osVal.resize(osVal.size() - 1); pszFieldname = osVal.c_str(); } else pszFieldname = expr->pszVal; if (psOptions->poFDefn->GetFieldIndex(pszFieldname) == -1) { CPLDebug("WFS", "Field '%s' unknown. Cannot use server-side filtering", pszFieldname); return FALSE; } if (psOptions->nVersion >= 200) osFilter += "<ValueReference>"; else osFilter += "<PropertyName>"; char* pszFieldnameXML = CPLEscapeString(pszFieldname, -1, CPLES_XML); osFilter += pszFieldnameXML; CPLFree(pszFieldnameXML); if (psOptions->nVersion >= 200) osFilter += "</ValueReference>"; else osFilter += "</PropertyName>"; break; } case TOKEN_LITERAL: { if (bExpectBinary) return FALSE; const char* pszLiteral; CPLString osVal; if (expr->pszVal[0] == '\'' || expr->pszVal[0] == '"') { osVal = expr->pszVal + 1; osVal.resize(osVal.size() - 1); pszLiteral = osVal.c_str(); } else pszLiteral = expr->pszVal; osFilter += "<Literal>"; char* pszLiteralXML = CPLEscapeString(pszLiteral, -1, CPLES_XML); osFilter += pszLiteralXML; CPLFree(pszLiteralXML); osFilter += "</Literal>"; break; } case TOKEN_NOT: osFilter += "<Not>"; if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, TRUE, psOptions)) return FALSE; osFilter += "</Not>"; break; case TOKEN_LIKE: { CPLString osVal; char ch; char firstCh = 0; int i; if (psOptions->nVersion == 100) osFilter += "<PropertyIsLike wildCard='*' singleChar='_' escape='!'>"; else osFilter += "<PropertyIsLike wildCard='*' singleChar='_' escapeChar='!'>"; if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions)) return FALSE; if (expr->expr2->eType != TOKEN_LITERAL) return FALSE; osFilter += "<Literal>"; /* Escape value according to above special characters */ /* For URL compatibility reason, we remap the OGR SQL '%' wildchard into '*' */ i = 0; ch = expr->expr2->pszVal[i]; if (ch == '\'' || ch == '"') { firstCh = ch; i ++; } for(; (ch = expr->expr2->pszVal[i]) != '\0'; i++) { if (ch == '%') osVal += "*"; else if (ch == '!') osVal += "!!"; else if (ch == '*') osVal += "!*"; else if (ch == firstCh && expr->expr2->pszVal[i + 1] == 0) break; else { char ach[2]; ach[0] = ch; ach[1] = 0; osVal += ach; } } osFilter += osVal; osFilter += "</Literal>"; osFilter += "</PropertyIsLike>"; break; } case TOKEN_EQUAL: case TOKEN_NOT_EQUAL: case TOKEN_LESSER_OR_EQUAL: case TOKEN_LESSER: case TOKEN_GREATER_OR_EQUAL: case TOKEN_GREATER: { if (expr->eType == TOKEN_EQUAL && expr->expr2->eType == TOKEN_LITERAL && EQUAL(expr->expr2->pszVal, "NULL")) { osFilter += "<PropertyIsNull>"; if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions)) return FALSE; osFilter += "</PropertyIsNull>"; psOptions->bOutNeedsNullCheck = TRUE; break; } if (expr->eType == TOKEN_NOT_EQUAL && expr->expr2->eType == TOKEN_LITERAL && EQUAL(expr->expr2->pszVal, "NULL")) { osFilter += "<Not><PropertyIsNull>"; if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions)) return FALSE; osFilter += "</PropertyIsNull></Not>"; psOptions->bOutNeedsNullCheck = TRUE; break; } TokenType eType = expr->eType; int bAddClosingNot = FALSE; if (!psOptions->bPropertyIsNotEqualToSupported && eType == TOKEN_NOT_EQUAL) { osFilter += "<Not>"; eType = TOKEN_EQUAL; bAddClosingNot = TRUE; } const char* pszName = NULL; switch(eType) { case TOKEN_EQUAL: pszName = "PropertyIsEqualTo"; break; case TOKEN_NOT_EQUAL: pszName = "PropertyIsNotEqualTo"; break; case TOKEN_LESSER_OR_EQUAL: pszName = "PropertyIsLessThanOrEqualTo"; break; case TOKEN_LESSER: pszName = "PropertyIsLessThan"; break; case TOKEN_GREATER_OR_EQUAL: pszName = "PropertyIsGreaterThanOrEqualTo"; break; case TOKEN_GREATER: pszName = "PropertyIsGreaterThan"; break; default: break; } osFilter += "<"; osFilter += pszName; osFilter += ">"; if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions)) return FALSE; if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr2, FALSE, psOptions)) return FALSE; osFilter += "</"; osFilter += pszName; osFilter += ">"; if (bAddClosingNot) osFilter += "</Not>"; break; } case TOKEN_AND: case TOKEN_OR: { const char* pszName = (expr->eType == TOKEN_AND) ? "And" : "Or"; osFilter += "<"; osFilter += pszName; osFilter += ">"; if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, TRUE, psOptions)) return FALSE; if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr2, TRUE, psOptions)) return FALSE; osFilter += "</"; osFilter += pszName; osFilter += ">"; break; } default: return FALSE; } return TRUE; }