LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/wfs - ogrwfslayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1196 490 41.0 %
Date: 2012-04-28 Functions: 38 26 68.4 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrwfslayer.cpp 23750 2012-01-12 23:45:00Z rouault $
       3                 :  *
       4                 :  * Project:  WFS Translator
       5                 :  * Purpose:  Implements OGRWFSLayer class.
       6                 :  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2010, Even Rouault <even dot rouault at mines dash paris dot org>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "cpl_port.h"
      31                 : #include "ogr_wfs.h"
      32                 : #include "ogr_api.h"
      33                 : #include "cpl_minixml.h"
      34                 : #include "cpl_http.h"
      35                 : #include "parsexsd.h"
      36                 : 
      37                 : CPL_CVSID("$Id: ogrwfslayer.cpp 23750 2012-01-12 23:45:00Z rouault $");
      38                 : 
      39                 : 
      40                 : /************************************************************************/
      41                 : /*                      OGRWFSRecursiveUnlink()                         */
      42                 : /************************************************************************/
      43                 : 
      44             496 : static void OGRWFSRecursiveUnlink( const char *pszName )
      45                 : 
      46                 : {
      47                 :     char **papszFileList;
      48                 :     int i;
      49                 : 
      50             496 :     papszFileList = CPLReadDir( pszName );
      51                 : 
      52             602 :     for( i = 0; papszFileList != NULL && papszFileList[i] != NULL; i++ )
      53                 :     {
      54                 :         VSIStatBufL  sStatBuf;
      55                 : 
      56             106 :         if( EQUAL(papszFileList[i],".") || EQUAL(papszFileList[i],"..") )
      57               0 :             continue;
      58                 : 
      59                 :         CPLString osFullFilename =
      60             106 :                  CPLFormFilename( pszName, papszFileList[i], NULL );
      61                 : 
      62             106 :         VSIStatL( osFullFilename, &sStatBuf );
      63                 : 
      64             106 :         if( VSI_ISREG( sStatBuf.st_mode ) )
      65                 :         {
      66             106 :             VSIUnlink( osFullFilename );
      67                 :         }
      68               0 :         else if( VSI_ISDIR( sStatBuf.st_mode ) )
      69                 :         {
      70               0 :             OGRWFSRecursiveUnlink( osFullFilename );
      71                 :         }
      72                 :     }
      73                 : 
      74             496 :     CSLDestroy( papszFileList );
      75                 : 
      76             496 :     VSIRmdir( pszName );
      77             496 : }
      78                 : 
      79                 : /************************************************************************/
      80                 : /*                            OGRWFSLayer()                             */
      81                 : /************************************************************************/
      82                 : 
      83             496 : OGRWFSLayer::OGRWFSLayer( OGRWFSDataSource* poDS,
      84                 :                           OGRSpatialReference* poSRS,
      85                 :                           int bAxisOrderAlreadyInverted,
      86                 :                           const char* pszBaseURL,
      87                 :                           const char* pszName,
      88                 :                           const char* pszNS,
      89             496 :                           const char* pszNSVal )
      90                 : 
      91                 : {
      92             496 :     this->poDS = poDS;
      93             496 :     this->poSRS = poSRS;
      94             496 :     this->bAxisOrderAlreadyInverted = bAxisOrderAlreadyInverted;
      95             496 :     this->pszBaseURL = CPLStrdup(pszBaseURL);
      96             496 :     this->pszName = CPLStrdup(pszName);
      97             496 :     this->pszNS = pszNS ? CPLStrdup(pszNS) : NULL;
      98             496 :     this->pszNSVal = pszNSVal ? CPLStrdup(pszNSVal) : NULL;
      99                 : 
     100             496 :     poFeatureDefn = NULL;
     101             496 :     poGMLFeatureClass = NULL;
     102             496 :     bGotApproximateLayerDefn = FALSE;
     103                 : 
     104             496 :     poBaseDS = NULL;
     105             496 :     poBaseLayer = NULL;
     106             496 :     bReloadNeeded = FALSE;
     107             496 :     bHasFetched = FALSE;
     108             496 :     eGeomType = wkbUnknown;
     109             496 :     nFeatures = -1;
     110                 : 
     111             496 :     dfMinX = dfMinY = dfMaxX = dfMaxY = 0;
     112             496 :     bHasExtents = FALSE;
     113             496 :     poFetchedFilterGeom = NULL;
     114                 : 
     115             496 :     nExpectedInserts = 0;
     116             496 :     bInTransaction = FALSE;
     117             496 :     bUseFeatureIdAtLayerLevel = FALSE;
     118                 : 
     119             496 :     bPagingActive = FALSE;
     120             496 :     nPagingStartIndex = 0;
     121             496 :     nFeatureRead = 0;
     122             496 :     nFeatureCountRequested = 0;
     123                 : 
     124             496 :     pszRequiredOutputFormat = NULL;
     125             496 :     pszRequiredOutputFormatURL = NULL;
     126                 : 
     127             496 :     bAscFlag = TRUE;
     128             496 : }
     129                 : 
     130                 : /************************************************************************/
     131                 : /*                             Clone()                                  */
     132                 : /************************************************************************/
     133                 : 
     134               2 : OGRWFSLayer* OGRWFSLayer::Clone()
     135                 : {
     136                 :     OGRWFSLayer* poDupLayer = new OGRWFSLayer(poDS, poSRS, bAxisOrderAlreadyInverted,
     137               2 :                                               pszBaseURL, pszName, pszNS, pszNSVal);
     138               2 :     if (poSRS)
     139               2 :         poSRS->Reference();
     140               2 :     poDupLayer->poFeatureDefn = GetLayerDefn()->Clone();
     141               2 :     poDupLayer->poFeatureDefn->Reference();
     142               2 :     poDupLayer->bGotApproximateLayerDefn = bGotApproximateLayerDefn;
     143               2 :     poDupLayer->eGeomType = poDupLayer->poFeatureDefn->GetGeomType();
     144               2 :     poDupLayer->pszRequiredOutputFormat = pszRequiredOutputFormat ? CPLStrdup(pszRequiredOutputFormat) : NULL;
     145               2 :     poDupLayer->pszRequiredOutputFormatURL = pszRequiredOutputFormatURL ? CPLStrdup(pszRequiredOutputFormatURL) : NULL;
     146               2 :     poDupLayer->bAscFlag = bAscFlag;
     147                 :     
     148               2 :     return poDupLayer;
     149                 : }
     150                 : 
     151                 : /************************************************************************/
     152                 : /*                            ~OGRWFSLayer()                            */
     153                 : /************************************************************************/
     154                 : 
     155             496 : OGRWFSLayer::~OGRWFSLayer()
     156                 : 
     157                 : {
     158             496 :     if (bInTransaction)
     159               0 :         CommitTransaction();
     160                 : 
     161             496 :     if( poSRS != NULL )
     162             496 :         poSRS->Release();
     163                 : 
     164             496 :     if (poFeatureDefn != NULL)
     165              92 :         poFeatureDefn->Release();
     166             496 :     delete poGMLFeatureClass;
     167                 : 
     168             496 :     CPLFree(pszBaseURL);
     169             496 :     CPLFree(pszName);
     170             496 :     CPLFree(pszNS);
     171             496 :     CPLFree(pszNSVal);
     172                 : 
     173             496 :     OGRDataSource::DestroyDataSource(poBaseDS);
     174                 : 
     175             496 :     delete poFetchedFilterGeom;
     176                 : 
     177             496 :     CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this);
     178             496 :     OGRWFSRecursiveUnlink(osTmpDirName);
     179                 : 
     180             496 :     CPLFree(pszRequiredOutputFormat);
     181             496 :     CPLFree(pszRequiredOutputFormatURL);
     182             496 : }
     183                 : 
     184                 : /************************************************************************/
     185                 : /*                    GetDescribeFeatureTypeURL()                       */
     186                 : /************************************************************************/
     187                 : 
     188               8 : CPLString OGRWFSLayer::GetDescribeFeatureTypeURL(int bWithNS)
     189                 : {
     190               8 :     CPLString osURL(pszBaseURL);
     191               8 :     osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
     192               8 :     osURL = CPLURLAddKVP(osURL, "VERSION", poDS->GetVersion());
     193               8 :     osURL = CPLURLAddKVP(osURL, "REQUEST", "DescribeFeatureType");
     194               8 :     osURL = CPLURLAddKVP(osURL, "TYPENAME", pszName);
     195               8 :     osURL = CPLURLAddKVP(osURL, "PROPERTYNAME", NULL);
     196               8 :     osURL = CPLURLAddKVP(osURL, "MAXFEATURES", NULL);
     197               8 :     osURL = CPLURLAddKVP(osURL, "COUNT", NULL);
     198               8 :     osURL = CPLURLAddKVP(osURL, "FILTER", NULL);
     199               8 :     osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", pszRequiredOutputFormatURL);
     200                 : 
     201               8 :     if (pszNS && poDS->GetNeedNAMESPACE())
     202                 :     {
     203                 :         /* Older Deegree version require NAMESPACE (e.g. http://www.nokis.org/deegree2/ogcwebservice) */
     204                 :         /* This has been now corrected */
     205               0 :         CPLString osValue("xmlns(");
     206               0 :         osValue += pszNS;
     207               0 :         osValue += "=";
     208               0 :         osValue += pszNSVal;
     209               0 :         osValue += ")";
     210               0 :         osURL = CPLURLAddKVP(osURL, "NAMESPACE", osValue);
     211                 :     }
     212                 : 
     213               0 :     return osURL;
     214                 : }
     215                 : 
     216                 : /************************************************************************/
     217                 : /*                      DescribeFeatureType()                           */
     218                 : /************************************************************************/
     219                 : 
     220               8 : OGRFeatureDefn* OGRWFSLayer::DescribeFeatureType()
     221                 : {
     222               8 :     CPLString osURL = GetDescribeFeatureTypeURL(TRUE);
     223                 : 
     224               8 :     CPLDebug("WFS", "%s", osURL.c_str());
     225                 : 
     226               8 :     CPLHTTPResult* psResult = poDS->HTTPFetch( osURL, NULL);
     227               8 :     if (psResult == NULL)
     228                 :     {
     229               0 :         return NULL;
     230                 :     }
     231                 : 
     232               8 :     if (strstr((const char*)psResult->pabyData, "<ServiceExceptionReport") != NULL)
     233                 :     {
     234               0 :         if (poDS->IsOldDeegree((const char*)psResult->pabyData))
     235                 :         {
     236               0 :             CPLHTTPDestroyResult(psResult);
     237               0 :             return DescribeFeatureType();
     238                 :         }
     239                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
     240               0 :                  psResult->pabyData);
     241               0 :         CPLHTTPDestroyResult(psResult);
     242               0 :         return NULL;
     243                 :     }
     244                 : 
     245               8 :     CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
     246               8 :     if (psXML == NULL)
     247                 :     {
     248                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
     249               0 :                 psResult->pabyData);
     250               0 :         CPLHTTPDestroyResult(psResult);
     251               0 :         return NULL;
     252                 :     }
     253               8 :     CPLHTTPDestroyResult(psResult);
     254                 : 
     255               8 :     CPLXMLNode* psSchema = WFSFindNode(psXML, "schema");
     256               8 :     if (psSchema == NULL)
     257                 :     {
     258               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <Schema>");
     259               0 :         CPLDestroyXMLNode( psXML );
     260                 : 
     261               0 :         return NULL;
     262                 :     }
     263                 : 
     264               8 :     OGRFeatureDefn* poFDefn = ParseSchema(psSchema);
     265               8 :     if (poFDefn)
     266               8 :         poDS->SaveLayerSchema(pszName, psSchema);
     267                 : 
     268               8 :     CPLDestroyXMLNode( psXML );
     269               8 :     return poFDefn;
     270                 : }
     271                 : 
     272                 : /************************************************************************/
     273                 : /*                            ParseSchema()                             */
     274                 : /************************************************************************/
     275                 : 
     276              90 : OGRFeatureDefn* OGRWFSLayer::ParseSchema(CPLXMLNode* psSchema)
     277                 : {
     278              90 :     osTargetNamespace = CPLGetXMLValue(psSchema, "targetNamespace", "");
     279                 : 
     280              90 :     CPLString osTmpFileName;
     281                 : 
     282             180 :     osTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
     283              90 :     CPLSerializeXMLTreeToFile(psSchema, osTmpFileName);
     284                 : 
     285              90 :     std::vector<GMLFeatureClass*> aosClasses;
     286              90 :     int bHaveSchema = GMLParseXSD( osTmpFileName, aosClasses );
     287                 : 
     288              90 :     if (bHaveSchema && aosClasses.size() == 1)
     289                 :     {
     290              90 :         return BuildLayerDefnFromFeatureClass(aosClasses[0]);
     291                 :     }
     292               0 :     else if (bHaveSchema)
     293                 :     {
     294               0 :         std::vector<GMLFeatureClass*>::const_iterator iter = aosClasses.begin();
     295               0 :         std::vector<GMLFeatureClass*>::const_iterator eiter = aosClasses.end();
     296               0 :         while (iter != eiter)
     297                 :         {
     298               0 :             GMLFeatureClass* poClass = *iter;
     299               0 :             iter ++;
     300               0 :             delete poClass;
     301                 :         }
     302                 :     }
     303                 : 
     304               0 :     VSIUnlink(osTmpFileName);
     305                 : 
     306               0 :     return NULL;
     307                 : }
     308                 : /************************************************************************/
     309                 : /*                   BuildLayerDefnFromFeatureClass()                   */
     310                 : /************************************************************************/
     311                 : 
     312              90 : OGRFeatureDefn* OGRWFSLayer::BuildLayerDefnFromFeatureClass(GMLFeatureClass* poClass)
     313                 : {
     314              90 :     this->poGMLFeatureClass = poClass;
     315                 : 
     316              90 :     OGRFeatureDefn* poFDefn = new OGRFeatureDefn(poDS->GetKeepLayerNamePrefix() ? pszName : poGMLFeatureClass->GetName());
     317              90 :     poFDefn->SetGeomType( (OGRwkbGeometryType)poGMLFeatureClass->GetGeometryType() );
     318                 : 
     319                 : /* -------------------------------------------------------------------- */
     320                 : /*      Added attributes (properties).                                  */
     321                 : /* -------------------------------------------------------------------- */
     322              90 :     OGRFieldDefn oField( "gml_id", OFTString );
     323              90 :     poFDefn->AddFieldDefn( &oField );
     324                 : 
     325             562 :     for( int iField = 0; iField < poGMLFeatureClass->GetPropertyCount(); iField++ )
     326                 :     {
     327             472 :         GMLPropertyDefn *poProperty = poGMLFeatureClass->GetProperty( iField );
     328                 :         OGRFieldType eFType;
     329                 : 
     330             472 :         if( poProperty->GetType() == GMLPT_Untyped )
     331               0 :             eFType = OFTString;
     332             472 :         else if( poProperty->GetType() == GMLPT_String )
     333             166 :             eFType = OFTString;
     334             306 :         else if( poProperty->GetType() == GMLPT_Integer )
     335              30 :             eFType = OFTInteger;
     336             276 :         else if( poProperty->GetType() == GMLPT_Real )
     337             276 :             eFType = OFTReal;
     338               0 :         else if( poProperty->GetType() == GMLPT_StringList )
     339               0 :             eFType = OFTStringList;
     340               0 :         else if( poProperty->GetType() == GMLPT_IntegerList )
     341               0 :             eFType = OFTIntegerList;
     342               0 :         else if( poProperty->GetType() == GMLPT_RealList )
     343               0 :             eFType = OFTRealList;
     344                 :         else
     345               0 :             eFType = OFTString;
     346                 : 
     347             472 :         OGRFieldDefn oField( poProperty->GetName(), eFType );
     348             472 :         if ( EQUALN(oField.GetNameRef(), "ogr:", 4) )
     349               0 :             oField.SetName(poProperty->GetName()+4);
     350             472 :         if( poProperty->GetWidth() > 0 )
     351               0 :             oField.SetWidth( poProperty->GetWidth() );
     352             472 :         if( poProperty->GetPrecision() > 0 )
     353               0 :             oField.SetPrecision( poProperty->GetPrecision() );
     354                 : 
     355             472 :         poFDefn->AddFieldDefn( &oField );
     356                 :     }
     357                 : 
     358              90 :     const char* pszGeometryColumnName = poGMLFeatureClass->GetGeometryElement();
     359              90 :     if (pszGeometryColumnName)
     360              90 :         osGeometryColumnName = pszGeometryColumnName;
     361                 : 
     362              90 :     return poFDefn;
     363                 : }
     364                 : 
     365                 : /************************************************************************/
     366                 : /*                       MakeGetFeatureURL()                            */
     367                 : /************************************************************************/
     368                 : 
     369              36 : CPLString OGRWFSLayer::MakeGetFeatureURL(int nMaxFeatures, int bRequestHits)
     370                 : {
     371              36 :     CPLString osURL(pszBaseURL);
     372              36 :     osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
     373              36 :     osURL = CPLURLAddKVP(osURL, "VERSION", poDS->GetVersion());
     374              36 :     osURL = CPLURLAddKVP(osURL, "REQUEST", "GetFeature");
     375              36 :     osURL = CPLURLAddKVP(osURL, "TYPENAME", pszName);
     376              36 :     if (pszRequiredOutputFormat)
     377               4 :         osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", pszRequiredOutputFormatURL);
     378                 : 
     379              36 :     if (poDS->IsPagingAllowed() && !bRequestHits)
     380                 :     {
     381               0 :         if (nFeatures < 0)
     382                 :         {
     383               0 :             if ((m_poAttrQuery == NULL || osWFSWhere.size() != 0) &&
     384                 :                 poDS->GetFeatureSupportHits())
     385                 :             {
     386               0 :                 nFeatures = ExecuteGetFeatureResultTypeHits();
     387                 :             }
     388                 :         }
     389               0 :         if (nFeatures >= poDS->GetPageSize())
     390                 :         {
     391               0 :             osURL = CPLURLAddKVP(osURL, "STARTINDEX", CPLSPrintf("%d", nPagingStartIndex + 1));
     392               0 :             nMaxFeatures = poDS->GetPageSize();
     393               0 :             nFeatureCountRequested = nMaxFeatures;
     394               0 :             bPagingActive = TRUE;
     395                 :         }
     396                 :         else
     397                 :         {
     398               0 :             osURL = CPLURLAddKVP(osURL, "STARTINDEX", NULL);
     399                 :         }
     400                 :     }
     401                 : 
     402              36 :     if (nMaxFeatures)
     403                 :     {
     404                 :         osURL = CPLURLAddKVP(osURL,
     405                 :                              atoi(poDS->GetVersion()) >= 2 ? "COUNT" : "MAXFEATURES",
     406               0 :                              CPLSPrintf("%d", nMaxFeatures));
     407                 :     }
     408              36 :     if (pszNS && poDS->GetNeedNAMESPACE())
     409                 :     {
     410                 :         /* Older Deegree version require NAMESPACE (e.g. http://www.nokis.org/deegree2/ogcwebservice) */
     411                 :         /* This has been now corrected */
     412               0 :         CPLString osValue("xmlns(");
     413               0 :         osValue += pszNS;
     414               0 :         osValue += "=";
     415               0 :         osValue += pszNSVal;
     416               0 :         osValue += ")";
     417               0 :         osURL = CPLURLAddKVP(osURL, "NAMESPACE", osValue);
     418                 :     }
     419                 : 
     420              36 :     delete poFetchedFilterGeom;
     421              36 :     poFetchedFilterGeom = NULL;
     422                 : 
     423              36 :     CPLString osGeomFilter;
     424                 : 
     425              36 :     if (m_poFilterGeom != NULL && osGeometryColumnName.size() > 0)
     426                 :     {
     427               2 :         OGREnvelope oEnvelope;
     428               2 :         m_poFilterGeom->getEnvelope(&oEnvelope);
     429                 : 
     430               2 :         poFetchedFilterGeom = m_poFilterGeom->clone();
     431                 : 
     432               2 :         osGeomFilter = "<BBOX>";
     433               2 :         if (atoi(poDS->GetVersion()) >= 2)
     434               2 :             osGeomFilter += "<ValueReference>";
     435                 :         else
     436               0 :             osGeomFilter += "<PropertyName>";
     437               2 :         if (pszNS)
     438                 :         {
     439               0 :             osGeomFilter += pszNS;
     440               0 :             osGeomFilter += ":";
     441                 :         }
     442               2 :         osGeomFilter += osGeometryColumnName;
     443               2 :         if (atoi(poDS->GetVersion()) >= 2)
     444               2 :             osGeomFilter += "</ValueReference>";
     445                 :         else
     446               0 :             osGeomFilter += "</PropertyName>";
     447               2 :         if ( poDS->RequiresEnvelopeSpatialFilter() )
     448                 :         {
     449               0 :             osGeomFilter += "<Envelope xmlns=\"http://www.opengis.net/gml\">";
     450               0 :             if (bAxisOrderAlreadyInverted)
     451                 :             {
     452                 :                 /* We can go here in WFS 1.1 with geographic coordinate systems */
     453                 :                 /* that are natively return in lat,long order, but as we have */
     454                 :                 /* presented long,lat order to the user, we must switch back */
     455                 :                 /* for the server... */
     456                 :                 osGeomFilter += CPLSPrintf("<coord><X>%.16f</X><Y>%.16f</Y></coord><coord><X>%.16f</X><Y>%.16f</Y></coord>",
     457               0 :                                         oEnvelope.MinY, oEnvelope.MinX, oEnvelope.MaxY, oEnvelope.MaxX);
     458                 :             }
     459                 :             else
     460                 :                 osGeomFilter += CPLSPrintf("<coord><X>%.16f</X><Y>%.16f</Y></coord><coord><X>%.16f</X><Y>%.16f</Y></coord>",
     461               0 :                                         oEnvelope.MinX, oEnvelope.MinY, oEnvelope.MaxX, oEnvelope.MaxY);
     462               0 :             osGeomFilter += "</Envelope>";
     463                 :         }
     464                 :         else
     465                 :         {
     466               2 :             osGeomFilter += "<gml:Box>";
     467               2 :             osGeomFilter += "<gml:coordinates>";
     468               2 :             if (bAxisOrderAlreadyInverted)
     469                 :             {
     470                 :                 /* We can go here in WFS 1.1 with geographic coordinate systems */
     471                 :                 /* that are natively return in lat,long order, but as we have */
     472                 :                 /* presented long,lat order to the user, we must switch back */
     473                 :                 /* for the server... */
     474               0 :                 osGeomFilter += CPLSPrintf("%.16f,%.16f %.16f,%.16f", oEnvelope.MinY, oEnvelope.MinX, oEnvelope.MaxY, oEnvelope.MaxX);
     475                 :             }
     476                 :             else
     477               2 :                 osGeomFilter += CPLSPrintf("%.16f,%.16f %.16f,%.16f", oEnvelope.MinX, oEnvelope.MinY, oEnvelope.MaxX, oEnvelope.MaxY);
     478               2 :             osGeomFilter += "</gml:coordinates>";
     479               2 :             osGeomFilter += "</gml:Box>";
     480                 :         }
     481               2 :         osGeomFilter += "</BBOX>";
     482                 :     }
     483                 : 
     484              36 :     if (osGeomFilter.size() != 0 || osWFSWhere.size() != 0)
     485                 :     {
     486              18 :         CPLString osFilter;
     487              18 :         if (atoi(poDS->GetVersion()) >= 2)
     488              10 :             osFilter = "<Filter xmlns=\"http://www.opengis.net/fes/2.0\"";
     489                 :         else
     490               8 :             osFilter = "<Filter xmlns=\"http://www.opengis.net/ogc\"";
     491              18 :         if (pszNS)
     492                 :         {
     493               8 :             osFilter += " xmlns:";
     494               8 :             osFilter += pszNS;
     495               8 :             osFilter += "=\"";
     496               8 :             osFilter += pszNSVal;
     497               8 :             osFilter += "\"";
     498                 :         }
     499              18 :         osFilter += " xmlns:gml=\"http://www.opengis.net/gml\">";
     500              18 :         if (osGeomFilter.size() != 0 && osWFSWhere.size() != 0)
     501               0 :             osFilter += "<And>";
     502              18 :         osFilter += osWFSWhere;
     503              18 :         osFilter += osGeomFilter;
     504              18 :         if (osGeomFilter.size() != 0 && osWFSWhere.size() != 0)
     505               0 :             osFilter += "</And>";
     506              18 :         osFilter += "</Filter>";
     507                 : 
     508              18 :         osURL = CPLURLAddKVP(osURL, "FILTER", osFilter);
     509                 :     }
     510                 :         
     511              36 :     if (bRequestHits)
     512                 :     {
     513              12 :         osURL = CPLURLAddKVP(osURL, "RESULTTYPE", "hits");
     514                 :     }
     515              24 :     else if (osFieldToSort.size() != 0)
     516                 :     {
     517               2 :         CPLString osSortBy(osFieldToSort);
     518               2 :         if (!bAscFlag)
     519                 :         {
     520               2 :             if (atoi(poDS->GetVersion()) >= 2)
     521               0 :                 osSortBy += " DESC";
     522                 :             else
     523               2 :                 osSortBy += " D";
     524                 :         }
     525               2 :         osURL = CPLURLAddKVP(osURL, "SORTBY", osSortBy.c_str());
     526                 :     }
     527                 : 
     528                 :     /* If no PROPERTYNAME is specified, build one if there are ignored fields */
     529              36 :     CPLString osPropertyName = CPLURLGetValue(osURL, "PROPERTYNAME");
     530              36 :     const char* pszPropertyName = osPropertyName.c_str();
     531              36 :     if (pszPropertyName[0] == 0 && poFeatureDefn != NULL)
     532                 :     {
     533              32 :         int bHasIgnoredField = FALSE;
     534              32 :         CPLString osPropertyName;
     535             346 :         for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
     536                 :         {
     537             314 :             if (EQUAL(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(), "gml_id"))
     538                 :             {
     539                 :                 /* fake field : skip it */
     540                 :             }
     541             282 :             else if (poFeatureDefn->GetFieldDefn(iField)->IsIgnored())
     542                 :             {
     543               0 :                 bHasIgnoredField = TRUE;
     544                 :             }
     545                 :             else
     546                 :             {
     547             282 :                 if (osPropertyName.size() != 0)
     548             252 :                     osPropertyName += ",";
     549             282 :                 osPropertyName += poFeatureDefn->GetFieldDefn(iField)->GetNameRef();
     550                 :             }
     551                 :         }
     552              32 :         if (osGeometryColumnName.size() != 0)
     553                 :         {
     554              30 :             if (poFeatureDefn->IsGeometryIgnored())
     555                 :             {
     556               0 :                 bHasIgnoredField = TRUE;
     557                 :             }
     558                 :             else
     559                 :             {
     560              30 :                 if (osPropertyName.size() != 0)
     561              28 :                     osPropertyName += ",";
     562              30 :                 osPropertyName += osGeometryColumnName;
     563                 :             }
     564                 :         }
     565                 : 
     566              32 :         if (bHasIgnoredField)
     567                 :         {
     568               0 :             osPropertyName = "(" + osPropertyName + ")";
     569               0 :             osURL = CPLURLAddKVP(osURL, "PROPERTYNAME", osPropertyName);
     570              32 :         }
     571                 :     }
     572                 : 
     573              36 :     return osURL;
     574                 : }
     575                 : 
     576                 : 
     577                 : /************************************************************************/
     578                 : /*               OGRWFSFetchContentDispositionFilename()                */
     579                 : /************************************************************************/
     580                 : 
     581              24 : const char* OGRWFSFetchContentDispositionFilename(char** papszHeaders)
     582                 : {
     583              24 :     char** papszIter = papszHeaders;
     584             188 :     while(papszIter && *papszIter)
     585                 :     {
     586                 :         /* For multipart, we have in raw format, but without end-of-line characters */
     587             140 :         if (strncmp(*papszIter, "Content-Disposition: attachment; filename=", 42) == 0)
     588                 :         {
     589               0 :             return *papszIter + 42;
     590                 :         }
     591                 :         /* For single part, the headers are in KEY=VAL format, but with e-o-l ... */
     592             140 :         else if (strncmp(*papszIter, "Content-Disposition=attachment; filename=", 41) == 0)
     593                 :         {
     594               0 :             char* pszVal = (char*)(*papszIter + 41);
     595               0 :             char* pszEOL = strchr(pszVal, '\r');
     596               0 :             if (pszEOL) *pszEOL = 0;
     597               0 :             pszEOL = strchr(pszVal, '\n');
     598               0 :             if (pszEOL) *pszEOL = 0;
     599               0 :             return pszVal;
     600                 :         }
     601             140 :         papszIter ++;
     602                 :     }
     603              24 :     return NULL;
     604                 : }
     605                 : 
     606                 : /************************************************************************/
     607                 : /*                         FetchGetFeature()                            */
     608                 : /************************************************************************/
     609                 : 
     610              24 : OGRDataSource* OGRWFSLayer::FetchGetFeature(int nMaxFeatures)
     611                 : {
     612                 : 
     613              24 :     CPLString osURL = MakeGetFeatureURL(nMaxFeatures, FALSE);
     614              24 :     CPLDebug("WFS", "%s", osURL.c_str());
     615                 : 
     616              24 :     CPLHTTPResult* psResult = poDS->HTTPFetch( osURL, NULL);
     617              24 :     if (psResult == NULL)
     618                 :     {
     619               0 :         return NULL;
     620                 :     }
     621                 : 
     622              24 :     const char* pszContentType = "";
     623              24 :     if (psResult->pszContentType)
     624              24 :         pszContentType = psResult->pszContentType;
     625                 : 
     626              24 :     CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this);
     627              24 :     VSIMkdir(osTmpDirName, 0);
     628                 : 
     629              24 :     GByte *pabyData = psResult->pabyData;
     630              24 :     int    nDataLen = psResult->nDataLen;
     631              24 :     int bIsMultiPart = FALSE;
     632              24 :     const char* pszAttachementFilename = NULL;
     633                 : 
     634              24 :     if(strstr(pszContentType,"multipart")
     635                 :         && CPLHTTPParseMultipartMime(psResult) )
     636                 :     {
     637                 :         int i;
     638               0 :         bIsMultiPart = TRUE;
     639               0 :         OGRWFSRecursiveUnlink(osTmpDirName);
     640               0 :         VSIMkdir(osTmpDirName, 0);
     641               0 :         for(i=0;i<psResult->nMimePartCount;i++)
     642                 :         {
     643               0 :             CPLString osTmpFileName = osTmpDirName + "/";
     644                 :             pszAttachementFilename =
     645                 :                 OGRWFSFetchContentDispositionFilename(
     646               0 :                     psResult->pasMimePart[i].papszHeaders);
     647                 : 
     648               0 :             if (pszAttachementFilename)
     649               0 :                 osTmpFileName += pszAttachementFilename;
     650                 :             else
     651               0 :                 osTmpFileName += CPLSPrintf("file_%d", i);
     652                 : 
     653               0 :             GByte* pData = (GByte*)VSIMalloc(psResult->pasMimePart[i].nDataLen);
     654               0 :             if (pData)
     655                 :             {
     656               0 :                 memcpy(pData, psResult->pasMimePart[i].pabyData, psResult->pasMimePart[i].nDataLen);
     657                 :                 VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName,
     658                 :                                                 pData,
     659               0 :                                                 psResult->pasMimePart[i].nDataLen, TRUE);
     660               0 :                 VSIFCloseL(fp);
     661                 :             }
     662                 :         }
     663                 :     }
     664                 :     else
     665                 :         pszAttachementFilename =
     666                 :                 OGRWFSFetchContentDispositionFilename(
     667              24 :                     psResult->papszHeaders);
     668                 : 
     669              24 :     int bJSON = FALSE;
     670              24 :     int bCSV = FALSE;
     671              24 :     int bKML = FALSE;
     672              24 :     int bKMZ = FALSE;
     673              24 :     int bZIP = FALSE;
     674              24 :     int bGZIP = FALSE;
     675                 : 
     676              24 :     CPLString osOutputFormat = CPLURLGetValue(osURL, "OUTPUTFORMAT");
     677              24 :     const char* pszOutputFormat = osOutputFormat.c_str();
     678                 : 
     679              24 :     if (FindSubStringInsensitive(pszContentType, "json") ||
     680                 :         FindSubStringInsensitive(pszOutputFormat, "json"))
     681                 :     {
     682               0 :         bJSON = TRUE;
     683                 :     }
     684              24 :     else if (FindSubStringInsensitive(pszContentType, "csv") ||
     685                 :              FindSubStringInsensitive(pszOutputFormat, "csv"))
     686                 :     {
     687               0 :         bCSV = TRUE;
     688                 :     }
     689              24 :     else if (FindSubStringInsensitive(pszContentType, "kml") ||
     690                 :              FindSubStringInsensitive(pszOutputFormat, "kml"))
     691                 :     {
     692               0 :         bKML = TRUE;
     693                 :     }
     694              24 :     else if (FindSubStringInsensitive(pszContentType, "kmz") ||
     695                 :              FindSubStringInsensitive(pszOutputFormat, "kmz"))
     696                 :     {
     697               0 :         bKMZ = TRUE;
     698                 :     }
     699              24 :     else if (strstr(pszContentType, "application/zip") != NULL)
     700                 :     {
     701               0 :         bZIP = TRUE;
     702                 :     }
     703              24 :     else if (strstr(pszContentType, "application/gzip") != NULL)
     704                 :     {
     705               0 :         bGZIP = TRUE;
     706                 :     }
     707                 : 
     708              24 :     int bRetry = FALSE;
     709                 : 
     710                 :     /* Deegree server does not support PropertyIsNotEqualTo */
     711                 :     /* We have to turn it into <Not><PropertyIsEqualTo> */
     712              24 :     if (osWFSWhere.size() != 0 && poDS->PropertyIsNotEqualToSupported() &&
     713                 :         strstr((const char*)pabyData, "Unknown comparison operation: 'PropertyIsNotEqualTo'") != NULL)
     714                 :     {
     715               2 :         poDS->SetPropertyIsNotEqualToUnSupported();
     716               2 :         bRetry = TRUE;
     717                 :     }
     718                 : 
     719                 :     /* Deegree server requires the gml: prefix in GmlObjectId element, but ESRI */
     720                 :     /* doesn't like it at all ! Other servers don't care... */
     721              24 :     if (osWFSWhere.size() != 0 && !poDS->DoesGmlObjectIdNeedGMLPrefix() &&
     722                 :         strstr((const char*)pabyData, "&lt;GmlObjectId&gt; requires 'gml:id'-attribute!") != NULL)
     723                 :     {
     724               0 :         poDS->SetGmlObjectIdNeedsGMLPrefix();
     725               0 :         bRetry = TRUE;
     726                 :     }
     727                 : 
     728                 :     /* GeoServer can return the error 'Only FeatureIds are supported when encoding id filters to SDE' */
     729              24 :     if (osWFSWhere.size() != 0 && !bUseFeatureIdAtLayerLevel &&
     730                 :         strstr((const char*)pabyData, "Only FeatureIds are supported") != NULL)
     731                 :     {
     732               0 :         bUseFeatureIdAtLayerLevel = TRUE;
     733               0 :         bRetry = TRUE;
     734                 :     }
     735                 : 
     736              24 :     if (bRetry)
     737                 :     {
     738               2 :         SetAttributeFilter(osSQLWhere);
     739               2 :         bHasFetched = TRUE;
     740               2 :         bReloadNeeded = FALSE;
     741                 : 
     742               2 :         CPLHTTPDestroyResult(psResult);
     743               2 :         return FetchGetFeature(nMaxFeatures);
     744                 :     }
     745                 : 
     746              22 :     if (strstr((const char*)pabyData, "<ServiceExceptionReport") != NULL ||
     747                 :         strstr((const char*)pabyData, "<ows:ExceptionReport") != NULL)
     748                 :     {
     749               0 :         if (poDS->IsOldDeegree((const char*)pabyData))
     750                 :         {
     751               0 :             CPLHTTPDestroyResult(psResult);
     752               0 :             return FetchGetFeature(nMaxFeatures);
     753                 :         }
     754                 : 
     755                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
     756               0 :                  pabyData);
     757               0 :         CPLHTTPDestroyResult(psResult);
     758               0 :         return NULL;
     759                 :     }
     760                 : 
     761              22 :     CPLString osTmpFileName;
     762                 : 
     763              22 :     if (!bIsMultiPart)
     764                 :     {
     765              22 :         if (bJSON)
     766               0 :             osTmpFileName = osTmpDirName + "/file.geojson";
     767              22 :         else if (bZIP)
     768               0 :             osTmpFileName = osTmpDirName + "/file.zip";
     769              22 :         else if (bCSV)
     770               0 :             osTmpFileName = osTmpDirName + "/file.csv";
     771              22 :         else if (bKML)
     772               0 :             osTmpFileName = osTmpDirName + "/file.kml";
     773              22 :         else if (bKMZ)
     774               0 :             osTmpFileName = osTmpDirName + "/file.kmz";
     775                 :         /* GML is a special case. It needs the .xsd file that has been saved */
     776                 :         /* as file.xsd, so we cannot used the attachement filename */
     777              22 :         else if (pszAttachementFilename &&
     778                 :                  !EQUAL(CPLGetExtension(pszAttachementFilename), "GML"))
     779                 :         {
     780               0 :             osTmpFileName = osTmpDirName + "/";
     781               0 :             osTmpFileName += pszAttachementFilename;
     782                 :         }
     783                 :         else
     784                 :         {
     785              22 :             osTmpFileName = osTmpDirName + "/file.gfs";
     786              22 :             VSIUnlink(osTmpFileName);
     787                 : 
     788              22 :             osTmpFileName = osTmpDirName + "/file.gml";
     789                 :         }
     790                 : 
     791                 :         VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName, pabyData,
     792              22 :                                         nDataLen, TRUE);
     793              22 :         VSIFCloseL(fp);
     794              22 :         psResult->pabyData = NULL;
     795                 : 
     796              22 :         if (bZIP)
     797                 :         {
     798               0 :             osTmpFileName = "/vsizip/" + osTmpFileName;
     799                 :         }
     800              22 :         else if (bGZIP)
     801                 :         {
     802               0 :             osTmpFileName = "/vsigzip/" + osTmpFileName;
     803                 :         }
     804                 :     }
     805                 :     else
     806                 :     {
     807               0 :         pabyData = NULL;
     808               0 :         nDataLen = 0;
     809               0 :         osTmpFileName = osTmpDirName;
     810                 :     }
     811                 : 
     812              22 :     CPLHTTPDestroyResult(psResult);
     813                 : 
     814                 :     OGRDataSource* poDS;
     815                 : 
     816              22 :     poDS = (OGRDataSource*) OGROpen(osTmpFileName, FALSE, NULL);
     817              22 :     if (poDS == NULL && (bZIP || bIsMultiPart))
     818                 :     {
     819               0 :         char** papszFileList = VSIReadDir(osTmpFileName);
     820                 :         int i;
     821               0 :         for( i = 0; papszFileList != NULL && papszFileList[i] != NULL; i++ )
     822                 :         {
     823                 :             CPLString osFullFilename =
     824               0 :                     CPLFormFilename( osTmpFileName, papszFileList[i], NULL );
     825               0 :             poDS = (OGRDataSource*) OGROpen(osFullFilename, FALSE, NULL);
     826               0 :             if (poDS != NULL)
     827                 :                 break;
     828                 :         }
     829                 : 
     830               0 :         CSLDestroy( papszFileList );
     831                 :     }
     832                 : 
     833              22 :     if (poDS == NULL)
     834                 :     {
     835               0 :         if (pabyData != NULL && !bJSON && !bZIP &&
     836                 :             strstr((const char*)pabyData, "<wfs:FeatureCollection") == NULL &&
     837                 :             strstr((const char*)pabyData, "<gml:FeatureCollection") == NULL)
     838                 :         {
     839               0 :             if (nDataLen > 1000)
     840               0 :                 pabyData[1000] = 0;
     841                 :             CPLError(CE_Failure, CPLE_AppDefined,
     842               0 :                     "Error: cannot parse %s", pabyData);
     843                 :         }
     844               0 :         return NULL;
     845                 :     }
     846                 : 
     847              22 :     OGRLayer* poLayer = poDS->GetLayer(0);
     848              22 :     if (poLayer == NULL)
     849                 :     {
     850               0 :         OGRDataSource::DestroyDataSource(poDS);
     851               0 :         return NULL;
     852                 :     }
     853                 : 
     854              22 :     return poDS;
     855                 : }
     856                 : 
     857                 : /************************************************************************/
     858                 : /*                            GetLayerDefn()                            */
     859                 : /************************************************************************/
     860                 : 
     861             862 : OGRFeatureDefn * OGRWFSLayer::GetLayerDefn()
     862                 : {
     863             862 :     if (poFeatureDefn)
     864             848 :         return poFeatureDefn;
     865                 : 
     866              14 :     poDS->LoadMultipleLayerDefn(GetName(), pszNS, pszNSVal);
     867                 : 
     868              14 :     if (poFeatureDefn)
     869               6 :         return poFeatureDefn;
     870                 : 
     871               8 :     return BuildLayerDefn();
     872                 : }
     873                 : 
     874                 : /************************************************************************/
     875                 : /*                          BuildLayerDefn()                            */
     876                 : /************************************************************************/
     877                 : 
     878              90 : OGRFeatureDefn * OGRWFSLayer::BuildLayerDefn(OGRFeatureDefn* poSrcFDefn)
     879                 : {
     880              90 :     int bUnsetWidthPrecision = FALSE;
     881                 : 
     882              90 :     poFeatureDefn = new OGRFeatureDefn( pszName );
     883              90 :     poFeatureDefn->Reference();
     884                 : 
     885              90 :     OGRDataSource* poDS = NULL;
     886                 : 
     887              90 :     if (poSrcFDefn == NULL)
     888               8 :         poSrcFDefn = DescribeFeatureType();
     889              90 :     if (poSrcFDefn == NULL)
     890                 :     {
     891               0 :         poDS = FetchGetFeature(1);
     892               0 :         if (poDS == NULL)
     893                 :         {
     894               0 :             return poFeatureDefn;
     895                 :         }
     896               0 :         poSrcFDefn = poDS->GetLayer(0)->GetLayerDefn();
     897               0 :         bGotApproximateLayerDefn = TRUE;
     898                 :         /* We cannot trust width and precision based on a single feature */
     899               0 :         bUnsetWidthPrecision = TRUE;
     900                 :     }
     901                 : 
     902              90 :     CPLString osPropertyName = CPLURLGetValue(pszBaseURL, "PROPERTYNAME");
     903              90 :     const char* pszPropertyName = osPropertyName.c_str();
     904                 : 
     905                 :     int i;
     906              90 :     poFeatureDefn->SetGeomType(poSrcFDefn->GetGeomType());
     907             652 :     for(i=0;i<poSrcFDefn->GetFieldCount();i++)
     908                 :     {
     909             562 :         if (pszPropertyName[0] != 0)
     910                 :         {
     911               0 :             if (strstr(pszPropertyName,
     912                 :                        poSrcFDefn->GetFieldDefn(i)->GetNameRef()) != NULL)
     913               0 :                 poFeatureDefn->AddFieldDefn(poSrcFDefn->GetFieldDefn(i));
     914                 :             else
     915               0 :                 bGotApproximateLayerDefn = TRUE;
     916                 :         }
     917                 :         else
     918                 :         {
     919             562 :             OGRFieldDefn oFieldDefn(poSrcFDefn->GetFieldDefn(i));
     920             562 :             if (bUnsetWidthPrecision)
     921                 :             {
     922               0 :                 oFieldDefn.SetWidth(0);
     923               0 :                 oFieldDefn.SetPrecision(0);
     924                 :             }
     925             562 :             poFeatureDefn->AddFieldDefn(&oFieldDefn);
     926                 :         }
     927                 :     }
     928                 : 
     929              90 :     if (poDS)
     930               0 :         OGRDataSource::DestroyDataSource(poDS);
     931                 :     else
     932              90 :         delete poSrcFDefn;
     933                 : 
     934              90 :     return poFeatureDefn;
     935                 : }
     936                 : 
     937                 : /************************************************************************/
     938                 : /*                           GetSpatialRef()                            */
     939                 : /************************************************************************/
     940                 : 
     941              10 : OGRSpatialReference *OGRWFSLayer::GetSpatialRef()
     942                 : {
     943              10 :     GetLayerDefn();
     944              10 :     return poSRS;
     945                 : }
     946                 : 
     947                 : /************************************************************************/
     948                 : /*                            ResetReading()                            */
     949                 : /************************************************************************/
     950                 : 
     951             126 : void OGRWFSLayer::ResetReading()
     952                 : 
     953                 : {
     954             126 :     GetLayerDefn();
     955             126 :     if (bPagingActive)
     956               0 :         bReloadNeeded = TRUE;
     957             126 :     nPagingStartIndex = 0;
     958             126 :     nFeatureRead = 0;
     959             126 :     nFeatureCountRequested = 0;
     960             126 :     if (bReloadNeeded)
     961                 :     {
     962              14 :         OGRDataSource::DestroyDataSource(poBaseDS);
     963              14 :         poBaseDS = NULL;
     964              14 :         poBaseLayer = NULL;
     965              14 :         bHasFetched = FALSE;
     966              14 :         bReloadNeeded = FALSE;
     967                 :     }
     968             126 :     if (poBaseLayer)
     969              96 :         poBaseLayer->ResetReading();
     970             126 : }
     971                 : 
     972                 : 
     973                 : /************************************************************************/
     974                 : /*                           GetNextFeature()                           */
     975                 : /************************************************************************/
     976                 : 
     977             398 : OGRFeature *OGRWFSLayer::GetNextFeature()
     978                 : {
     979             398 :     GetLayerDefn();
     980             398 :     if (bPagingActive && nFeatureRead == nPagingStartIndex + nFeatureCountRequested)
     981                 :     {
     982               0 :         bReloadNeeded = TRUE;
     983               0 :         nPagingStartIndex = nFeatureRead;
     984                 :     }
     985             398 :     if (bReloadNeeded)
     986                 :     {
     987               4 :         OGRDataSource::DestroyDataSource(poBaseDS);
     988               4 :         poBaseDS = NULL;
     989               4 :         poBaseLayer = NULL;
     990               4 :         bHasFetched = FALSE;
     991               4 :         bReloadNeeded = FALSE;
     992                 :     }
     993             398 :     if (poBaseDS == NULL && !bHasFetched)
     994                 :     {
     995              22 :         bHasFetched = TRUE;
     996              22 :         poBaseDS = FetchGetFeature(0);
     997              22 :         if (poBaseDS)
     998                 :         {
     999              22 :             poBaseLayer = poBaseDS->GetLayer(0);
    1000              22 :             poBaseLayer->ResetReading();
    1001                 : 
    1002                 :             /* Check that the layer field definition is consistant with the one */
    1003                 :             /* we got in BuildLayerDefn() */
    1004              22 :             if (poFeatureDefn->GetFieldCount() != poBaseLayer->GetLayerDefn()->GetFieldCount())
    1005               2 :                 bGotApproximateLayerDefn = TRUE;
    1006                 :             else
    1007                 :             {
    1008                 :                 int iField;
    1009             154 :                 for(iField = 0;iField < poFeatureDefn->GetFieldCount(); iField++)
    1010                 :                 {
    1011             134 :                     OGRFieldDefn* poFDefn1 = poFeatureDefn->GetFieldDefn(iField);
    1012             134 :                     OGRFieldDefn* poFDefn2 = poBaseLayer->GetLayerDefn()->GetFieldDefn(iField);
    1013             134 :                     if (strcmp(poFDefn1->GetNameRef(), poFDefn2->GetNameRef()) != 0 ||
    1014                 :                         poFDefn1->GetType() != poFDefn2->GetType())
    1015                 :                     {
    1016               0 :                         bGotApproximateLayerDefn = TRUE;
    1017               0 :                         break;
    1018                 :                     }
    1019                 :                 }
    1020                 :             }
    1021                 :         }
    1022                 :     }
    1023             398 :     if (!poBaseLayer)
    1024               0 :         return NULL;
    1025                 : 
    1026              62 :     while(TRUE)
    1027                 :     {
    1028             460 :         OGRFeature* poSrcFeature = poBaseLayer->GetNextFeature();
    1029             460 :         if (poSrcFeature == NULL)
    1030              36 :             return NULL;
    1031             424 :         nFeatureRead ++;
    1032                 : 
    1033             424 :         OGRGeometry* poGeom = poSrcFeature->GetGeometryRef();
    1034             424 :         if( m_poFilterGeom != NULL && poGeom != NULL &&
    1035                 :             !FilterGeometry( poGeom ) )
    1036                 :         {
    1037              58 :             delete poSrcFeature;
    1038              58 :             continue;
    1039                 :         }
    1040                 : 
    1041                 :         /* Client-side attribue filtering with underlying layer defn */
    1042                 :         /* identical to exposed layer defn */
    1043             366 :         if( !bGotApproximateLayerDefn &&
    1044                 :             osWFSWhere.size() == 0 &&
    1045                 :             m_poAttrQuery != NULL &&
    1046                 :             !m_poAttrQuery->Evaluate( poSrcFeature ) )
    1047                 :         {
    1048               4 :             delete poSrcFeature;
    1049               4 :             continue;
    1050                 :         }
    1051                 : 
    1052             362 :         OGRFeature* poNewFeature = new OGRFeature(poFeatureDefn);
    1053             362 :         if (bGotApproximateLayerDefn)
    1054                 :         {
    1055              24 :             poNewFeature->SetFrom(poSrcFeature);
    1056                 : 
    1057                 :             /* Client-side attribue filtering */
    1058              24 :             if( m_poAttrQuery != NULL &&
    1059                 :                 osWFSWhere.size() == 0 &&
    1060                 :                 !m_poAttrQuery->Evaluate( poNewFeature ) )
    1061                 :             {
    1062               0 :                 delete poSrcFeature;
    1063               0 :                 delete poNewFeature;
    1064               0 :                 continue;
    1065                 :             }
    1066                 :         }
    1067                 :         else
    1068                 :         {
    1069                 :             int iField;
    1070            1694 :             for(iField = 0;iField < poFeatureDefn->GetFieldCount(); iField++)
    1071            1356 :                 poNewFeature->SetField( iField, poSrcFeature->GetRawFieldRef(iField) );
    1072             338 :             poNewFeature->SetStyleString(poSrcFeature->GetStyleString());
    1073             338 :             poNewFeature->SetGeometryDirectly(poSrcFeature->StealGeometry());
    1074                 :         }
    1075             362 :         poNewFeature->SetFID(poSrcFeature->GetFID());
    1076             362 :         poGeom = poNewFeature->GetGeometryRef();
    1077                 : 
    1078                 :         /* FIXME? I don't really know what we should do with WFS 1.1.0 */
    1079                 :         /* and non-GML format !!! I guess 50% WFS servers must do it wrong anyway */
    1080                 :         /* GeoServer does currently axis inversion for non GML output, but */
    1081                 :         /* apparently this is not correct : http://jira.codehaus.org/browse/GEOS-3657 */
    1082             362 :         if (bAxisOrderAlreadyInverted &&
    1083               0 :             strcmp(poBaseDS->GetDriver()->GetName(), "GML") != 0)
    1084                 :         {
    1085               0 :             poGeom->swapXY();
    1086                 :         }
    1087                 : 
    1088             362 :         if (poGeom && poSRS)
    1089             362 :             poGeom->assignSpatialReference(poSRS);
    1090             362 :         delete poSrcFeature;
    1091             362 :         return poNewFeature;
    1092                 :     }
    1093                 : }
    1094                 : 
    1095                 : /************************************************************************/
    1096                 : /*                         SetSpatialFilter()                           */
    1097                 : /************************************************************************/
    1098                 : 
    1099              26 : void OGRWFSLayer::SetSpatialFilter( OGRGeometry * poGeom )
    1100                 : {
    1101              46 :     if (poFetchedFilterGeom == NULL && poBaseDS != NULL)
    1102                 :     {
    1103                 :         /* If there was no filter set, and that we set one */
    1104                 :         /* the new result set can only be a subset of the whole */
    1105                 :         /* so no need to reload from source */
    1106              20 :         bReloadNeeded = FALSE;
    1107                 :     }
    1108               6 :     else if (poFetchedFilterGeom != NULL && poGeom != NULL && poBaseDS != NULL)
    1109                 :     {
    1110               0 :         OGREnvelope oOldEnvelope, oNewEnvelope;
    1111               0 :         poFetchedFilterGeom->getEnvelope(&oOldEnvelope);
    1112               0 :         poGeom->getEnvelope(&oNewEnvelope);
    1113                 :         /* Optimization : we don't need to request the server */
    1114                 :         /* if the new BBOX is inside the old BBOX as we have */
    1115                 :         /* already all the features */
    1116               0 :         bReloadNeeded = ! oOldEnvelope.Contains(oNewEnvelope);
    1117                 :     }
    1118                 :     else
    1119               6 :         bReloadNeeded = TRUE;
    1120              26 :     nFeatures = -1;
    1121              26 :     OGRLayer::SetSpatialFilter(poGeom);
    1122              26 :     ResetReading();
    1123              26 : }
    1124                 : 
    1125                 : /************************************************************************/
    1126                 : /*                        SetAttributeFilter()                          */
    1127                 : /************************************************************************/
    1128                 : 
    1129              34 : OGRErr OGRWFSLayer::SetAttributeFilter( const char * pszFilter )
    1130                 : {
    1131              34 :     if (pszFilter != NULL && pszFilter[0] == 0)
    1132               4 :         pszFilter = NULL;
    1133                 : 
    1134              34 :     OGRErr eErr = OGRLayer::SetAttributeFilter(pszFilter);
    1135              34 :     if (eErr != CE_None)
    1136               0 :         return eErr;
    1137                 : 
    1138              34 :     CPLString osOldWFSWhere(osWFSWhere);
    1139              34 :     if (poDS->HasMinOperators() && pszFilter != NULL)
    1140                 :     {
    1141              14 :         int bNeedsNullCheck = FALSE;
    1142                 :         int nVersion = (strcmp(poDS->GetVersion(),"1.0.0") == 0) ? 100 :
    1143              14 :                        (atoi(poDS->GetVersion()) >= 2) ? 200 : 110;
    1144                 :         osWFSWhere = WFS_TurnSQLFilterToOGCFilter(pszFilter,
    1145                 :                                               nVersion,
    1146                 :                                               poDS->PropertyIsNotEqualToSupported(),
    1147                 :                                               poDS->UseFeatureId() || bUseFeatureIdAtLayerLevel,
    1148                 :                                               poDS->DoesGmlObjectIdNeedGMLPrefix(),
    1149              14 :                                               &bNeedsNullCheck);
    1150              14 :         if (bNeedsNullCheck && !poDS->HasNullCheck())
    1151               0 :             osWFSWhere = "";
    1152              14 :         if (osWFSWhere.size() == 0)
    1153                 :         {
    1154               2 :             CPLDebug("WFS", "Using client-side only mode for filter \"%s\"", pszFilter);
    1155                 :         }
    1156                 :     }
    1157                 :     else
    1158              20 :         osWFSWhere = "";
    1159                 : 
    1160              34 :     osSQLWhere = (pszFilter) ? pszFilter : "";
    1161                 : 
    1162              34 :     if (osWFSWhere != osOldWFSWhere)
    1163              16 :         bReloadNeeded = TRUE;
    1164                 :     else
    1165              18 :         bReloadNeeded = FALSE;
    1166              34 :     nFeatures = -1;
    1167                 : 
    1168              34 :     return CE_None;
    1169                 : }
    1170                 : 
    1171                 : /************************************************************************/
    1172                 : /*                           TestCapability()                           */
    1173                 : /************************************************************************/
    1174                 : 
    1175              48 : int OGRWFSLayer::TestCapability( const char * pszCap )
    1176                 : 
    1177                 : {
    1178              48 :     if( EQUAL(pszCap,OLCFastFeatureCount) )
    1179                 :     {
    1180              32 :         if (nFeatures >= 0)
    1181               0 :             return TRUE;
    1182                 : 
    1183                 :         return poBaseLayer != NULL && m_poFilterGeom == NULL &&
    1184              32 :                m_poAttrQuery == NULL &&  poBaseLayer->TestCapability(pszCap);
    1185                 :     }
    1186                 : 
    1187              16 :     else if( EQUAL(pszCap,OLCFastGetExtent) )
    1188                 :     {
    1189               2 :         if (bHasExtents)
    1190               0 :             return TRUE;
    1191                 : 
    1192                 :         return poBaseLayer != NULL &&
    1193               2 :                poBaseLayer->TestCapability(pszCap);
    1194                 :     }
    1195                 : 
    1196              14 :     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
    1197               2 :         return poBaseLayer != NULL && poBaseLayer->TestCapability(pszCap);
    1198                 : 
    1199              12 :     else if( EQUAL(pszCap, OLCSequentialWrite) ||
    1200                 :              EQUAL(pszCap, OLCDeleteFeature) ||
    1201                 :              EQUAL(pszCap, OLCRandomWrite) )
    1202                 :     {
    1203               6 :         GetLayerDefn();
    1204                 :         return poDS->SupportTransactions() && poDS->UpdateMode() &&
    1205               6 :                poFeatureDefn->GetFieldIndex("gml_id") == 0;
    1206                 :     }
    1207               6 :     else if ( EQUAL(pszCap, OLCTransactions) )
    1208                 :     {
    1209               0 :         return poDS->SupportTransactions() && poDS->UpdateMode();
    1210                 :     }
    1211               6 :     else if( EQUAL(pszCap,OLCIgnoreFields) )
    1212                 :     {
    1213               0 :         return TRUE;
    1214                 :     }
    1215                 : 
    1216               6 :     return FALSE;
    1217                 : }
    1218                 : 
    1219                 : /************************************************************************/
    1220                 : /*                  ExecuteGetFeatureResultTypeHits()                   */
    1221                 : /************************************************************************/
    1222                 : 
    1223              12 : int OGRWFSLayer::ExecuteGetFeatureResultTypeHits()
    1224                 : {
    1225              12 :     char* pabyData = NULL;
    1226              12 :     CPLString osURL = MakeGetFeatureURL(0, TRUE);
    1227              12 :     if (pszRequiredOutputFormat)
    1228               4 :         osURL = CPLURLAddKVP(osURL, "OUTPUTFORMAT", pszRequiredOutputFormatURL);
    1229              12 :     CPLDebug("WFS", "%s", osURL.c_str());
    1230                 : 
    1231              12 :     CPLHTTPResult* psResult = poDS->HTTPFetch( osURL, NULL);
    1232              12 :     if (psResult == NULL)
    1233                 :     {
    1234               0 :         return -1;
    1235                 :     }
    1236                 : 
    1237                 :     /* http://demo.snowflakesoftware.com:8080/Obstacle_AIXM_ZIP/GOPublisherWFS returns */
    1238                 :     /* zip content, including for RESULTTYPE=hits */
    1239              12 :     if (psResult->pszContentType != NULL &&
    1240                 :         strstr(psResult->pszContentType, "application/zip") != NULL)
    1241                 :     {
    1242               0 :         CPLString osTmpFileName;
    1243               0 :         osTmpFileName.Printf("/vsimem/wfstemphits_%p.zip", this);
    1244                 :         VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName, psResult->pabyData,
    1245               0 :                                              psResult->nDataLen, FALSE);
    1246               0 :         VSIFCloseL(fp);
    1247                 : 
    1248               0 :         CPLString osZipTmpFileName("/vsizip/" + osTmpFileName);
    1249                 : 
    1250               0 :         char** papszDirContent = CPLReadDir(osZipTmpFileName);
    1251               0 :         if (CSLCount(papszDirContent) != 1)
    1252                 :         {
    1253                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1254               0 :                      "Cannot parse result of RESULTTYPE=hits request : more than one file in zip");
    1255               0 :             CSLDestroy(papszDirContent);
    1256               0 :             CPLHTTPDestroyResult(psResult);
    1257               0 :             VSIUnlink(osTmpFileName);
    1258               0 :             return -1;
    1259                 :         }
    1260                 : 
    1261               0 :         CPLString osFileInZipTmpFileName = osZipTmpFileName + "/";
    1262               0 :         osFileInZipTmpFileName += papszDirContent[0];
    1263                 : 
    1264               0 :         fp = VSIFOpenL(osFileInZipTmpFileName.c_str(), "rb");
    1265               0 :         if (fp == NULL)
    1266                 :         {
    1267                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1268               0 :                      "Cannot parse result of RESULTTYPE=hits request : cannot open one file in zip");
    1269               0 :             CSLDestroy(papszDirContent);
    1270               0 :             CPLHTTPDestroyResult(psResult);
    1271               0 :             VSIUnlink(osTmpFileName);
    1272               0 :             return -1;
    1273                 :         }
    1274                 :         VSIStatBufL sBuf;
    1275               0 :         VSIStatL(osFileInZipTmpFileName.c_str(), &sBuf);
    1276               0 :         pabyData = (char*) CPLMalloc((size_t)(sBuf.st_size + 1));
    1277               0 :         pabyData[sBuf.st_size] = 0;
    1278               0 :         VSIFReadL(pabyData, 1, (size_t)sBuf.st_size, fp);
    1279               0 :         VSIFCloseL(fp);
    1280                 : 
    1281               0 :         CSLDestroy(papszDirContent);
    1282               0 :         VSIUnlink(osTmpFileName);
    1283                 :     }
    1284                 :     else
    1285                 :     {
    1286              12 :         pabyData = (char*) psResult->pabyData;
    1287              12 :         psResult->pabyData = NULL;
    1288                 :     }
    1289                 : 
    1290              12 :     if (strstr(pabyData, "<ServiceExceptionReport") != NULL ||
    1291                 :         strstr(pabyData, "<ows:ExceptionReport") != NULL)
    1292                 :     {
    1293               0 :         if (poDS->IsOldDeegree(pabyData))
    1294                 :         {
    1295               0 :             CPLHTTPDestroyResult(psResult);
    1296               0 :             return ExecuteGetFeatureResultTypeHits();
    1297                 :         }
    1298                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
    1299               0 :                  pabyData);
    1300               0 :         CPLHTTPDestroyResult(psResult);
    1301               0 :         CPLFree(pabyData);
    1302               0 :         return -1;
    1303                 :     }
    1304                 : 
    1305              12 :     CPLXMLNode* psXML = CPLParseXMLString( pabyData );
    1306              12 :     if (psXML == NULL)
    1307                 :     {
    1308                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
    1309               0 :                 pabyData);
    1310               0 :         CPLHTTPDestroyResult(psResult);
    1311               0 :         CPLFree(pabyData);
    1312               0 :         return -1;
    1313                 :     }
    1314                 : 
    1315              12 :     CPLStripXMLNamespace( psXML, NULL, TRUE );
    1316              12 :     CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=FeatureCollection" );
    1317              12 :     if (psRoot == NULL)
    1318                 :     {
    1319               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <FeatureCollection>");
    1320               0 :         CPLDestroyXMLNode( psXML );
    1321               0 :         CPLHTTPDestroyResult(psResult);
    1322               0 :         CPLFree(pabyData);
    1323               0 :         return -1;
    1324                 :     }
    1325                 : 
    1326              12 :     const char* pszValue = CPLGetXMLValue(psRoot, "numberOfFeatures", NULL);
    1327              12 :     if (pszValue == NULL)
    1328               8 :         pszValue = CPLGetXMLValue(psRoot, "numberMatched", NULL); /* WFS 2.0.0 */
    1329              12 :     if (pszValue == NULL)
    1330                 :     {
    1331               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find numberOfFeatures");
    1332               0 :         CPLDestroyXMLNode( psXML );
    1333               0 :         CPLHTTPDestroyResult(psResult);
    1334               0 :         CPLFree(pabyData);
    1335                 :         
    1336               0 :         poDS->DisableSupportHits();
    1337               0 :         return -1;
    1338                 :     }
    1339                 : 
    1340              12 :     int nFeatures = atoi(pszValue);
    1341                 :     /* Hum, http://deegree3-testing.deegree.org:80/deegree-inspire-node/services?MAXFEATURES=10&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=ad:Address&OUTPUTFORMAT=text/xml;%20subtype=gml/3.2.1&RESULTTYPE=hits */
    1342                 :     /* returns more than MAXFEATURES features... So truncate to MAXFEATURES */
    1343              12 :     CPLString osMaxFeatures = CPLURLGetValue(osURL, atoi(poDS->GetVersion()) >= 2 ? "COUNT" : "MAXFEATURES");
    1344              12 :     if (osMaxFeatures.size() != 0)
    1345                 :     {
    1346               4 :         int nMaxFeatures = atoi(osMaxFeatures);
    1347               4 :         if (nFeatures > nMaxFeatures)
    1348                 :         {
    1349               2 :             CPLDebug("WFS", "Truncating result from %d to %d", nFeatures, nMaxFeatures);
    1350               2 :             nFeatures = nMaxFeatures;
    1351                 :         }
    1352                 :     }
    1353                 : 
    1354              12 :     CPLDestroyXMLNode( psXML );
    1355              12 :     CPLHTTPDestroyResult(psResult);
    1356              12 :     CPLFree(pabyData);
    1357                 : 
    1358              12 :     return nFeatures;
    1359                 : }
    1360                 : 
    1361                 : /************************************************************************/
    1362                 : /*                           GetFeatureCount()                          */
    1363                 : /************************************************************************/
    1364                 : 
    1365              34 : int OGRWFSLayer::GetFeatureCount( int bForce )
    1366                 : {
    1367              34 :     if (nFeatures >= 0)
    1368               2 :         return nFeatures;
    1369                 : 
    1370              32 :     if (TestCapability(OLCFastFeatureCount))
    1371               4 :         return poBaseLayer->GetFeatureCount(bForce);
    1372                 : 
    1373              28 :     if ((m_poAttrQuery == NULL || osWFSWhere.size() != 0) &&
    1374                 :          poDS->GetFeatureSupportHits())
    1375                 :     {
    1376              12 :         nFeatures = ExecuteGetFeatureResultTypeHits();
    1377              12 :         if (nFeatures >= 0)
    1378              12 :             return nFeatures;
    1379                 :     }
    1380                 :     
    1381              16 :     nFeatures = OGRLayer::GetFeatureCount(bForce);
    1382              16 :     return nFeatures;
    1383                 : }
    1384                 : 
    1385                 : 
    1386                 : /************************************************************************/
    1387                 : /*                              SetExtent()                             */
    1388                 : /************************************************************************/
    1389                 : 
    1390               0 : void OGRWFSLayer::SetExtents(double dfMinX, double dfMinY, double dfMaxX, double dfMaxY)
    1391                 : {
    1392               0 :     this->dfMinX = dfMinX;
    1393               0 :     this->dfMinY = dfMinY;
    1394               0 :     this->dfMaxX = dfMaxX;
    1395               0 :     this->dfMaxY = dfMaxY;
    1396               0 :     bHasExtents = TRUE;
    1397               0 : }
    1398                 : 
    1399                 : /************************************************************************/
    1400                 : /*                              GetExtent()                             */
    1401                 : /************************************************************************/
    1402                 : 
    1403               2 : OGRErr OGRWFSLayer::GetExtent(OGREnvelope *psExtent, int bForce)
    1404                 : {
    1405               2 :     if (bHasExtents)
    1406                 :     {
    1407               0 :         psExtent->MinX = dfMinX;
    1408               0 :         psExtent->MinY = dfMinY;
    1409               0 :         psExtent->MaxX = dfMaxX;
    1410               0 :         psExtent->MaxY = dfMaxY;
    1411               0 :         return OGRERR_NONE;
    1412                 :     }
    1413                 : 
    1414               2 :     if (TestCapability(OLCFastGetExtent))
    1415               0 :         return poBaseLayer->GetExtent(psExtent, bForce);
    1416                 : 
    1417               2 :     return OGRLayer::GetExtent(psExtent, bForce);
    1418                 : }
    1419                 : 
    1420                 : /************************************************************************/
    1421                 : /*                          GetShortName()                              */
    1422                 : /************************************************************************/
    1423                 : 
    1424            3924 : const char* OGRWFSLayer::GetShortName()
    1425                 : {
    1426            3924 :     const char* pszShortName = strchr(pszName, ':');
    1427            3924 :     if (pszShortName == NULL)
    1428              36 :         pszShortName = pszName;
    1429                 :     else
    1430            3888 :         pszShortName ++;
    1431            3924 :     return pszShortName;
    1432                 : }
    1433                 : 
    1434                 : 
    1435                 : /************************************************************************/
    1436                 : /*                          GetPostHeader()                             */
    1437                 : /************************************************************************/
    1438                 : 
    1439               0 : CPLString OGRWFSLayer::GetPostHeader()
    1440                 : {
    1441               0 :     CPLString osPost;
    1442               0 :     osPost += "<?xml version=\"1.0\"?>\n";
    1443               0 :     osPost += "<wfs:Transaction xmlns:wfs=\"http://www.opengis.net/wfs\"\n";
    1444               0 :     osPost += "                 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
    1445               0 :     osPost += "                 service=\"WFS\" version=\""; osPost += poDS->GetVersion(); osPost += "\"\n";
    1446               0 :     osPost += "                 xmlns:gml=\"http://www.opengis.net/gml\"\n";
    1447               0 :     osPost += "                 xmlns:ogc=\"http://www.opengis.net/ogc\"\n";
    1448               0 :     osPost += "                 xsi:schemaLocation=\"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/";
    1449               0 :     osPost += poDS->GetVersion();
    1450               0 :     osPost += "/wfs.xsd ";
    1451               0 :     osPost += osTargetNamespace;
    1452               0 :     osPost += " ";
    1453                 : 
    1454                 :     char* pszXMLEncoded = CPLEscapeString(
    1455               0 :                     GetDescribeFeatureTypeURL(FALSE), -1, CPLES_XML);
    1456               0 :     osPost += pszXMLEncoded;
    1457               0 :     CPLFree(pszXMLEncoded);
    1458                 : 
    1459               0 :     osPost += "\">\n";
    1460                 : 
    1461               0 :     return osPost;
    1462                 : }
    1463                 : 
    1464                 : /************************************************************************/
    1465                 : /*                          CreateFeature()                             */
    1466                 : /************************************************************************/
    1467                 : 
    1468               0 : OGRErr OGRWFSLayer::CreateFeature( OGRFeature *poFeature )
    1469                 : {
    1470               0 :     if (!TestCapability(OLCSequentialWrite))
    1471                 :     {
    1472               0 :         if (!poDS->SupportTransactions())
    1473                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1474               0 :                      "CreateFeature() not supported: no WMS-T features advertized by server");
    1475               0 :         else if (!poDS->UpdateMode())
    1476                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1477               0 :                      "CreateFeature() not supported: datasource opened as read-only");
    1478               0 :         return OGRERR_FAILURE;
    1479                 :     }
    1480                 : 
    1481               0 :     if (poGMLFeatureClass == NULL)
    1482                 :     {
    1483                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1484               0 :                  "Cannot insert feature because we didn't manage to parse the .XSD schema");
    1485               0 :         return OGRERR_FAILURE;
    1486                 :     }
    1487                 : 
    1488               0 :     if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
    1489                 :     {
    1490                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1491               0 :                  "Cannot find gml_id field");
    1492               0 :         return OGRERR_FAILURE;
    1493                 :     }
    1494                 : 
    1495               0 :     if (poFeature->IsFieldSet(0))
    1496                 :     {
    1497                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1498               0 :                  "Cannot insert a feature when gml_id field is already set");
    1499               0 :         return OGRERR_FAILURE;
    1500                 :     }
    1501                 : 
    1502               0 :     CPLString osPost;
    1503                 : 
    1504               0 :     const char* pszShortName = GetShortName();
    1505                 : 
    1506               0 :     if (!bInTransaction)
    1507                 :     {
    1508               0 :         osPost += GetPostHeader();
    1509               0 :         osPost += "  <wfs:Insert>\n";
    1510                 :     }
    1511               0 :     osPost += "    <feature:"; osPost += pszShortName; osPost += " xmlns:feature=\"";
    1512               0 :     osPost += osTargetNamespace; osPost += "\">\n";
    1513                 : 
    1514                 :     int i;
    1515               0 :     for(i=1; i <= poFeature->GetFieldCount(); i++)
    1516                 :     {
    1517               0 :         if (poGMLFeatureClass->GetGeometryAttributeIndex() == i - 1)
    1518                 :         {
    1519               0 :             OGRGeometry* poGeom = poFeature->GetGeometryRef();
    1520               0 :             if (poGeom != NULL && osGeometryColumnName.size() != 0)
    1521                 :             {
    1522               0 :                 if (poGeom->getSpatialReference() == NULL)
    1523               0 :                     poGeom->assignSpatialReference(poSRS);
    1524                 :                 char* pszGML;
    1525               0 :                 if (strcmp(poDS->GetVersion(), "1.1.0") == 0)
    1526                 :                 {
    1527               0 :                     char** papszOptions = CSLAddString(NULL, "FORMAT=GML3");
    1528               0 :                     pszGML = OGR_G_ExportToGMLEx((OGRGeometryH)poGeom, papszOptions);
    1529               0 :                     CSLDestroy(papszOptions);
    1530                 :                 }
    1531                 :                 else
    1532               0 :                     pszGML = OGR_G_ExportToGML((OGRGeometryH)poGeom);
    1533               0 :                 osPost += "      <feature:"; osPost += osGeometryColumnName; osPost += ">";
    1534               0 :                 osPost += pszGML;
    1535               0 :                 osPost += "</feature:"; osPost += osGeometryColumnName; osPost += ">\n";
    1536               0 :                 CPLFree(pszGML);
    1537                 :             }
    1538                 :         }
    1539               0 :         if (i == poFeature->GetFieldCount())
    1540               0 :             break;
    1541                 : 
    1542               0 :         if (poFeature->IsFieldSet(i))
    1543                 :         {
    1544               0 :             OGRFieldDefn* poFDefn = poFeature->GetFieldDefnRef(i);
    1545               0 :             osPost += "      <feature:";
    1546               0 :             osPost += poFDefn->GetNameRef();
    1547               0 :             osPost += ">";
    1548               0 :             if (poFDefn->GetType() == OFTInteger)
    1549               0 :                 osPost += CPLSPrintf("%d", poFeature->GetFieldAsInteger(i));
    1550               0 :             else if (poFDefn->GetType() == OFTReal)
    1551               0 :                 osPost += CPLSPrintf("%.16g", poFeature->GetFieldAsDouble(i));
    1552                 :             else
    1553                 :             {
    1554                 :                 char* pszXMLEncoded = CPLEscapeString(poFeature->GetFieldAsString(i),
    1555               0 :                                                 -1, CPLES_XML);
    1556               0 :                 osPost += pszXMLEncoded;
    1557               0 :                 CPLFree(pszXMLEncoded);
    1558                 :             }
    1559               0 :             osPost += "</feature:";
    1560               0 :             osPost += poFDefn->GetNameRef();
    1561               0 :             osPost += ">\n";
    1562                 :         }
    1563                 : 
    1564                 :     }
    1565                 :     
    1566               0 :     osPost += "    </feature:"; osPost += pszShortName; osPost += ">\n";
    1567                 : 
    1568               0 :     if (!bInTransaction)
    1569                 :     {
    1570               0 :         osPost += "  </wfs:Insert>\n";
    1571               0 :         osPost += "</wfs:Transaction>\n";
    1572                 :     }
    1573                 :     else
    1574                 :     {
    1575               0 :         osGlobalInsert += osPost;
    1576               0 :         nExpectedInserts ++;
    1577               0 :         return OGRERR_NONE;
    1578                 :     }
    1579                 : 
    1580               0 :     CPLDebug("WFS", "Post : %s", osPost.c_str());
    1581                 : 
    1582               0 :     char** papszOptions = NULL;
    1583               0 :     papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
    1584                 :     papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
    1585               0 :                                    "Content-Type: application/xml; charset=UTF-8");
    1586                 : 
    1587               0 :     CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
    1588               0 :     CSLDestroy(papszOptions);
    1589                 : 
    1590               0 :     if (psResult == NULL)
    1591                 :     {
    1592               0 :         return OGRERR_FAILURE;
    1593                 :     }
    1594                 : 
    1595               0 :     if (strstr((const char*)psResult->pabyData,
    1596                 :                                     "<ServiceExceptionReport") != NULL ||
    1597                 :         strstr((const char*)psResult->pabyData,
    1598                 :                                     "<ows:ExceptionReport") != NULL)
    1599                 :     {
    1600                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
    1601               0 :                  psResult->pabyData);
    1602               0 :         CPLHTTPDestroyResult(psResult);
    1603               0 :         return OGRERR_FAILURE;
    1604                 :     }
    1605                 : 
    1606               0 :     CPLDebug("WFS", "Response: %s", psResult->pabyData);
    1607                 : 
    1608               0 :     CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
    1609               0 :     if (psXML == NULL)
    1610                 :     {
    1611                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
    1612               0 :                 psResult->pabyData);
    1613               0 :         CPLHTTPDestroyResult(psResult);
    1614               0 :         return OGRERR_FAILURE;
    1615                 :     }
    1616                 : 
    1617               0 :     CPLStripXMLNamespace( psXML, NULL, TRUE );
    1618               0 :     int bUse100Schema = FALSE;
    1619               0 :     CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
    1620               0 :     if (psRoot == NULL)
    1621                 :     {
    1622               0 :         psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
    1623               0 :         if (psRoot)
    1624               0 :             bUse100Schema = TRUE;
    1625                 :     }
    1626                 : 
    1627               0 :     if (psRoot == NULL)
    1628                 :     {
    1629                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1630               0 :                  "Cannot find <TransactionResponse>");
    1631               0 :         CPLDestroyXMLNode( psXML );
    1632               0 :         CPLHTTPDestroyResult(psResult);
    1633               0 :         return OGRERR_FAILURE;
    1634                 :     }
    1635                 : 
    1636               0 :     CPLXMLNode* psFeatureID = NULL;
    1637                 : 
    1638               0 :     if (bUse100Schema)
    1639                 :     {
    1640               0 :         if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
    1641                 :         {
    1642                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1643                 :                      "Insert failed : %s",
    1644               0 :                      psResult->pabyData);
    1645               0 :             CPLDestroyXMLNode( psXML );
    1646               0 :             CPLHTTPDestroyResult(psResult);
    1647               0 :             return OGRERR_FAILURE;
    1648                 :         }
    1649                 : 
    1650                 :         psFeatureID =
    1651               0 :             CPLGetXMLNode( psRoot, "InsertResult.FeatureId");
    1652               0 :         if (psFeatureID == NULL)
    1653                 :         {
    1654                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1655               0 :                     "Cannot find InsertResult.FeatureId");
    1656               0 :             CPLDestroyXMLNode( psXML );
    1657               0 :             CPLHTTPDestroyResult(psResult);
    1658               0 :             return OGRERR_FAILURE;
    1659                 :         }
    1660                 :     }
    1661                 :     else
    1662                 :     {
    1663                 :         psFeatureID =
    1664               0 :             CPLGetXMLNode( psRoot, "InsertResults.Feature.FeatureId");
    1665               0 :         if (psFeatureID == NULL)
    1666                 :         {
    1667                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1668               0 :                     "Cannot find InsertResults.Feature.FeatureId");
    1669               0 :             CPLDestroyXMLNode( psXML );
    1670               0 :             CPLHTTPDestroyResult(psResult);
    1671               0 :             return OGRERR_FAILURE;
    1672                 :         }
    1673                 :     }
    1674                 : 
    1675               0 :     const char* pszFID = CPLGetXMLValue(psFeatureID, "fid", NULL);
    1676               0 :     if (pszFID == NULL)
    1677                 :     {
    1678               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find fid");
    1679               0 :         CPLDestroyXMLNode( psXML );
    1680               0 :         CPLHTTPDestroyResult(psResult);
    1681               0 :         return OGRERR_FAILURE;
    1682                 :     }
    1683                 : 
    1684               0 :     poFeature->SetField("gml_id", pszFID);
    1685                 : 
    1686                 :     /* If the returned fid is of the form layer_name.num, then use */
    1687                 :     /* num as the OGR FID */
    1688               0 :     if (strncmp(pszFID, pszShortName, strlen(pszShortName)) == 0 &&
    1689               0 :         pszFID[strlen(pszShortName)] == '.')
    1690                 :     {
    1691               0 :         int nFID = atoi(pszFID + strlen(pszShortName) + 1);
    1692                 :         char szTemp[12];
    1693               0 :         sprintf(szTemp, "%d", nFID);
    1694                 :         /* Check that it fits on a int32 */
    1695               0 :         if (strcmp(szTemp, pszFID + strlen(pszShortName) + 1) == 0)
    1696               0 :             poFeature->SetFID(nFID);
    1697                 :     }
    1698                 : 
    1699               0 :     CPLDebug("WFS", "Got FID = %ld", poFeature->GetFID());
    1700                 : 
    1701               0 :     CPLDestroyXMLNode( psXML );
    1702               0 :     CPLHTTPDestroyResult(psResult);
    1703                 : 
    1704                 :     /* Invalidate layer */
    1705               0 :     bReloadNeeded = TRUE;
    1706               0 :     nFeatures = -1;
    1707                 : 
    1708               0 :     return OGRERR_NONE;
    1709                 : }
    1710                 : 
    1711                 : 
    1712                 : /************************************************************************/
    1713                 : /*                             SetFeature()                             */
    1714                 : /************************************************************************/
    1715                 : 
    1716               0 : OGRErr OGRWFSLayer::SetFeature( OGRFeature *poFeature )
    1717                 : {
    1718               0 :     if (!TestCapability(OLCRandomWrite))
    1719                 :     {
    1720               0 :         if (!poDS->SupportTransactions())
    1721                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1722               0 :                      "SetFeature() not supported: no WMS-T features advertized by server");
    1723               0 :         else if (!poDS->UpdateMode())
    1724                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1725               0 :                      "SetFeature() not supported: datasource opened as read-only");
    1726               0 :         return OGRERR_FAILURE;
    1727                 :     }
    1728                 : 
    1729               0 :     if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
    1730                 :     {
    1731                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1732               0 :                  "Cannot find gml_id field");
    1733               0 :         return OGRERR_FAILURE;
    1734                 :     }
    1735                 : 
    1736               0 :     if (poFeature->IsFieldSet(0) == FALSE)
    1737                 :     {
    1738                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1739               0 :                  "Cannot update a feature when gml_id field is not set");
    1740               0 :         return OGRERR_FAILURE;
    1741                 :     }
    1742                 : 
    1743               0 :     if (bInTransaction)
    1744                 :     {
    1745                 :         CPLError(CE_Warning, CPLE_AppDefined,
    1746               0 :                  "SetFeature() not yet dealt in transaction. Issued immediately");
    1747                 :     }
    1748                 : 
    1749               0 :     const char* pszShortName = GetShortName();
    1750                 : 
    1751               0 :     CPLString osPost;
    1752               0 :     osPost += GetPostHeader();
    1753                 : 
    1754               0 :     osPost += "  <wfs:Update typeName=\"feature:"; osPost += pszShortName; osPost +=  "\" xmlns:feature=\"";
    1755               0 :     osPost += osTargetNamespace; osPost += "\">\n";
    1756                 : 
    1757               0 :     OGRGeometry* poGeom = poFeature->GetGeometryRef();
    1758               0 :     if ( osGeometryColumnName.size() != 0 )
    1759                 :     {
    1760               0 :         osPost += "    <wfs:Property>\n";
    1761               0 :         osPost += "      <wfs:Name>"; osPost += osGeometryColumnName; osPost += "</wfs:Name>\n";
    1762               0 :         if (poGeom != NULL)
    1763                 :         {
    1764               0 :             if (poGeom->getSpatialReference() == NULL)
    1765               0 :                 poGeom->assignSpatialReference(poSRS);
    1766                 :             char* pszGML;
    1767               0 :             if (strcmp(poDS->GetVersion(), "1.1.0") == 0)
    1768                 :             {
    1769               0 :                 char** papszOptions = CSLAddString(NULL, "FORMAT=GML3");
    1770               0 :                 pszGML = OGR_G_ExportToGMLEx((OGRGeometryH)poGeom, papszOptions);
    1771               0 :                 CSLDestroy(papszOptions);
    1772                 :             }
    1773                 :             else
    1774               0 :                 pszGML = OGR_G_ExportToGML((OGRGeometryH)poGeom);
    1775               0 :             osPost += "      <wfs:Value>";
    1776               0 :             osPost += pszGML;
    1777               0 :             osPost += "</wfs:Value>\n";
    1778               0 :             CPLFree(pszGML);
    1779                 :         }
    1780               0 :         osPost += "    </wfs:Property>\n";
    1781                 :     }
    1782                 : 
    1783                 :     int i;
    1784               0 :     for(i=1; i < poFeature->GetFieldCount(); i++)
    1785                 :     {
    1786               0 :         OGRFieldDefn* poFDefn = poFeature->GetFieldDefnRef(i);
    1787                 : 
    1788               0 :         osPost += "    <wfs:Property>\n";
    1789               0 :         osPost += "      <wfs:Name>"; osPost += poFDefn->GetNameRef(); osPost += "</wfs:Name>\n";
    1790               0 :         if (poFeature->IsFieldSet(i))
    1791                 :         {
    1792               0 :             osPost += "      <wfs:Value>";
    1793               0 :             if (poFDefn->GetType() == OFTInteger)
    1794               0 :                 osPost += CPLSPrintf("%d", poFeature->GetFieldAsInteger(i));
    1795               0 :             else if (poFDefn->GetType() == OFTReal)
    1796               0 :                 osPost += CPLSPrintf("%.16g", poFeature->GetFieldAsDouble(i));
    1797                 :             else
    1798                 :             {
    1799                 :                 char* pszXMLEncoded = CPLEscapeString(poFeature->GetFieldAsString(i),
    1800               0 :                                                 -1, CPLES_XML);
    1801               0 :                 osPost += pszXMLEncoded;
    1802               0 :                 CPLFree(pszXMLEncoded);
    1803                 :             }
    1804               0 :             osPost += "</wfs:Value>\n";
    1805                 :         }
    1806               0 :         osPost += "    </wfs:Property>\n";
    1807                 :     }
    1808               0 :     osPost += "    <ogc:Filter>\n";
    1809               0 :     if (poDS->UseFeatureId() || bUseFeatureIdAtLayerLevel)
    1810               0 :         osPost += "      <ogc:FeatureId fid=\"";
    1811               0 :     else if (atoi(poDS->GetVersion()) >= 2)
    1812               0 :         osPost += "      <ogc:ResourceId rid=\"";
    1813                 :     else
    1814               0 :         osPost += "      <ogc:GmlObjectId gml:id=\"";
    1815               0 :     osPost += poFeature->GetFieldAsString(0); osPost += "\"/>\n";
    1816               0 :     osPost += "    </ogc:Filter>\n";
    1817               0 :     osPost += "  </wfs:Update>\n";
    1818               0 :     osPost += "</wfs:Transaction>\n";
    1819                 : 
    1820               0 :     CPLDebug("WFS", "Post : %s", osPost.c_str());
    1821                 : 
    1822               0 :     char** papszOptions = NULL;
    1823               0 :     papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
    1824                 :     papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
    1825               0 :                                    "Content-Type: application/xml; charset=UTF-8");
    1826                 : 
    1827               0 :     CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
    1828               0 :     CSLDestroy(papszOptions);
    1829                 : 
    1830               0 :     if (psResult == NULL)
    1831                 :     {
    1832               0 :         return OGRERR_FAILURE;
    1833                 :     }
    1834                 : 
    1835               0 :     if (strstr((const char*)psResult->pabyData,
    1836                 :                                     "<ServiceExceptionReport") != NULL ||
    1837                 :         strstr((const char*)psResult->pabyData,
    1838                 :                                     "<ows:ExceptionReport") != NULL)
    1839                 :     {
    1840                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
    1841               0 :                  psResult->pabyData);
    1842               0 :         CPLHTTPDestroyResult(psResult);
    1843               0 :         return OGRERR_FAILURE;
    1844                 :     }
    1845                 : 
    1846               0 :     CPLDebug("WFS", "Response: %s", psResult->pabyData);
    1847                 : 
    1848               0 :     CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
    1849               0 :     if (psXML == NULL)
    1850                 :     {
    1851                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
    1852               0 :                 psResult->pabyData);
    1853               0 :         CPLHTTPDestroyResult(psResult);
    1854               0 :         return OGRERR_FAILURE;
    1855                 :     }
    1856                 : 
    1857               0 :     CPLStripXMLNamespace( psXML, NULL, TRUE );
    1858               0 :     int bUse100Schema = FALSE;
    1859               0 :     CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
    1860               0 :     if (psRoot == NULL)
    1861                 :     {
    1862               0 :         psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
    1863               0 :         if (psRoot)
    1864               0 :             bUse100Schema = TRUE;
    1865                 :     }
    1866               0 :     if (psRoot == NULL)
    1867                 :     {
    1868                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1869               0 :                  "Cannot find <TransactionResponse>");
    1870               0 :         CPLDestroyXMLNode( psXML );
    1871               0 :         CPLHTTPDestroyResult(psResult);
    1872               0 :         return OGRERR_FAILURE;
    1873                 :     }
    1874                 : 
    1875               0 :     if (bUse100Schema)
    1876                 :     {
    1877               0 :         if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
    1878                 :         {
    1879                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1880                 :                      "Update failed : %s",
    1881               0 :                      psResult->pabyData);
    1882               0 :             CPLDestroyXMLNode( psXML );
    1883               0 :             CPLHTTPDestroyResult(psResult);
    1884               0 :             return OGRERR_FAILURE;
    1885                 :         }
    1886                 :     }
    1887                 : 
    1888               0 :     CPLDestroyXMLNode( psXML );
    1889               0 :     CPLHTTPDestroyResult(psResult);
    1890                 : 
    1891                 :     /* Invalidate layer */
    1892               0 :     bReloadNeeded = TRUE;
    1893               0 :     nFeatures = -1;
    1894                 : 
    1895               0 :     return OGRERR_NONE;
    1896                 : }
    1897                 : /************************************************************************/
    1898                 : /*                               GetFeature()                           */
    1899                 : /************************************************************************/
    1900                 : 
    1901               4 : OGRFeature* OGRWFSLayer::GetFeature(long nFID)
    1902                 : {
    1903               4 :     GetLayerDefn();
    1904               4 :     if (poBaseLayer == NULL && poFeatureDefn->GetFieldIndex("gml_id") == 0)
    1905                 :     {
    1906                 :         /* This is lovely hackish. We assume that then gml_id will be */
    1907                 :         /* layer_name.number. This is actually what we can observe with */
    1908                 :         /* GeoServer and TinyOWS */
    1909               0 :         CPLString osVal = CPLSPrintf("gml_id = '%s.%ld'", GetShortName(), nFID);
    1910               0 :         CPLString osOldSQLWhere(osSQLWhere);
    1911               0 :         SetAttributeFilter(osVal);
    1912               0 :         OGRFeature* poFeature = GetNextFeature();
    1913               0 :         const char* pszOldFilter = osOldSQLWhere.size() ? osOldSQLWhere.c_str() : NULL;
    1914               0 :         SetAttributeFilter(pszOldFilter);
    1915               0 :         if (poFeature)
    1916               0 :             return poFeature;
    1917                 :     }
    1918                 : 
    1919               4 :     return OGRLayer::GetFeature(nFID);
    1920                 : }
    1921                 : 
    1922                 : /************************************************************************/
    1923                 : /*                         DeleteFromFilter()                           */
    1924                 : /************************************************************************/
    1925                 : 
    1926               0 : OGRErr OGRWFSLayer::DeleteFromFilter( CPLString osOGCFilter )
    1927                 : {
    1928               0 :     if (!TestCapability(OLCDeleteFeature))
    1929                 :     {
    1930               0 :         if (!poDS->SupportTransactions())
    1931                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1932               0 :                      "DeleteFromFilter() not supported: no WMS-T features advertized by server");
    1933               0 :         else if (!poDS->UpdateMode())
    1934                 :             CPLError(CE_Failure, CPLE_AppDefined,
    1935               0 :                      "DeleteFromFilter() not supported: datasource opened as read-only");
    1936               0 :         return OGRERR_FAILURE;
    1937                 :     }
    1938                 : 
    1939               0 :     if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
    1940                 :     {
    1941                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1942               0 :                  "Cannot find gml_id field");
    1943               0 :         return OGRERR_FAILURE;
    1944                 :     }
    1945               0 :     const char* pszShortName = GetShortName();
    1946                 : 
    1947               0 :     CPLString osPost;
    1948               0 :     osPost += GetPostHeader();
    1949                 : 
    1950               0 :     osPost += "  <wfs:Delete xmlns:feature=\""; osPost += osTargetNamespace;
    1951               0 :     osPost += "\" typeName=\"feature:"; osPost += pszShortName; osPost += "\">\n";
    1952               0 :     osPost += "    <ogc:Filter>\n";
    1953               0 :     osPost += osOGCFilter;
    1954               0 :     osPost += "    </ogc:Filter>\n";
    1955               0 :     osPost += "  </wfs:Delete>\n";
    1956               0 :     osPost += "</wfs:Transaction>\n";
    1957                 : 
    1958               0 :     CPLDebug("WFS", "Post : %s", osPost.c_str());
    1959                 : 
    1960               0 :     char** papszOptions = NULL;
    1961               0 :     papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
    1962                 :     papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
    1963               0 :                                    "Content-Type: application/xml; charset=UTF-8");
    1964                 : 
    1965               0 :     CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
    1966               0 :     CSLDestroy(papszOptions);
    1967                 : 
    1968               0 :     if (psResult == NULL)
    1969                 :     {
    1970               0 :         return OGRERR_FAILURE;
    1971                 :     }
    1972                 : 
    1973               0 :     if (strstr((const char*)psResult->pabyData, "<ServiceExceptionReport") != NULL ||
    1974                 :         strstr((const char*)psResult->pabyData, "<ows:ExceptionReport") != NULL)
    1975                 :     {
    1976                 :         CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
    1977               0 :                  psResult->pabyData);
    1978               0 :         CPLHTTPDestroyResult(psResult);
    1979               0 :         return OGRERR_FAILURE;
    1980                 :     }
    1981                 : 
    1982               0 :     CPLDebug("WFS", "Response: %s", psResult->pabyData);
    1983                 : 
    1984               0 :     CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
    1985               0 :     if (psXML == NULL)
    1986                 :     {
    1987                 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
    1988               0 :                 psResult->pabyData);
    1989               0 :         CPLHTTPDestroyResult(psResult);
    1990               0 :         return OGRERR_FAILURE;
    1991                 :     }
    1992                 : 
    1993               0 :     CPLStripXMLNamespace( psXML, NULL, TRUE );
    1994               0 :     int bUse100Schema = FALSE;
    1995               0 :     CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
    1996               0 :     if (psRoot == NULL)
    1997                 :     {
    1998               0 :         psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
    1999               0 :         if (psRoot)
    2000               0 :             bUse100Schema = TRUE;
    2001                 :     }
    2002               0 :     if (psRoot == NULL)
    2003                 :     {
    2004               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <TransactionResponse>");
    2005               0 :         CPLDestroyXMLNode( psXML );
    2006               0 :         CPLHTTPDestroyResult(psResult);
    2007               0 :         return OGRERR_FAILURE;
    2008                 :     }
    2009                 : 
    2010               0 :     if (bUse100Schema)
    2011                 :     {
    2012               0 :         if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
    2013                 :         {
    2014                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2015                 :                      "Delete failed : %s",
    2016               0 :                      psResult->pabyData);
    2017               0 :             CPLDestroyXMLNode( psXML );
    2018               0 :             CPLHTTPDestroyResult(psResult);
    2019               0 :             return OGRERR_FAILURE;
    2020                 :         }
    2021                 :     }
    2022                 : 
    2023               0 :     CPLDestroyXMLNode( psXML );
    2024               0 :     CPLHTTPDestroyResult(psResult);
    2025                 : 
    2026                 :     /* Invalidate layer */
    2027               0 :     bReloadNeeded = TRUE;
    2028               0 :     nFeatures = -1;
    2029                 : 
    2030               0 :     return OGRERR_NONE;
    2031                 : }
    2032                 : 
    2033                 : /************************************************************************/
    2034                 : /*                            DeleteFeature()                           */
    2035                 : /************************************************************************/
    2036                 : 
    2037               0 : OGRErr OGRWFSLayer::DeleteFeature( long nFID )
    2038                 : {
    2039               0 :     if (!TestCapability(OLCDeleteFeature))
    2040                 :     {
    2041               0 :         if (!poDS->SupportTransactions())
    2042                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2043               0 :                      "DeleteFeature() not supported: no WMS-T features advertized by server");
    2044               0 :         else if (!poDS->UpdateMode())
    2045                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2046               0 :                      "DeleteFeature() not supported: datasource opened as read-only");
    2047               0 :         return OGRERR_FAILURE;
    2048                 :     }
    2049                 : 
    2050               0 :     if (poFeatureDefn->GetFieldIndex("gml_id") != 0)
    2051                 :     {
    2052                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2053               0 :                  "Cannot find gml_id field");
    2054               0 :         return OGRERR_FAILURE;
    2055                 :     }
    2056                 : 
    2057               0 :     OGRFeature* poFeature = GetFeature(nFID);
    2058               0 :     if (poFeature == NULL)
    2059                 :     {
    2060                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2061               0 :                  "Cannot find feature %ld", nFID);
    2062               0 :         return OGRERR_FAILURE;
    2063                 :     }
    2064                 : 
    2065               0 :     const char* pszGMLID = poFeature->GetFieldAsString("gml_id");
    2066               0 :     if (pszGMLID == NULL)
    2067                 :     {
    2068                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2069               0 :                  "Cannot delete a feature with gml_id unset");
    2070               0 :         delete poFeature;
    2071               0 :         return OGRERR_FAILURE;
    2072                 :     }
    2073                 : 
    2074               0 :     if (bInTransaction)
    2075                 :     {
    2076                 :         CPLError(CE_Warning, CPLE_AppDefined,
    2077               0 :                  "DeleteFeature() not yet dealt in transaction. Issued immediately");
    2078                 :     }
    2079                 : 
    2080               0 :     CPLString osGMLID = pszGMLID;
    2081               0 :     pszGMLID = NULL;
    2082               0 :     delete poFeature;
    2083               0 :     poFeature = NULL;
    2084                 : 
    2085               0 :     CPLString osFilter;
    2086               0 :     osFilter = "<ogc:FeatureId fid=\""; osFilter += osGMLID; osFilter += "\"/>\n";
    2087               0 :     return DeleteFromFilter(osFilter);
    2088                 : }
    2089                 : 
    2090                 : 
    2091                 : /************************************************************************/
    2092                 : /*                         StartTransaction()                           */
    2093                 : /************************************************************************/
    2094                 : 
    2095               0 : OGRErr OGRWFSLayer::StartTransaction()
    2096                 : {
    2097               0 :     if (!TestCapability(OLCTransactions))
    2098                 :     {
    2099               0 :         if (!poDS->SupportTransactions())
    2100                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2101               0 :                      "StartTransaction() not supported: no WMS-T features advertized by server");
    2102               0 :         else if (!poDS->UpdateMode())
    2103                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2104               0 :                      "StartTransaction() not supported: datasource opened as read-only");
    2105               0 :         return OGRERR_FAILURE;
    2106                 :     }
    2107                 : 
    2108               0 :     if (bInTransaction)
    2109                 :     {
    2110                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2111               0 :                      "StartTransaction() has already been called");
    2112               0 :         return OGRERR_FAILURE;
    2113                 :     }
    2114                 : 
    2115               0 :     bInTransaction = TRUE;
    2116               0 :     osGlobalInsert = "";
    2117               0 :     nExpectedInserts = 0;
    2118               0 :     aosFIDList.resize(0);
    2119                 : 
    2120               0 :     return OGRERR_NONE;
    2121                 : }
    2122                 : 
    2123                 : /************************************************************************/
    2124                 : /*                        CommitTransaction()                           */
    2125                 : /************************************************************************/
    2126                 : 
    2127               0 : OGRErr OGRWFSLayer::CommitTransaction()
    2128                 : {
    2129               0 :     if (!TestCapability(OLCTransactions))
    2130                 :     {
    2131               0 :         if (!poDS->SupportTransactions())
    2132                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2133               0 :                      "CommitTransaction() not supported: no WMS-T features advertized by server");
    2134               0 :         else if (!poDS->UpdateMode())
    2135                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2136               0 :                      "CommitTransaction() not supported: datasource opened as read-only");
    2137               0 :         return OGRERR_FAILURE;
    2138                 :     }
    2139                 : 
    2140               0 :     if (!bInTransaction)
    2141                 :     {
    2142                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2143               0 :                      "StartTransaction() has not yet been called");
    2144               0 :         return OGRERR_FAILURE;
    2145                 :     }
    2146                 : 
    2147               0 :     if (osGlobalInsert.size() != 0)
    2148                 :     {
    2149               0 :         CPLString osPost = GetPostHeader();
    2150               0 :         osPost += "  <wfs:Insert>\n";
    2151               0 :         osPost += osGlobalInsert;
    2152               0 :         osPost += "  </wfs:Insert>\n";
    2153               0 :         osPost += "</wfs:Transaction>\n";
    2154                 : 
    2155               0 :         bInTransaction = FALSE;
    2156               0 :         osGlobalInsert = "";
    2157               0 :         int nExpectedInserts = this->nExpectedInserts;
    2158               0 :         this->nExpectedInserts = 0;
    2159                 : 
    2160               0 :         CPLDebug("WFS", "Post : %s", osPost.c_str());
    2161                 : 
    2162               0 :         char** papszOptions = NULL;
    2163               0 :         papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", osPost.c_str());
    2164                 :         papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
    2165               0 :                                     "Content-Type: application/xml; charset=UTF-8");
    2166                 : 
    2167               0 :         CPLHTTPResult* psResult = poDS->HTTPFetch(poDS->GetPostTransactionURL(), papszOptions);
    2168               0 :         CSLDestroy(papszOptions);
    2169                 : 
    2170               0 :         if (psResult == NULL)
    2171                 :         {
    2172               0 :             return OGRERR_FAILURE;
    2173                 :         }
    2174                 : 
    2175               0 :         if (strstr((const char*)psResult->pabyData,
    2176                 :                                         "<ServiceExceptionReport") != NULL ||
    2177                 :             strstr((const char*)psResult->pabyData,
    2178                 :                                         "<ows:ExceptionReport") != NULL)
    2179                 :         {
    2180                 :             CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
    2181               0 :                     psResult->pabyData);
    2182               0 :             CPLHTTPDestroyResult(psResult);
    2183               0 :             return OGRERR_FAILURE;
    2184                 :         }
    2185                 : 
    2186               0 :         CPLDebug("WFS", "Response: %s", psResult->pabyData);
    2187                 : 
    2188               0 :         CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
    2189               0 :         if (psXML == NULL)
    2190                 :         {
    2191                 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
    2192               0 :                     psResult->pabyData);
    2193               0 :             CPLHTTPDestroyResult(psResult);
    2194               0 :             return OGRERR_FAILURE;
    2195                 :         }
    2196                 : 
    2197               0 :         CPLStripXMLNamespace( psXML, NULL, TRUE );
    2198               0 :         int bUse100Schema = FALSE;
    2199               0 :         CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=TransactionResponse" );
    2200               0 :         if (psRoot == NULL)
    2201                 :         {
    2202               0 :             psRoot = CPLGetXMLNode( psXML, "=WFS_TransactionResponse" );
    2203               0 :             if (psRoot)
    2204               0 :                 bUse100Schema = TRUE;
    2205                 :         }
    2206                 : 
    2207               0 :         if (psRoot == NULL)
    2208                 :         {
    2209                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2210               0 :                     "Cannot find <TransactionResponse>");
    2211               0 :             CPLDestroyXMLNode( psXML );
    2212               0 :             CPLHTTPDestroyResult(psResult);
    2213               0 :             return OGRERR_FAILURE;
    2214                 :         }
    2215                 : 
    2216               0 :         if (bUse100Schema)
    2217                 :         {
    2218               0 :             if (CPLGetXMLNode( psRoot, "TransactionResult.Status.FAILED" ))
    2219                 :             {
    2220                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2221                 :                         "Insert failed : %s",
    2222               0 :                         psResult->pabyData);
    2223               0 :                 CPLDestroyXMLNode( psXML );
    2224               0 :                 CPLHTTPDestroyResult(psResult);
    2225               0 :                 return OGRERR_FAILURE;
    2226                 :             }
    2227                 : 
    2228                 :             /* TODO */
    2229                 :         }
    2230                 :         else
    2231                 :         {
    2232               0 :             int nGotInserted = atoi(CPLGetXMLValue(psRoot, "TransactionSummary.totalInserted", ""));
    2233               0 :             if (nGotInserted != nExpectedInserts)
    2234                 :             {
    2235                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2236                 :                         "Only %d features were inserted whereas %d where expected",
    2237               0 :                          nGotInserted, nExpectedInserts);
    2238               0 :                 CPLDestroyXMLNode( psXML );
    2239               0 :                 CPLHTTPDestroyResult(psResult);
    2240               0 :                 return OGRERR_FAILURE;
    2241                 :             }
    2242                 : 
    2243                 :             CPLXMLNode* psInsertResults =
    2244               0 :                 CPLGetXMLNode( psRoot, "InsertResults");
    2245               0 :             if (psInsertResults == NULL)
    2246                 :             {
    2247                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2248               0 :                         "Cannot find node InsertResults");
    2249               0 :                 CPLDestroyXMLNode( psXML );
    2250               0 :                 CPLHTTPDestroyResult(psResult);
    2251               0 :                 return OGRERR_FAILURE;
    2252                 :             }
    2253                 : 
    2254               0 :             aosFIDList.resize(0);
    2255                 : 
    2256               0 :             CPLXMLNode* psChild = psInsertResults->psChild;
    2257               0 :             while(psChild)
    2258                 :             {
    2259               0 :                 const char* pszFID = CPLGetXMLValue(psChild, "FeatureId.fid", NULL);
    2260               0 :                 if (pszFID == NULL)
    2261                 :                 {
    2262               0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Cannot find fid");
    2263               0 :                     CPLDestroyXMLNode( psXML );
    2264               0 :                     CPLHTTPDestroyResult(psResult);
    2265               0 :                     return OGRERR_FAILURE;
    2266                 :                 }
    2267               0 :                 aosFIDList.push_back(pszFID);
    2268                 : 
    2269               0 :                 psChild = psChild->psNext;
    2270                 :             }
    2271                 : 
    2272               0 :             if ((int)aosFIDList.size() != nGotInserted)
    2273                 :             {
    2274                 :                 CPLError(CE_Failure, CPLE_AppDefined,
    2275               0 :                         "Inconsistant InsertResults: did not get expected FID count");
    2276               0 :                 CPLDestroyXMLNode( psXML );
    2277               0 :                 CPLHTTPDestroyResult(psResult);
    2278               0 :                 return OGRERR_FAILURE;
    2279                 :             }
    2280                 :         }
    2281                 : 
    2282               0 :         CPLDestroyXMLNode( psXML );
    2283               0 :         CPLHTTPDestroyResult(psResult);
    2284                 :     }
    2285                 : 
    2286               0 :     bInTransaction = FALSE;
    2287               0 :     osGlobalInsert = "";
    2288               0 :     nExpectedInserts = 0;
    2289                 : 
    2290               0 :     return OGRERR_NONE;
    2291                 : }
    2292                 : 
    2293                 : /************************************************************************/
    2294                 : /*                      RollbackTransaction()                           */
    2295                 : /************************************************************************/
    2296                 : 
    2297               0 : OGRErr OGRWFSLayer::RollbackTransaction()
    2298                 : {
    2299               0 :     if (!TestCapability(OLCTransactions))
    2300                 :     {
    2301               0 :         if (!poDS->SupportTransactions())
    2302                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2303               0 :                      "RollbackTransaction() not supported: no WMS-T features advertized by server");
    2304               0 :         else if (!poDS->UpdateMode())
    2305                 :             CPLError(CE_Failure, CPLE_AppDefined,
    2306               0 :                      "RollbackTransaction() not supported: datasource opened as read-only");
    2307               0 :         return OGRERR_FAILURE;
    2308                 :     }
    2309                 : 
    2310               0 :     if (!bInTransaction)
    2311                 :     {
    2312                 :         CPLError(CE_Failure, CPLE_AppDefined,
    2313               0 :                      "StartTransaction() has not yet been called");
    2314               0 :         return OGRERR_FAILURE;
    2315                 :     }
    2316                 : 
    2317               0 :     bInTransaction = FALSE;
    2318               0 :     osGlobalInsert = "";
    2319               0 :     nExpectedInserts = 0;
    2320                 : 
    2321               0 :     return OGRERR_NONE;
    2322                 : }
    2323                 : 
    2324                 : /************************************************************************/
    2325                 : /*                    SetRequiredOutputFormat()                         */
    2326                 : /************************************************************************/
    2327                 : 
    2328             308 : void  OGRWFSLayer::SetRequiredOutputFormat(const char* pszRequiredOutputFormatIn)
    2329                 : {
    2330             308 :     CPLFree(pszRequiredOutputFormat);
    2331             308 :     CPLFree(pszRequiredOutputFormatURL);
    2332             308 :     if (pszRequiredOutputFormatIn)
    2333                 :     {
    2334             308 :         pszRequiredOutputFormat = CPLStrdup(pszRequiredOutputFormatIn);
    2335             308 :         pszRequiredOutputFormatURL = CPLEscapeString(pszRequiredOutputFormatIn, -1, CPLES_URL);
    2336                 :     }
    2337                 :     else
    2338                 :     {
    2339               0 :         pszRequiredOutputFormat = NULL;
    2340               0 :         pszRequiredOutputFormatURL = NULL;
    2341                 :     }
    2342             308 : }
    2343                 : 
    2344                 : /************************************************************************/
    2345                 : /*                            SetOrderBy()                              */
    2346                 : /************************************************************************/
    2347                 : 
    2348               2 : void OGRWFSLayer::SetOrderBy(const char* pszFieldToSort, int bAscFlag)
    2349                 : {
    2350               2 :     osFieldToSort = pszFieldToSort ? pszFieldToSort : "";
    2351               2 :     this->bAscFlag = bAscFlag;
    2352               2 : }

Generated by: LCOV version 1.7