LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/wfs - ogrwfslayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1152 776 67.4 %
Date: 2011-12-18 Functions: 35 31 88.6 %

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

Generated by: LCOV version 1.7