Пример #1
0
char* GML_GetSRSName(const OGRSpatialReference* poSRS, int bLongSRS, int *pbCoordSwap)
{
    *pbCoordSwap = FALSE;
    if (poSRS == NULL)
        return CPLStrdup("");

    const char* pszAuthName = NULL;
    const char* pszAuthCode = NULL;
    const char* pszTarget = NULL;

    if (poSRS->IsProjected())
        pszTarget = "PROJCS";
    else
        pszTarget = "GEOGCS";

    char szSrsName[50];
    szSrsName[0] = 0;

    pszAuthName = poSRS->GetAuthorityName( pszTarget );
    if( NULL != pszAuthName )
    {
        if( EQUAL( pszAuthName, "EPSG" ) )
        {
            pszAuthCode = poSRS->GetAuthorityCode( pszTarget );
            if( NULL != pszAuthCode && strlen(pszAuthCode) < 10 )
            {
                if (bLongSRS && !(((OGRSpatialReference*)poSRS)->EPSGTreatsAsLatLong() ||
                                  ((OGRSpatialReference*)poSRS)->EPSGTreatsAsNorthingEasting()))
                {
                    OGRSpatialReference oSRS;
                    if (oSRS.importFromEPSGA(atoi(pszAuthCode)) == OGRERR_NONE)
                    {
                        if (oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting())
                            *pbCoordSwap = TRUE;
                    }
                }

                if (bLongSRS)
                {
                    sprintf( szSrsName, " srsName=\"urn:ogc:def:crs:%s::%s\"",
                        pszAuthName, pszAuthCode );
                }
                else
                {
                    sprintf( szSrsName, " srsName=\"%s:%s\"",
                            pszAuthName, pszAuthCode );
                }
            }
        }
    }

    return CPLStrdup(szSrsName);
}
Пример #2
0
int GML_IsSRSLatLongOrder(const char* pszSRSName)
{
    if (pszSRSName == NULL)
        return FALSE;

    if (strncmp(pszSRSName, "urn:", 4) == 0)
    {
        if (strstr(pszSRSName, ":4326") != NULL)
        {
            /* Shortcut ... */
            return TRUE;
        }
        else
        {
            OGRSpatialReference oSRS;
            if (oSRS.importFromURN(pszSRSName) == OGRERR_NONE)
            {
                if (oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting())
                    return TRUE;
            }
        }
    }
    return FALSE;
}
Пример #3
0
static int OGR2GML3GeometryAppend( const OGRGeometry *poGeometry,
                                   const OGRSpatialReference* poParentSRS,
                                   char **ppszText, int *pnLength,
                                   int *pnMaxLength,
                                   int bIsSubGeometry,
                                   int bLongSRS,
                                   int bLineStringAsCurve,
                                   const char* pszGMLId,
                                   int nSRSDimensionLocFlags,
                                   int bForceLineStringAsLinearRing )

