Ejemplo n.º 1
0
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;
}
Ejemplo n.º 3
0
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;
}