{

/* -------------------------------------------------------------------- */
/*      Check for Spatial Reference System attached to given geometry   */
/* -------------------------------------------------------------------- */

    // Buffer for srsName, srsDimension and gml:id attributes (srsName="..." gml:id="...")
    char szAttributes[256];
    int nAttrsLength = 0;

    szAttributes[0] = 0;

    const OGRSpatialReference* poSRS = NULL;
    if (poParentSRS)
        poSRS = poParentSRS;
    else
        poParentSRS = poSRS = poGeometry->getSpatialReference();

    int bCoordSwap = FALSE;

    if( NULL != poSRS )
    {
        const char* pszAuthName = NULL;
        const char* pszAuthCode = NULL;
        const char* pszTarget = NULL;

        if (poSRS->IsProjected())
            pszTarget = "PROJCS";
        else
            pszTarget = "GEOGCS";

        pszAuthName = poSRS->GetAuthorityName( pszTarget );
        if( NULL != pszAuthName )
        {
            if( EQUAL( pszAuthName, "EPSG" ) )
            {
                pszAuthCode = poSRS->GetAuthorityCode( pszTarget );
                if( NULL != pszAuthCode && strlen(pszAuthCode) < 10 )
                {
                    if (bLongSRS && !(((OGRSpatialReference*)poSRS)->EPSGTreatsAsLatLong() ||
                                      ((OGRSpatialReference*)poSRS)->EPSGTreatsAsNorthingEasting()))
                    {
                        OGRSpatialReference oSRS;
                        if (oSRS.importFromEPSGA(atoi(pszAuthCode)) == OGRERR_NONE)
                        {
                            if (oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting())
                                bCoordSwap = TRUE;
                        }
                    }

                    if (!bIsSubGeometry)
                    {
                        if (bLongSRS)
                        {
                            snprintf( szAttributes, sizeof(szAttributes),
                                      " srsName=\"urn:ogc:def:crs:%s::%s\"",
                                      pszAuthName, pszAuthCode );
                        }
                        else
                        {
                            snprintf( szAttributes, sizeof(szAttributes),
                                      " srsName=\"%s:%s\"",
                                      pszAuthName, pszAuthCode );
                        }

                        nAttrsLength = strlen(szAttributes);
                    }
                }
            }
        }
    }

    if( (nSRSDimensionLocFlags & SRSDIM_LOC_GEOMETRY) != 0 &&
        wkbHasZ(poGeometry->getGeometryType()) )
    {
        strcat(szAttributes, " srsDimension=\"3\"");
        nAttrsLength = strlen(szAttributes);

        nSRSDimensionLocFlags &= ~SRSDIM_LOC_GEOMETRY;
    }

    if (pszGMLId != NULL && nAttrsLength + 9 + strlen(pszGMLId) + 1 < sizeof(szAttributes))
    {
        strcat(szAttributes, " gml:id=\"");
        strcat(szAttributes, pszGMLId);
        strcat(szAttributes, "\"");
        nAttrsLength = strlen(szAttributes);
    }

    OGRwkbGeometryType eType = poGeometry->getGeometryType();
    OGRwkbGeometryType eFType = wkbFlatten(eType);

/* -------------------------------------------------------------------- */
/*      2D Point                                                        */
/* -------------------------------------------------------------------- */
    if( eType == wkbPoint )
    {
        char    szCoordinate[256];
        OGRPoint *poPoint = (OGRPoint *) poGeometry;

        if (bCoordSwap)
            OGRMakeWktCoordinate( szCoordinate,
                           poPoint->getY(), poPoint->getX(), 0.0, 2 );
        else
            OGRMakeWktCoordinate( szCoordinate,
                           poPoint->getX(), poPoint->getY(), 0.0, 2 );

        _GrowBuffer( *pnLength + strlen(szCoordinate) + 60 + nAttrsLength,
                     ppszText, pnMaxLength );

        sprintf( *ppszText + *pnLength,
                "<gml:Point%s><gml:pos>%s</gml:pos></gml:Point>",
                 szAttributes, szCoordinate );

        *pnLength += strlen( *ppszText + *pnLength );
    }
/* -------------------------------------------------------------------- */
/*      3D Point                                                        */
/* -------------------------------------------------------------------- */
    else if( eType == wkbPoint25D )
    {
        char    szCoordinate[256];
        OGRPoint *poPoint = (OGRPoint *) poGeometry;

        if (bCoordSwap)
            OGRMakeWktCoordinate( szCoordinate,
                           poPoint->getY(), poPoint->getX(), poPoint->getZ(), 3 );
        else
            OGRMakeWktCoordinate( szCoordinate,
                           poPoint->getX(), poPoint->getY(), poPoint->getZ(), 3 );

        _GrowBuffer( *pnLength + strlen(szCoordinate) + 70 + nAttrsLength,
                     ppszText, pnMaxLength );

        sprintf( *ppszText + *pnLength,
                "<gml:Point%s><gml:pos>%s</gml:pos></gml:Point>",
                 szAttributes, szCoordinate );

        *pnLength += strlen( *ppszText + *pnLength );
    }

/* -------------------------------------------------------------------- */
/*      LineString and LinearRing                                       */
/* -------------------------------------------------------------------- */
    else if( eFType == wkbLineString )
    {
        int bRing = EQUAL(poGeometry->getGeometryName(),"LINEARRING") ||
                    bForceLineStringAsLinearRing;
        if (!bRing && bLineStringAsCurve)
        {
            AppendString( ppszText, pnLength, pnMaxLength,
                            "<gml:Curve" );
            AppendString( ppszText, pnLength, pnMaxLength,
                            szAttributes );
            AppendString( ppszText, pnLength, pnMaxLength,
                            "><gml:segments><gml:LineStringSegment>" );
            AppendGML3CoordinateList( (OGRLineString *) poGeometry, bCoordSwap,
                                ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags );
            AppendString( ppszText, pnLength, pnMaxLength,
                            "</gml:LineStringSegment></gml:segments></gml:Curve>" );
        }
        else
        {
            // Buffer for tag name + srsName attribute if set
            const size_t nLineTagLength = 16;
            char* pszLineTagName = NULL;
            pszLineTagName = (char *) CPLMalloc( nLineTagLength + nAttrsLength + 1 );

            if( bRing )
            {
                /* LinearRing isn't supposed to have srsName attribute according to GML3 SF-0 */
                AppendString( ppszText, pnLength, pnMaxLength,
                            "<gml:LinearRing>" );
            }
            else
            {
                sprintf( pszLineTagName, "<gml:LineString%s>", szAttributes );

                AppendString( ppszText, pnLength, pnMaxLength,
                            pszLineTagName );
            }

            // FREE TAG BUFFER
            CPLFree( pszLineTagName );

            AppendGML3CoordinateList( (OGRLineString *) poGeometry, bCoordSwap,
                                ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags );

            if( bRing )
                AppendString( ppszText, pnLength, pnMaxLength,
                            "</gml:LinearRing>" );
            else
                AppendString( ppszText, pnLength, pnMaxLength,
                            "</gml:LineString>" );
        }
    }

/* -------------------------------------------------------------------- */
/*      ArcString or Circle                                             */
/* -------------------------------------------------------------------- */
    else if( eFType == wkbCircularString )
    {
        AppendString( ppszText, pnLength, pnMaxLength,
                        "<gml:Curve" );
        AppendString( ppszText, pnLength, pnMaxLength,
                        szAttributes );
        OGRSimpleCurve* poSC = (OGRSimpleCurve *) poGeometry;
        /* SQL MM has a unique type for arc and circle, GML not */
        if( poSC->getNumPoints() == 3 &&
            poSC->getX(0) == poSC->getX(2) &&
            poSC->getY(0) == poSC->getY(2) )
        {
            double dfMidX = (poSC->getX(0) + poSC->getX(1)) / 2;
            double dfMidY = (poSC->getY(0) + poSC->getY(1)) / 2;
            double dfDirX = (poSC->getX(1) - poSC->getX(0)) / 2;
            double dfDirY = (poSC->getY(1) - poSC->getY(0)) / 2;
            double dfNormX = -dfDirY;
            double dfNormY = dfDirX;
            double dfNewX = dfMidX + dfNormX;
            double dfNewY = dfMidY + dfNormY;
            OGRLineString* poLS = new OGRLineString();
            OGRPoint p;
            poSC->getPoint(0, &p);
            poLS->addPoint(&p);
            poSC->getPoint(1, &p);
            if( poSC->getCoordinateDimension() == 3 )
                poLS->addPoint(dfNewX, dfNewY, p.getZ());
            else
                poLS->addPoint(dfNewX, dfNewY);
            poLS->addPoint(&p);
            AppendString( ppszText, pnLength, pnMaxLength,
                            "><gml:segments><gml:Circle>" );
            AppendGML3CoordinateList( poLS, bCoordSwap,
                                ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags );
            AppendString( ppszText, pnLength, pnMaxLength,
                            "</gml:Circle></gml:segments></gml:Curve>" );
            delete poLS;
        }
        else
        {
            AppendString( ppszText, pnLength, pnMaxLength,
                            "><gml:segments><gml:ArcString>" );
            AppendGML3CoordinateList( poSC, bCoordSwap,
                                ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags );
            AppendString( ppszText, pnLength, pnMaxLength,
                            "</gml:ArcString></gml:segments></gml:Curve>" );
        }
    }

/* -------------------------------------------------------------------- */
/*      CompositeCurve                                                  */
/* -------------------------------------------------------------------- */
    else if( eFType == wkbCompoundCurve )
    {
        AppendString( ppszText, pnLength, pnMaxLength,
                        "<gml:CompositeCurve" );
        AppendString( ppszText, pnLength, pnMaxLength,
                        szAttributes );
        AppendString( ppszText, pnLength, pnMaxLength,">");

        OGRCompoundCurve* poCC = (OGRCompoundCurve*)poGeometry;
        for(int i=0;i<poCC->getNumCurves();i++)
        {
            AppendString( ppszText, pnLength, pnMaxLength,
                          "<gml:curveMember>" );
            if( !OGR2GML3GeometryAppend( poCC->getCurve(i), poSRS, ppszText, pnLength,
                                         pnMaxLength, TRUE, bLongSRS,
                                         bLineStringAsCurve,
                                         NULL, nSRSDimensionLocFlags, FALSE) )
                return FALSE;
            AppendString( ppszText, pnLength, pnMaxLength,
                          "</gml:curveMember>" );
        }
        AppendString( ppszText, pnLength, pnMaxLength,
                      "</gml:CompositeCurve>" );
    }

/* -------------------------------------------------------------------- */
/*      Polygon                                                         */
/* -------------------------------------------------------------------- */
    else if( eFType == wkbPolygon || eFType == wkbCurvePolygon )
    {
        OGRCurvePolygon      *poCP = (OGRCurvePolygon *) poGeometry;

        // Buffer for polygon tag name + srsName attribute if set
        const size_t nPolyTagLength = 13;
        char* pszPolyTagName = NULL;
        pszPolyTagName = (char *) CPLMalloc( nPolyTagLength + nAttrsLength + 1 );

        // Compose Polygon tag with or without srsName attribute
        sprintf( pszPolyTagName, "<gml:Polygon%s>", szAttributes );

        AppendString( ppszText, pnLength, pnMaxLength,
                      pszPolyTagName );

        // FREE TAG BUFFER
        CPLFree( pszPolyTagName );

        // Don't add srsName to polygon rings

        if( poCP->getExteriorRingCurve() != NULL )
        {
            AppendString( ppszText, pnLength, pnMaxLength,
                          "<gml:exterior>" );

            if( !OGR2GML3GeometryAppend( poCP->getExteriorRingCurve(), poSRS,
                                         ppszText, pnLength, pnMaxLength,
                                         TRUE, bLongSRS, bLineStringAsCurve,
                                         NULL, nSRSDimensionLocFlags, TRUE) )
            {
                return FALSE;
            }

            AppendString( ppszText, pnLength, pnMaxLength,
                          "</gml:exterior>" );
        }

        for( int iRing = 0; iRing < poCP->getNumInteriorRings(); iRing++ )
        {
            OGRCurve *poRing = poCP->getInteriorRingCurve(iRing);

            AppendString( ppszText, pnLength, pnMaxLength,
                          "<gml:interior>" );

            if( !OGR2GML3GeometryAppend( poRing, poSRS, ppszText, pnLength,
                                         pnMaxLength, TRUE, bLongSRS,
                                         bLineStringAsCurve,
                                         NULL, nSRSDimensionLocFlags, TRUE) )
                return FALSE;

            AppendString( ppszText, pnLength, pnMaxLength,
                          "</gml:interior>" );
        }

        AppendString( ppszText, pnLength, pnMaxLength,
                      "</gml:Polygon>" );
    }

/* -------------------------------------------------------------------- */
/*      MultiSurface, MultiCurve, MultiPoint, MultiGeometry             */
/* -------------------------------------------------------------------- */
    else if( eFType == wkbMultiPolygon
             || eFType == wkbMultiSurface
             || eFType == wkbMultiLineString
             || eFType == wkbMultiCurve
             || eFType == wkbMultiPoint
             || eFType == wkbGeometryCollection )
    {
        OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeometry;
        int             iMember;
        const char *pszElemClose = NULL;
        const char *pszMemberElem = NULL;

        // Buffer for opening tag + srsName attribute
        char* pszElemOpen = NULL;

        if( eFType == wkbMultiPolygon || eFType == wkbMultiSurface )
        {
            pszElemOpen = (char *) CPLMalloc( 13 + nAttrsLength + 1 );
            sprintf( pszElemOpen, "MultiSurface%s>", szAttributes );

            pszElemClose = "MultiSurface>";
            pszMemberElem = "surfaceMember>";
        }
        else if( eFType == wkbMultiLineString || eFType == wkbMultiCurve )
        {
            pszElemOpen = (char *) CPLMalloc( 16 + nAttrsLength + 1 );
            sprintf( pszElemOpen, "MultiCurve%s>", szAttributes );

            pszElemClose = "MultiCurve>";
            pszMemberElem = "curveMember>";
        }
        else if( eFType == wkbMultiPoint )
        {
            pszElemOpen = (char *) CPLMalloc( 11 + nAttrsLength + 1 );
            sprintf( pszElemOpen, "MultiPoint%s>", szAttributes );

            pszElemClose = "MultiPoint>";
            pszMemberElem = "pointMember>";
        }
        else
        {
            pszElemOpen = (char *) CPLMalloc( 19 + nAttrsLength + 1 );
            sprintf( pszElemOpen, "MultiGeometry%s>", szAttributes );

            pszElemClose = "MultiGeometry>";
            pszMemberElem = "geometryMember>";
        }

        AppendString( ppszText, pnLength, pnMaxLength, "<gml:" );
        AppendString( ppszText, pnLength, pnMaxLength, pszElemOpen );

        for( iMember = 0; iMember < poGC->getNumGeometries(); iMember++)
        {
            OGRGeometry *poMember = poGC->getGeometryRef( iMember );

            AppendString( ppszText, pnLength, pnMaxLength, "<gml:" );
            AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem );

            char* pszGMLIdSub = NULL;
            if (pszGMLId != NULL)
                pszGMLIdSub = CPLStrdup(CPLSPrintf("%s.%d", pszGMLId, iMember));

            if( !OGR2GML3GeometryAppend( poMember, poSRS,
                                         ppszText, pnLength, pnMaxLength,
                                         TRUE, bLongSRS, bLineStringAsCurve,
                                         pszGMLIdSub, nSRSDimensionLocFlags, FALSE ) )
            {
                CPLFree(pszGMLIdSub);
                return FALSE;
            }

            CPLFree(pszGMLIdSub);

            AppendString( ppszText, pnLength, pnMaxLength, "</gml:" );
            AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem );
        }

        AppendString( ppszText, pnLength, pnMaxLength, "</gml:" );
        AppendString( ppszText, pnLength, pnMaxLength, pszElemClose );

        // FREE TAG BUFFER
        CPLFree( pszElemOpen );
    }
    else
    {
        CPLError(CE_Failure, CPLE_NotSupported, "Unsupported geometry type %s",
                 OGRGeometryTypeToName(eType));
        return FALSE;
    }

    return TRUE;
}
Пример #4
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;
}
Пример #5
0
static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
                                   const OGRSpatialReference* poParentSRS,
                                   char **ppszText, int *pnLength,
                                   int *pnMaxLength,
                                   int bIsSubGeometry,
                                   int bLongSRS,
                                   int bLineStringAsCurve,
                                   const char* pszGMLId,
                                   int nSRSDimensionLocFlags )

{

/* -------------------------------------------------------------------- */
/*      Check for Spatial Reference System attached to given geometry   */
/* -------------------------------------------------------------------- */

    // Buffer for srsName, srsDimension and gml:id attributes (srsName="..." gml:id="...")
    char szAttributes[256];
    int nAttrsLength = 0;

    szAttributes[0] = 0;

    const OGRSpatialReference* poSRS = NULL;
    if (poParentSRS)
        poSRS = poParentSRS;
    else
        poParentSRS = poSRS = poGeometry->getSpatialReference();

    int bCoordSwap = FALSE;

    if( NULL != poSRS )
    {
        const char* pszAuthName = NULL;
        const char* pszAuthCode = NULL;
        const char* pszTarget = NULL;

        if (poSRS->IsProjected())
            pszTarget = "PROJCS";
        else
            pszTarget = "GEOGCS";

        pszAuthName = poSRS->GetAuthorityName( pszTarget );
        if( NULL != pszAuthName )
        {
            if( EQUAL( pszAuthName, "EPSG" ) )
            {
                pszAuthCode = poSRS->GetAuthorityCode( pszTarget );
                if( NULL != pszAuthCode && strlen(pszAuthCode) < 10 )
                {
                    if (bLongSRS && !(((OGRSpatialReference*)poSRS)->EPSGTreatsAsLatLong() ||
                                      ((OGRSpatialReference*)poSRS)->EPSGTreatsAsNorthingEasting()))
                    {
                        OGRSpatialReference oSRS;
                        if (oSRS.importFromEPSGA(atoi(pszAuthCode)) == OGRERR_NONE)
                        {
                            if (oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting())
                                bCoordSwap = TRUE;
                        }
                    }

                    if (!bIsSubGeometry)
                    {
                        if (bLongSRS)
                        {
                            snprintf( szAttributes, sizeof(szAttributes),
                                      " srsName=\"urn:ogc:def:crs:%s::%s\"",
                                      pszAuthName, pszAuthCode );
                        }
                        else
                        {
                            snprintf( szAttributes, sizeof(szAttributes),
                                      " srsName=\"%s:%s\"",
                                      pszAuthName, pszAuthCode );
                        }

                        nAttrsLength = strlen(szAttributes);
                    }
                }
            }
        }
    }

    if( (nSRSDimensionLocFlags & SRSDIM_LOC_GEOMETRY) != 0 &&
        (poGeometry->getGeometryType() & wkb25DBit) != 0 )
    {
        strcat(szAttributes, " srsDimension=\"3\"");
        nAttrsLength = strlen(szAttributes);

        nSRSDimensionLocFlags &= ~SRSDIM_LOC_GEOMETRY;
    }

    if (pszGMLId != NULL && nAttrsLength + 9 + strlen(pszGMLId) + 1 < sizeof(szAttributes))
    {
        strcat(szAttributes, " gml:id=\"");
        strcat(szAttributes, pszGMLId);
        strcat(szAttributes, "\"");
        nAttrsLength = strlen(szAttributes);
    }

/* -------------------------------------------------------------------- */
/*      2D Point                                                        */
/* -------------------------------------------------------------------- */
    if( poGeometry->getGeometryType() == wkbPoint )
    {
        char    szCoordinate[256];
        OGRPoint *poPoint = (OGRPoint *) poGeometry;

        if (bCoordSwap)
            OGRMakeWktCoordinate( szCoordinate,
                           poPoint->getY(), poPoint->getX(), 0.0, 2 );
        else
            OGRMakeWktCoordinate( szCoordinate,
                           poPoint->getX(), poPoint->getY(), 0.0, 2 );

        _GrowBuffer( *pnLength + strlen(szCoordinate) + 60 + nAttrsLength,
                     ppszText, pnMaxLength );

        sprintf( *ppszText + *pnLength,
                "<gml:Point%s><gml:pos>%s</gml:pos></gml:Point>",
                 szAttributes, szCoordinate );

        *pnLength += strlen( *ppszText + *pnLength );
    }
/* -------------------------------------------------------------------- */
/*      3D Point                                                        */
/* -------------------------------------------------------------------- */
    else if( poGeometry->getGeometryType() == wkbPoint25D )
    {
        char    szCoordinate[256];
        OGRPoint *poPoint = (OGRPoint *) poGeometry;

        if (bCoordSwap)
            OGRMakeWktCoordinate( szCoordinate,
                           poPoint->getY(), poPoint->getX(), poPoint->getZ(), 3 );
        else
            OGRMakeWktCoordinate( szCoordinate,
                           poPoint->getX(), poPoint->getY(), poPoint->getZ(), 3 );

        _GrowBuffer( *pnLength + strlen(szCoordinate) + 70 + nAttrsLength,
                     ppszText, pnMaxLength );

        sprintf( *ppszText + *pnLength,
                "<gml:Point%s><gml:pos>%s</gml:pos></gml:Point>",
                 szAttributes, szCoordinate );

        *pnLength += strlen( *ppszText + *pnLength );
    }

/* -------------------------------------------------------------------- */
/*      LineString and LinearRing                                       */
/* -------------------------------------------------------------------- */
    else if( poGeometry->getGeometryType() == wkbLineString
             || poGeometry->getGeometryType() == wkbLineString25D )
    {
        int bRing = EQUAL(poGeometry->getGeometryName(),"LINEARRING");
        if (!bRing && bLineStringAsCurve)
        {
            AppendString( ppszText, pnLength, pnMaxLength,
                            "<gml:Curve" );
            AppendString( ppszText, pnLength, pnMaxLength,
                            szAttributes );
            AppendString( ppszText, pnLength, pnMaxLength,
                            "><gml:segments><gml:LineStringSegment>" );
            AppendGML3CoordinateList( (OGRLineString *) poGeometry, bCoordSwap,
                                ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags );
            AppendString( ppszText, pnLength, pnMaxLength,
                            "</gml:LineStringSegment></gml:segments></gml:Curve>" );
        }
        else
        {
            // Buffer for tag name + srsName attribute if set
            const size_t nLineTagLength = 16;
            char* pszLineTagName = NULL;
            pszLineTagName = (char *) CPLMalloc( nLineTagLength + nAttrsLength + 1 );

            if( bRing )
            {
                /* LinearRing isn't supposed to have srsName attribute according to GML3 SF-0 */
                AppendString( ppszText, pnLength, pnMaxLength,
                            "<gml:LinearRing>" );
            }
            else
            {
                sprintf( pszLineTagName, "<gml:LineString%s>", szAttributes );

                AppendString( ppszText, pnLength, pnMaxLength,
                            pszLineTagName );
            }

            // FREE TAG BUFFER
            CPLFree( pszLineTagName );

            AppendGML3CoordinateList( (OGRLineString *) poGeometry, bCoordSwap,
                                ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags );

            if( bRing )
                AppendString( ppszText, pnLength, pnMaxLength,
                            "</gml:LinearRing>" );
            else
                AppendString( ppszText, pnLength, pnMaxLength,
                            "</gml:LineString>" );
        }
    }

/* -------------------------------------------------------------------- */
/*      Polygon                                                         */
/* -------------------------------------------------------------------- */
    else if( poGeometry->getGeometryType() == wkbPolygon
             || poGeometry->getGeometryType() == wkbPolygon25D )
    {
        OGRPolygon      *poPolygon = (OGRPolygon *) poGeometry;

        // Buffer for polygon tag name + srsName attribute if set
        const size_t nPolyTagLength = 13;
        char* pszPolyTagName = NULL;
        pszPolyTagName = (char *) CPLMalloc( nPolyTagLength + nAttrsLength + 1 );

        // Compose Polygon tag with or without srsName attribute
        sprintf( pszPolyTagName, "<gml:Polygon%s>", szAttributes );

        AppendString( ppszText, pnLength, pnMaxLength,
                      pszPolyTagName );

        // FREE TAG BUFFER
        CPLFree( pszPolyTagName );

        // Don't add srsName to polygon rings

        if( poPolygon->getExteriorRing() != NULL )
        {
            AppendString( ppszText, pnLength, pnMaxLength,
                          "<gml:exterior>" );

            if( !OGR2GML3GeometryAppend( poPolygon->getExteriorRing(), poSRS,
                                         ppszText, pnLength, pnMaxLength,
                                         TRUE, bLongSRS, bLineStringAsCurve,
                                         NULL, nSRSDimensionLocFlags) )
            {
                return FALSE;
            }

            AppendString( ppszText, pnLength, pnMaxLength,
                          "</gml:exterior>" );
        }

        for( int iRing = 0; iRing < poPolygon->getNumInteriorRings(); iRing++ )
        {
            OGRLinearRing *poRing = poPolygon->getInteriorRing(iRing);

            AppendString( ppszText, pnLength, pnMaxLength,
                          "<gml:interior>" );

            if( !OGR2GML3GeometryAppend( poRing, poSRS, ppszText, pnLength,
                                         pnMaxLength, TRUE, bLongSRS,
                                         bLineStringAsCurve,
                                         NULL, nSRSDimensionLocFlags) )
                return FALSE;

            AppendString( ppszText, pnLength, pnMaxLength,
                          "</gml:interior>" );
        }

        AppendString( ppszText, pnLength, pnMaxLength,
                      "</gml:Polygon>" );
    }

/* -------------------------------------------------------------------- */
/*      MultiPolygon, MultiLineString, MultiPoint, MultiGeometry        */
/* -------------------------------------------------------------------- */
    else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon
             || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString
             || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint
             || wkbFlatten(poGeometry->getGeometryType()) == wkbGeometryCollection )
    {
        OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeometry;
        int             iMember;
        const char *pszElemClose = NULL;
        const char *pszMemberElem = NULL;

        // Buffer for opening tag + srsName attribute
        char* pszElemOpen = NULL;

        if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon )
        {
            pszElemOpen = (char *) CPLMalloc( 13 + nAttrsLength + 1 );
            sprintf( pszElemOpen, "MultiSurface%s>", szAttributes );

            pszElemClose = "MultiSurface>";
            pszMemberElem = "surfaceMember>";
        }
        else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString )
        {
            pszElemOpen = (char *) CPLMalloc( 16 + nAttrsLength + 1 );
            sprintf( pszElemOpen, "MultiCurve%s>", szAttributes );

            pszElemClose = "MultiCurve>";
            pszMemberElem = "curveMember>";
        }
        else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint )
        {
            pszElemOpen = (char *) CPLMalloc( 11 + nAttrsLength + 1 );
            sprintf( pszElemOpen, "MultiPoint%s>", szAttributes );

            pszElemClose = "MultiPoint>";
            pszMemberElem = "pointMember>";
        }
        else
        {
            pszElemOpen = (char *) CPLMalloc( 19 + nAttrsLength + 1 );
            sprintf( pszElemOpen, "MultiGeometry%s>", szAttributes );

            pszElemClose = "MultiGeometry>";
            pszMemberElem = "geometryMember>";
        }

        AppendString( ppszText, pnLength, pnMaxLength, "<gml:" );
        AppendString( ppszText, pnLength, pnMaxLength, pszElemOpen );

        for( iMember = 0; iMember < poGC->getNumGeometries(); iMember++)
        {
            OGRGeometry *poMember = poGC->getGeometryRef( iMember );

            AppendString( ppszText, pnLength, pnMaxLength, "<gml:" );
            AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem );

            char* pszGMLIdSub = NULL;
            if (pszGMLId != NULL)
                pszGMLIdSub = CPLStrdup(CPLSPrintf("%s.%d", pszGMLId, iMember));

            if( !OGR2GML3GeometryAppend( poMember, poSRS,
                                         ppszText, pnLength, pnMaxLength,
                                         TRUE, bLongSRS, bLineStringAsCurve,
                                         pszGMLIdSub, nSRSDimensionLocFlags ) )
            {
                CPLFree(pszGMLIdSub);
                return FALSE;
            }

            CPLFree(pszGMLIdSub);

            AppendString( ppszText, pnLength, pnMaxLength, "</gml:" );
            AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem );
        }

        AppendString( ppszText, pnLength, pnMaxLength, "</gml:" );
        AppendString( ppszText, pnLength, pnMaxLength, pszElemClose );

        // FREE TAG BUFFER
        CPLFree( pszElemOpen );
    }
    else
    {
        return FALSE;
    }

    return TRUE;
}