46     struct createFeatureParams
    63     QString createFeatureGeoJSON( 
const QgsFeature &feature, 
const createFeatureParams ¶ms, 
const QgsAttributeList &pkAttributes );
    67     QDomElement createFeatureGML2( 
const QgsFeature &feature, QDomDocument &doc, 
const createFeatureParams ¶ms, 
const QgsProject *project, 
const QgsAttributeList &pkAttributes );
    69     QDomElement createFeatureGML3( 
const QgsFeature &feature, QDomDocument &doc, 
const createFeatureParams ¶ms, 
const QgsProject *project, 
const QgsAttributeList &pkAttributes );
    84     QgsWfsParameters mWfsParameters;
    97     mWfsParameters.dump();
   103     if ( doc.setContent( mRequestParameters.value( QStringLiteral( 
"REQUEST_BODY" ) ), 
true, &errorMsg ) )
   105       QDomElement docElem = doc.documentElement();
   114     QStringList typeNameList;
   117     bool onlyOneLayer = ( aRequest.
queries.size() == 1 );
   120     int requestPrecision = 6;
   124     QList<getFeatureQuery>::iterator qIt = aRequest.
queries.begin();
   125     for ( ; qIt != aRequest.
queries.end(); ++qIt )
   127       typeNameList << ( *qIt ).typeName;
   133     QMap<QString, QgsMapLayer *> mapLayerMap;
   134     for ( 
int i = 0; i < wfsLayerIds.size(); ++i )
   148       if ( typeNameList.contains( name ) )
   151         mapLayerMap[name] = layer;
   155           requestRect = layer->
extent();
   156           requestCrs = layer->
crs();
   165               requestRect = transform.transform( layer->
extent() );
   175             requestRect = 
QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
   181 #ifdef HAVE_SERVER_PYTHON_PLUGINS   191     long sentFeatures = 0;
   192     long iteratedFeatures = 0;
   195     qIt = aRequest.
queries.begin();
   196     for ( ; qIt != aRequest.
queries.end(); ++qIt )
   201       if ( !mapLayerMap.keys().contains( typeName ) )
   207 #ifdef HAVE_SERVER_PYTHON_PLUGINS   225 #ifdef HAVE_SERVER_PYTHON_PLUGINS   232       QMap< int, QString > layerAliasInfo;
   234       QgsStringMap::const_iterator aliasIt = aliasMap.constBegin();
   235       for ( ; aliasIt != aliasMap.constEnd(); ++aliasIt )
   238         if ( attrIndex != -1 )
   240           layerAliasInfo.insert( attrIndex, aliasIt.value() );
   251       if ( !propertyList.isEmpty() && propertyList.first() != QStringLiteral( 
"*" ) )
   254         QStringList::const_iterator plstIt;
   257         QList<QString> propertynames;
   258         QList<QString> fieldnames;
   259         for ( 
int idx = 0; idx < fields.
count(); ++idx )
   261           fieldnames.append( fields[idx].name() );
   265         for ( plstIt = propertyList.constBegin(); plstIt != propertyList.constEnd(); ++plstIt )
   268           int fieldNameIdx = propertynames.indexOf( fieldName );
   269           if ( fieldNameIdx == -1 )
   271             fieldNameIdx = fieldnames.indexOf( fieldName );
   273           if ( fieldNameIdx > -1 )
   275             idxList.append( fieldNameIdx );
   277           else if ( fieldName == QStringLiteral( 
"geometry" ) )
   282         if ( !idxList.isEmpty() )
   284           attrIndexes = idxList;
   290       if ( !attrIndexes.isEmpty() && !layerExcludedAttributes.isEmpty() )
   292         foreach ( 
const QString &excludedAttribute, layerExcludedAttributes )
   294           int fieldNameIdx = fields.
indexOf( excludedAttribute );
   295           if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
   297             attrIndexes.removeOne( fieldNameIdx );
   325 #ifdef HAVE_SERVER_PYTHON_PLUGINS   330         QStringList attributes = QStringList();
   331         for ( 
int idx : attrIndexes )
   358         geometryName = QLatin1String( 
"NONE" );
   362       if ( !query.
srsName.isEmpty() )
   387       if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
   391           if ( iteratedFeatures >= aRequest.
startIndex )
   400         const createFeatureParams cfp = { layerPrecision,
   410           if ( iteratedFeatures == aRequest.
startIndex )
   411             startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
   413           if ( iteratedFeatures >= aRequest.
startIndex )
   423 #ifdef HAVE_SERVER_PYTHON_PLUGINS   425     filterRestorer.reset();
   428     if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
   430       hitGetFeature( request, response, project, aRequest.
outputFormat, sentFeatures, typeNameList );
   435       if ( iteratedFeatures <= aRequest.
startIndex )
   436         startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
   445     request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
   446     request.
startIndex = mWfsParameters.startIndexAsInt();
   450     QStringList fidList = mWfsParameters.featureIds();
   451     bool paramContainsFeatureIds = !fidList.isEmpty();
   452     QStringList filterList = mWfsParameters.filters();
   453     bool paramContainsFilters = !filterList.isEmpty();
   454     QString bbox = mWfsParameters.bbox();
   455     bool paramContainsBbox = !bbox.isEmpty();
   456     if ( ( paramContainsFeatureIds
   457            && ( paramContainsFilters || paramContainsBbox ) )
   458          || ( paramContainsFilters
   459               && ( paramContainsFeatureIds || paramContainsBbox ) )
   460          || ( paramContainsBbox
   461               && ( paramContainsFeatureIds || paramContainsFilters ) )
   468     QStringList propertyNameList = mWfsParameters.propertyNames();
   471     request.
geometryName = mWfsParameters.geometryNameAsString().toUpper();
   473     QStringList typeNameList;
   475     if ( paramContainsFeatureIds )
   478       if ( !propertyNameList.isEmpty() && propertyNameList.size() != fidList.size() )
   482       if ( propertyNameList.isEmpty() )
   484         for ( 
int i = 0; i < fidList.size(); ++i )
   486           propertyNameList << QStringLiteral( 
"*" );
   490       QMap<QString, QStringList> fidsMap;
   492       QStringList::const_iterator fidIt = fidList.constBegin();
   493       QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
   494       for ( ; fidIt != fidList.constEnd(); ++fidIt )
   497         QString fid = *fidIt;
   500         QString propertyName;
   501         if ( propertyNameIt != propertyNameList.constEnd() )
   503           propertyName = *propertyNameIt;
   506         if ( !fid.contains( 
'.' ) )
   511         QString 
typeName = fid.section( 
'.', 0, 0 );
   512         fid = fid.section( 
'.', 1, 1 );
   513         if ( !typeNameList.contains( typeName ) )
   519         QString key = QStringLiteral( 
"%1(%2)" ).arg( typeName ).arg( propertyName );
   521         if ( fidsMap.contains( key ) )
   523           fids = fidsMap.value( key );
   526         fidsMap.insert( key, fids );
   528         if ( propertyNameIt != propertyNameList.constEnd() )
   534       QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
   535       while ( fidsMapIt != fidsMap.constEnd() )
   537         QString key = fidsMapIt.key();
   540         QRegExp rx( 
"([^()]+)\\(([^()]+)\\)" );
   541         if ( rx.indexIn( key, 0 ) == -1 )
   546         QString propertyName = rx.cap( 2 );
   550         query.
srsName = mWfsParameters.srsName();
   553         if ( propertyName != QStringLiteral( 
"*" ) )
   555           QStringList propertyList;
   557           const QStringList attrList = propertyName.split( 
',' );
   558           QStringList::const_iterator alstIt;
   559           for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
   561             QString fieldName = *alstIt;
   562             fieldName = fieldName.trimmed();
   563             if ( fieldName.contains( 
':' ) )
   565               fieldName = fieldName.section( 
':', 1, 1 );
   567             if ( fieldName.contains( 
'/' ) )
   569               if ( fieldName.section( 
'/', 0, 0 ) != 
typeName )
   573               fieldName = fieldName.section( 
'/', 1, 1 );
   575             propertyList.append( fieldName );
   584         request.
queries.append( query );
   590     if ( !mRequestParameters.contains( QStringLiteral( 
"TYPENAME" ) ) )
   595     typeNameList = mWfsParameters.typeNames();
   597     if ( !propertyNameList.isEmpty() && typeNameList.size() != propertyNameList.size() )
   601     if ( propertyNameList.isEmpty() )
   603       for ( 
int i = 0; i < typeNameList.size(); ++i )
   605         propertyNameList << QStringLiteral( 
"*" );
   610     QStringList::const_iterator typeNameIt = typeNameList.constBegin();
   611     QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
   612     for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
   615       typeName = typeName.trimmed();
   617       QString propertyName;
   618       if ( propertyNameIt != propertyNameList.constEnd() )
   620         propertyName = *propertyNameIt;
   625       query.
srsName = mWfsParameters.srsName();
   628       if ( propertyName != QStringLiteral( 
"*" ) )
   630         QStringList propertyList;
   632         const QStringList attrList = propertyName.split( 
',' );
   633         QStringList::const_iterator alstIt;
   634         for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
   636           QString fieldName = *alstIt;
   637           fieldName = fieldName.trimmed();
   638           if ( fieldName.contains( 
':' ) )
   640             fieldName = fieldName.section( 
':', 1, 1 );
   642           if ( fieldName.contains( 
'/' ) )
   644             if ( fieldName.section( 
'/', 0, 0 ) != 
typeName )
   648             fieldName = fieldName.section( 
'/', 1, 1 );
   650           propertyList.append( fieldName );
   655       request.
queries.append( query );
   657       if ( propertyNameIt != propertyNameList.constEnd() )
   664     QStringList expFilterList = mWfsParameters.expFilters();
   665     if ( !expFilterList.isEmpty() )
   668       if ( request.
queries.size() == expFilterList.size() )
   671         QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
   672         QStringList::const_iterator expFilterIt = expFilterList.constBegin();
   673         for ( ; qIt != request.
queries.end(); ++qIt )
   678           if ( expFilterIt != expFilterList.constEnd() )
   680             expFilter = *expFilterIt;
   682           std::shared_ptr<QgsExpression> filter( 
new QgsExpression( expFilter ) );
   685             if ( filter->hasParserError() )
   689             if ( filter->needsGeometry() )
   703     if ( paramContainsBbox )
   710       if ( mWfsParameters.bbox().split( 
',' ).size() == 5 && ! mWfsParameters.srsName().isEmpty() )
   712         QString 
crs( mWfsParameters.bbox().split( 
',' )[4] );
   713         if ( 
crs != mWfsParameters.srsName() )
   717           if ( sourceCrs.
isValid() && destinationCrs.isValid( ) )
   725               if ( extentGeom.
transform( transform ) == 0 )
   739       QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
   740       for ( ; qIt != request.
queries.end(); ++qIt )
   747     else if ( paramContainsFilters )
   750       if ( request.
queries.size() != filterList.size() )
   756       QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
   757       QStringList::const_iterator filterIt = filterList.constBegin();
   758       for ( ; qIt != request.
queries.end(); ++qIt )
   763         if ( filterIt != filterList.constEnd() )
   766           if ( !filter.setContent( *filterIt, 
true, &errorMsg ) )
   772         QDomElement filterElem = filter.firstChildElement();
   773         QStringList serverFids;
   777         if ( filterIt != filterList.constEnd() )
   785     QStringList sortByList = mWfsParameters.sortBy();
   786     if ( !sortByList.isEmpty() && request.
queries.size() == sortByList.size() )
   789       QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
   790       QStringList::const_iterator sortByIt = sortByList.constBegin();
   791       for ( ; qIt != request.
queries.end(); ++qIt )
   796         if ( sortByIt != sortByList.constEnd() )
   800         for ( 
const QString &attribute : sortBy.split( 
',' ) )
   802           if ( attribute.endsWith( QLatin1String( 
" D" ) ) || attribute.endsWith( QLatin1String( 
"+D" ) ) )
   806           else if ( attribute.endsWith( QLatin1String( 
" DESC" ) ) || attribute.endsWith( QLatin1String( 
"+DESC" ) ) )
   810           else if ( attribute.endsWith( QLatin1String( 
" A" ) ) || attribute.endsWith( QLatin1String( 
"+A" ) ) )
   814           else if ( attribute.endsWith( QLatin1String( 
" ASC" ) ) || attribute.endsWith( QLatin1String( 
"+ASC" ) ) )
   832     request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
   833     request.
startIndex = mWfsParameters.startIndexAsInt();
   836     QDomNodeList queryNodes = docElem.elementsByTagName( QStringLiteral( 
"Query" ) );
   837     QDomElement queryElem;
   838     for ( 
int i = 0; i < queryNodes.size(); i++ )
   840       queryElem = queryNodes.at( i ).toElement();
   842       request.
queries.append( query );
   849     QDomNodeList sortByNodes = sortByElem.childNodes();
   850     if ( sortByNodes.size() )
   852       for ( 
int i = 0; i < sortByNodes.size(); i++ )
   854         QDomElement sortPropElem = sortByNodes.at( i ).toElement();
   855         QDomNodeList sortPropChildNodes = sortPropElem.childNodes();
   856         if ( sortPropChildNodes.size() )
   859           bool ascending = 
true;
   860           for ( 
int j = 0; j < sortPropChildNodes.size(); j++ )
   862             QDomElement sortPropChildElem = sortPropChildNodes.at( j ).toElement();
   863             if ( sortPropChildElem.tagName() == QLatin1String( 
"PropertyName" ) )
   865               fieldName = sortPropChildElem.text().trimmed();
   867             else if ( sortPropChildElem.tagName() == QLatin1String( 
"SortOrder" ) )
   869               QString sortOrder = sortPropChildElem.text().trimmed().toUpper();
   870               if ( sortOrder == QLatin1String( 
"DESC" ) || sortOrder == QLatin1String( 
"D" ) )
   875           if ( fieldName.contains( 
':' ) )
   877             fieldName = fieldName.section( 
':', 1, 1 );
   879           if ( fieldName.contains( 
'/' ) )
   881             if ( fieldName.section( 
'/', 0, 0 ) != 
typeName )
   885             fieldName = fieldName.section( 
'/', 1, 1 );
   888           if ( !fieldName.isEmpty() )
   889             featureRequest.
addOrderBy( fieldName, ascending );
   897     QString 
typeName = queryElem.attribute( QStringLiteral( 
"typeName" ), QString() );
   898     if ( typeName.contains( 
':' ) )
   900       typeName = typeName.section( 
':', 1, 1 );
   904     QStringList serverFids;
   905     QStringList propertyList;
   906     QDomNodeList queryChildNodes = queryElem.childNodes();
   907     if ( queryChildNodes.size() )
   909       QDomElement sortByElem;
   910       for ( 
int q = 0; q < queryChildNodes.size(); q++ )
   912         QDomElement queryChildElem = queryChildNodes.at( q ).toElement();
   913         if ( queryChildElem.tagName() == QLatin1String( 
"PropertyName" ) )
   915           QString fieldName = queryChildElem.text().trimmed();
   916           if ( fieldName.contains( 
':' ) )
   918             fieldName = fieldName.section( 
':', 1, 1 );
   920           if ( fieldName.contains( 
'/' ) )
   922             if ( fieldName.section( 
'/', 0, 0 ) != 
typeName )
   926             fieldName = fieldName.section( 
'/', 1, 1 );
   928           propertyList.append( fieldName );
   930         else if ( queryChildElem.tagName() == QLatin1String( 
"Filter" ) )
   934         else if ( queryChildElem.tagName() == QLatin1String( 
"SortBy" ) )
   936           sortByElem = queryChildElem;
   943     QString srsName = queryElem.attribute( QStringLiteral( 
"srsName" ), QString() );
   956     static QSet< QString > sParamFilter
   958       QStringLiteral( 
"REQUEST" ),
   959       QStringLiteral( 
"FORMAT" ),
   960       QStringLiteral( 
"OUTPUTFORMAT" ),
   961       QStringLiteral( 
"BBOX" ),
   962       QStringLiteral( 
"FEATUREID" ),
   963       QStringLiteral( 
"TYPENAME" ),
   964       QStringLiteral( 
"FILTER" ),
   965       QStringLiteral( 
"EXP_FILTER" ),
   966       QStringLiteral( 
"MAXFEATURES" ),
   967       QStringLiteral( 
"STARTINDEX" ),
   968       QStringLiteral( 
"PROPERTYNAME" ),
   969       QStringLiteral( 
"_DC" )
   974                         int numberOfFeatures, 
const QStringList &typeNames )
   976       QDateTime now = QDateTime::currentDateTime();
   979       if ( format == QgsWfsParameters::Format::GeoJSON )
   981         response.
setHeader( 
"Content-Type", 
"application/vnd.geo+json; charset=utf-8" );
   982         fcString = QStringLiteral( 
"{\"type\": \"FeatureCollection\",\n" );
   983         fcString += QStringLiteral( 
" \"timeStamp\": \"%1\"\n" ).arg( now.toString( Qt::ISODate ) );
   984         fcString += QStringLiteral( 
" \"numberOfFeatures\": %1\n" ).arg( QString::number( numberOfFeatures ) );
   985         fcString += QLatin1String( 
"}" );
   989         if ( format == QgsWfsParameters::Format::GML2 )
   990           response.
setHeader( 
"Content-Type", 
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
   992           response.
setHeader( 
"Content-Type", 
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
   995         QString hrefString = 
serviceUrl( request, project );
   997         QUrl mapUrl( hrefString );
   999         QUrlQuery query( mapUrl );
  1000         query.addQueryItem( QStringLiteral( 
"SERVICE" ), QStringLiteral( 
"WFS" ) );
  1002         if ( mWfsParameters.version().isEmpty() )
  1005           query.addQueryItem( QStringLiteral( 
"VERSION" ), QStringLiteral( 
"1.1.0" ) );
  1007           query.addQueryItem( QStringLiteral( 
"VERSION" ), QStringLiteral( 
"1.0.0" ) );
  1009         for ( 
auto param : query.queryItems() )
  1011           if ( sParamFilter.contains( param.first.toUpper() ) )
  1012             query.removeAllQueryItems( param.first );
  1015         query.addQueryItem( QStringLiteral( 
"REQUEST" ), QStringLiteral( 
"DescribeFeatureType" ) );
  1016         query.addQueryItem( QStringLiteral( 
"TYPENAME" ), typeNames.join( 
',' ) );
  1019           if ( format == QgsWfsParameters::Format::GML2 )
  1020             query.addQueryItem( QStringLiteral( 
"OUTPUTFORMAT" ), QStringLiteral( 
"text/xml; subtype=gml/2.1.2" ) );
  1022             query.addQueryItem( QStringLiteral( 
"OUTPUTFORMAT" ), QStringLiteral( 
"text/xml; subtype=gml/3.1.1" ) );
  1025           query.addQueryItem( QStringLiteral( 
"OUTPUTFORMAT" ), QStringLiteral( 
"XMLSCHEMA" ) );
  1027         mapUrl.setQuery( query );
  1029         hrefString = mapUrl.toString();
  1032         fcString = QStringLiteral( 
"<wfs:FeatureCollection" );
  1036         fcString += QLatin1String( 
" xmlns:ows=\"http://www.opengis.net/ows\"" );
  1037         fcString += QLatin1String( 
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
  1039         fcString += QLatin1String( 
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
  1040         fcString += 
" xsi:schemaLocation=\"" + 
WFS_NAMESPACE + 
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " + 
QGS_NAMESPACE + 
" " + hrefString.replace( QLatin1String( 
"&" ), QLatin1String( 
"&" ) ) + 
"\"";
  1041         fcString += 
"\n timeStamp=\"" + now.toString( Qt::ISODate ) + 
"\"";
  1042         fcString += 
"\n numberOfFeatures=\"" + QString::number( numberOfFeatures ) + 
"\"";
  1043         fcString += QLatin1String( 
">\n" );
  1044         fcString += QStringLiteral( 
"</wfs:FeatureCollection>" );
  1047       response.
write( fcString.toUtf8() );
  1056       std::unique_ptr< QgsRectangle > transformedRect;
  1058       if ( format == QgsWfsParameters::Format::GeoJSON )
  1060         response.
setHeader( 
"Content-Type", 
"application/vnd.geo+json; charset=utf-8" );
  1070             if ( exportGeom.
transform( transform ) == 0 )
  1073               rect = transformedRect.get();
  1084         fcString = QStringLiteral( 
"{\"type\": \"FeatureCollection\",\n" );
  1086         fcString += QLatin1String( 
" \"features\": [\n" );
  1087         response.
write( fcString.toUtf8() );
  1091         if ( format == QgsWfsParameters::Format::GML2 )
  1092           response.
setHeader( 
"Content-Type", 
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
  1094           response.
setHeader( 
"Content-Type", 
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
  1097         QString hrefString = 
serviceUrl( request, project );
  1099         QUrl mapUrl( hrefString );
  1101         QUrlQuery query( mapUrl );
  1102         query.addQueryItem( QStringLiteral( 
"SERVICE" ), QStringLiteral( 
"WFS" ) );
  1104         if ( mWfsParameters.version().isEmpty() )
  1107           query.addQueryItem( QStringLiteral( 
"VERSION" ), QStringLiteral( 
"1.1.0" ) );
  1109           query.addQueryItem( QStringLiteral( 
"VERSION" ), QStringLiteral( 
"1.0.0" ) );
  1111         for ( 
auto param : query.queryItems() )
  1113           if ( sParamFilter.contains( param.first.toUpper() ) )
  1114             query.removeAllQueryItems( param.first );
  1117         query.addQueryItem( QStringLiteral( 
"REQUEST" ), QStringLiteral( 
"DescribeFeatureType" ) );
  1118         query.addQueryItem( QStringLiteral( 
"TYPENAME" ), typeNames.join( 
',' ) );
  1121           if ( format == QgsWfsParameters::Format::GML2 )
  1122             query.addQueryItem( QStringLiteral( 
"OUTPUTFORMAT" ), QStringLiteral( 
"text/xml; subtype=gml/2.1.2" ) );
  1124             query.addQueryItem( QStringLiteral( 
"OUTPUTFORMAT" ), QStringLiteral( 
"text/xml; subtype=gml/3.1.1" ) );
  1127           query.addQueryItem( QStringLiteral( 
"OUTPUTFORMAT" ), QStringLiteral( 
"XMLSCHEMA" ) );
  1129         mapUrl.setQuery( query );
  1131         hrefString = mapUrl.toString();
  1134         fcString = QStringLiteral( 
"<wfs:FeatureCollection" );
  1138         fcString += QLatin1String( 
" xmlns:ows=\"http://www.opengis.net/ows\"" );
  1139         fcString += QLatin1String( 
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
  1141         fcString += QLatin1String( 
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
  1142         fcString += 
" xsi:schemaLocation=\"" + 
WFS_NAMESPACE + 
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " + 
QGS_NAMESPACE + 
" " + hrefString.replace( QLatin1String( 
"&" ), QLatin1String( 
"&" ) ) + 
"\"";
  1143         fcString += QLatin1String( 
">\n" );
  1145         response.
write( fcString.toUtf8() );
  1149         QDomElement bbElem = doc.createElement( QStringLiteral( 
"gml:boundedBy" ) );
  1150         if ( format == QgsWfsParameters::Format::GML3 )
  1153           if ( !envElem.isNull() )
  1157               envElem.setAttribute( QStringLiteral( 
"srsName" ), crs.
authid() );
  1159             bbElem.appendChild( envElem );
  1160             doc.appendChild( bbElem );
  1166           if ( !boxElem.isNull() )
  1170               boxElem.setAttribute( QStringLiteral( 
"srsName" ), crs.
authid() );
  1172             bbElem.appendChild( boxElem );
  1173             doc.appendChild( bbElem );
  1176         response.
write( doc.toByteArray() );
  1187       if ( format == QgsWfsParameters::Format::GeoJSON )
  1191           fcString += QLatin1String( 
"  " );
  1193           fcString += QLatin1String( 
" ," );
  1194         mJsonExporter.setSourceCrs( params.crs );
  1195         mJsonExporter.setIncludeGeometry( 
false );
  1196         mJsonExporter.setIncludeAttributes( !params.attributeIndexes.isEmpty() );
  1197         mJsonExporter.setAttributes( params.attributeIndexes );
  1198         fcString += createFeatureGeoJSON( feature, params, pkAttributes );
  1199         fcString += QLatin1String( 
"\n" );
  1201         response.
write( fcString.toUtf8() );
  1205         QDomDocument gmlDoc;
  1206         QDomElement featureElement;
  1207         if ( format == QgsWfsParameters::Format::GML3 )
  1209           featureElement = createFeatureGML3( feature, gmlDoc, params, project, pkAttributes );
  1210           gmlDoc.appendChild( featureElement );
  1214           featureElement = createFeatureGML2( feature, gmlDoc, params, project, pkAttributes );
  1215           gmlDoc.appendChild( featureElement );
  1217         response.
write( gmlDoc.toByteArray() );
  1227       if ( format == QgsWfsParameters::Format::GeoJSON )
  1229         fcString += QLatin1String( 
" ]\n" );
  1230         fcString += QLatin1String( 
"}" );
  1234         fcString = QStringLiteral( 
"</wfs:FeatureCollection>\n" );
  1236       response.
write( fcString.toUtf8() );
  1240     QString createFeatureGeoJSON( 
const QgsFeature &feature, 
const createFeatureParams ¶ms, 
const QgsAttributeList &pkAttributes )
  1250       if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String( 
"NONE" ) )
  1252         mJsonExporter.setIncludeGeometry( 
true );
  1253         if ( params.geometryName == QLatin1String( 
"EXTENT" ) )
  1258         else if ( params.geometryName == QLatin1String( 
"CENTROID" ) )
  1264       return mJsonExporter.exportFeature( f, QVariantMap(), 
id );
  1268     QDomElement createFeatureGML2( 
const QgsFeature &feature, QDomDocument &doc, 
const createFeatureParams ¶ms, 
const QgsProject *project, 
const QgsAttributeList &pkAttributes )
  1271       QDomElement featureElement = doc.createElement( QStringLiteral( 
"gml:featureMember" ) );
  1274       QDomElement typeNameElement = doc.createElement( 
"qgs:" + params.typeName  );
  1276       typeNameElement.setAttribute( QStringLiteral( 
"fid" ), 
id );
  1277       featureElement.appendChild( typeNameElement );
  1281       if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String( 
"NONE" ) )
  1283         int prec = params.precision;
  1289           if ( transformed.
transform( mTransform ) == 0 )
  1292             crs = params.outputCrs;
  1293             if ( crs.
isGeographic() && !params.crs.isGeographic() )
  1294               prec = std::min( params.precision + 3, 6 );
  1302         QDomElement geomElem = doc.createElement( QStringLiteral( 
"qgs:geometry" ) );
  1303         QDomElement gmlElem;
  1304         if ( params.geometryName == QLatin1String( 
"EXTENT" ) )
  1309         else if ( params.geometryName == QLatin1String( 
"CENTROID" ) )
  1319             gmlElem = abstractGeom->
asGml2( doc, prec, 
"http://www.opengis.net/gml" );
  1323         if ( !gmlElem.isNull() )
  1326           QDomElement bbElem = doc.createElement( QStringLiteral( 
"gml:boundedBy" ) );
  1331             boxElem.setAttribute( QStringLiteral( 
"srsName" ), crs.
authid() );
  1332             gmlElem.setAttribute( QStringLiteral( 
"srsName" ), crs.
authid() );
  1335           bbElem.appendChild( boxElem );
  1336           typeNameElement.appendChild( bbElem );
  1338           geomElem.appendChild( gmlElem );
  1339           typeNameElement.appendChild( geomElem );
  1346       for ( 
int i = 0; i < params.attributeIndexes.count(); ++i )
  1348         int idx = params.attributeIndexes[i];
  1349         if ( idx >= fields.
count() )
  1355         QString attributeName = field.
name();
  1357         QDomElement fieldElem = doc.createElement( 
"qgs:" + attributeName.replace( 
' ', 
'_' ).replace( 
cleanTagNameRegExp, QString() ) );
  1358         QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
  1359         if ( featureAttributes[idx].isNull() )
  1361           fieldElem.setAttribute( QStringLiteral( 
"xsi:nil" ), QStringLiteral( 
"true" ) );
  1363         fieldElem.appendChild( fieldText );
  1364         typeNameElement.appendChild( fieldElem );
  1367       return featureElement;
  1370     QDomElement createFeatureGML3( 
const QgsFeature &feature, QDomDocument &doc, 
const createFeatureParams ¶ms, 
const QgsProject *project, 
const QgsAttributeList &pkAttributes )
  1373       QDomElement featureElement = doc.createElement( QStringLiteral( 
"gml:featureMember" ) );
  1376       QDomElement typeNameElement = doc.createElement( 
"qgs:" + params.typeName  );
  1378       typeNameElement.setAttribute( QStringLiteral( 
"gml:id" ), 
id );
  1379       featureElement.appendChild( typeNameElement );
  1383       if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String( 
"NONE" ) )
  1385         int prec = params.precision;
  1391           if ( transformed.
transform( mTransform ) == 0 )
  1394             crs = params.outputCrs;
  1395             if ( crs.
isGeographic() && !params.crs.isGeographic() )
  1396               prec = std::min( params.precision + 3, 6 );
  1404         QDomElement geomElem = doc.createElement( QStringLiteral( 
"qgs:geometry" ) );
  1405         QDomElement gmlElem;
  1406         if ( params.geometryName == QLatin1String( 
"EXTENT" ) )
  1411         else if ( params.geometryName == QLatin1String( 
"CENTROID" ) )
  1421             gmlElem = abstractGeom->
asGml3( doc, prec, 
"http://www.opengis.net/gml" );
  1425         if ( !gmlElem.isNull() )
  1428           QDomElement bbElem = doc.createElement( QStringLiteral( 
"gml:boundedBy" ) );
  1433             boxElem.setAttribute( QStringLiteral( 
"srsName" ), crs.
authid() );
  1434             gmlElem.setAttribute( QStringLiteral( 
"srsName" ), crs.
authid() );
  1437           bbElem.appendChild( boxElem );
  1438           typeNameElement.appendChild( bbElem );
  1440           geomElem.appendChild( gmlElem );
  1441           typeNameElement.appendChild( geomElem );
  1448       for ( 
int i = 0; i < params.attributeIndexes.count(); ++i )
  1450         int idx = params.attributeIndexes[i];
  1451         if ( idx >= fields.
count() )
  1459         QString attributeName = field.
name();
  1461         QDomElement fieldElem = doc.createElement( 
"qgs:" + attributeName.replace( 
' ', 
'_' ).replace( 
cleanTagNameRegExp, QString() ) );
  1462         QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
  1463         if ( featureAttributes[idx].isNull() )
  1465           fieldElem.setAttribute( QStringLiteral( 
"xsi:nil" ), QStringLiteral( 
"true" ) );
  1467         fieldElem.appendChild( fieldText );
  1468         typeNameElement.appendChild( fieldElem );
  1471       return featureElement;
  1476       if ( value.isNull() )
  1479       if ( setup.
type() ==  QStringLiteral( 
"DateTime" ) )
  1482         const QVariantMap config = setup.
config();
  1483         const QString fieldFormat = config.value( QStringLiteral( 
"field_format" ), fieldFormatter.
defaultFormat( value.type() ) ).toString();
  1484         QDateTime date = value.toDateTime();
  1486         if ( date.isValid() )
  1488           return date.toString( fieldFormat );
  1491       else if ( setup.
type() ==  QStringLiteral( 
"Range" ) )
  1493         const QVariantMap config = setup.
config();
  1494         if ( config.contains( QStringLiteral( 
"Precision" ) ) )
  1498           int precision( config[ QStringLiteral( 
"Precision" ) ].toInt( &ok ) );
  1500             return QString::number( value.toDouble(), 
'f', 
precision );
  1504       switch ( value.type() )
  1507         case QVariant::UInt:
  1508         case QVariant::LongLong:
  1509         case QVariant::ULongLong:
  1510         case QVariant::Double:
  1511           return value.toString();
  1513         case QVariant::Bool:
  1514           return value.toBool() ? QStringLiteral( 
"true" ) : QStringLiteral( 
"false" );
  1516         case QVariant::StringList:
  1517         case QVariant::List:
  1523           if ( v.indexOf( 
'<' ) != -1 || v.indexOf( 
'&' ) != -1 )
  1524             v.prepend( QStringLiteral( 
"<![CDATA[" ) ).append( QStringLiteral( 
"]]>" ) );
  1530         case QVariant::String:
  1532           QString v = value.toString();
  1535           if ( v.indexOf( 
'<' ) != -1 || v.indexOf( 
'&' ) != -1 )
  1536             v.prepend( QStringLiteral( 
"<![CDATA[" ) ).append( QStringLiteral( 
"]]>" ) );
 int lookupField(const QString &fieldName) const
Looks up field's index from the field name. 
void writeGetFeature(QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response)
Output WFS GetFeature response. 
bool isValid() const
Returns the validity of this feature. 
Class for parsing and evaluation of expressions (formerly called "search strings"). 
QgsStringMap attributeAliases() const
Returns a map of field name to attribute alias. 
Wrapper for iterator of features from vector data provider or vector layer. 
virtual void setHeader(const QString &key, const QString &value)=0
Set Header entry Add Header entry to the response Note that it is usually an error to set Header afte...
A rectangle specified with double values. 
Base class for all map layer types. 
QgsFeatureRequest featureRequest
QgsMapLayerType type() const
Returns the type of the layer. 
const Flags & flags() const
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct. 
getFeatureRequest parseGetFeatureRequestBody(QDomElement &docElem, const QgsProject *project)
Transform RequestBody root element to getFeatureRequest. 
const QString QGS_NAMESPACE
QSet< QString > excludeAttributesWfs() const
A set of attributes that are not advertised in WFS requests with QGIS server. 
SERVER_EXPORT QString getServerFid(const QgsFeature &feature, const QgsAttributeList &pkAttributes)
Returns the feature id based on primary keys. 
QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error. 
virtual QgsAttributeList pkAttributeIndexes() const
Returns list of indexes of fields that make up the primary key. 
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched. 
Container of fields for a vector layer. 
A geometry is the spatial representation of a feature. 
QgsFeatureRequest & addOrderBy(const QString &expression, bool ascending=true)
Adds a new OrderByClause, appending it as the least important one. 
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field. 
QgsGeometry centroid() const
Returns the center of mass of a geometry. 
static QDomElement rectangleToGMLBox(QgsRectangle *box, QDomDocument &doc, int precision=17)
Exports the rectangle to GML2 Box. 
virtual QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const =0
Returns a GML2 representation of the geometry. 
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project. 
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
const QgsCoordinateReferenceSystem & crs
const QgsAttributeList & attributeIndexes
void parseSortByElement(QDomElement &sortByElem, QgsFeatureRequest &featureRequest, const QString &typeName)
Add SortBy element to featureRequest. 
virtual void write(const QString &data)
Write string This is a convenient method that will write directly to the underlying I/O device...
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken. 
int count() const
Returns number of items. 
QMap< QString, QString > QgsStringMap
QString layerTypeName(const QgsMapLayer *layer)
Returns typename from vector layer. 
virtual QgsRectangle extent() const
Returns the extent of the layer. 
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1) 
static void applyAccessControlLayerFilters(const QgsAccessControl *accessControl, QgsMapLayer *mapLayer, QHash< QgsMapLayer *, QString > &originalLayerFilters)
Apply filter from AccessControl. 
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions. 
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle. 
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression. 
QString serviceUrl(const QgsServerRequest &request, const QgsProject *project)
Service URL string. 
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject. 
QgsFields fields() const FINAL
Returns the list of fields of this layer. 
static QString encodeValue(const QVariant &value)
Encodes a value to a JSON string representation, adding appropriate quotations and escaping where req...
const QString & geometryName
bool isEmpty() const
Returns true if the rectangle is empty. 
getFeatureQuery parseQueryElement(QDomElement &queryElem, const QgsProject *project)
Transform Query element to getFeatureQuery. 
QgsServerRequest::Parameters parameters() const
Returns a map of query parameters with keys converted to uppercase. 
A class to describe the version of a project. 
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double. 
QgsWfsParameters::Format outputFormat
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary). 
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle. 
const QString GML_NAMESPACE
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< getFeatureQuery > queries
const QString WFS_NAMESPACE
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken. 
QgsFeatureRequest parseFilterElement(const QString &typeName, QDomElement &filterElem, const QgsProject *project)
Transform a Filter element to a feature request. 
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc. 
QString implementationVersion()
Returns the highest version supported by this implementation. 
QgsAttributeList attributeList() const
Returns list of attribute indexes. 
Format
Output format for the response. 
Encapsulate a field in an attribute table or data source. 
Abstract base class for all geometries. 
SERVER_EXPORT QgsFeatureRequest updateFeatureRequestFromServerFids(QgsFeatureRequest &featureRequest, const QStringList &serverFids, const QgsVectorDataProvider *provider)
Returns the feature request based on feature ids build with primary keys. 
SERVER_EXPORT int wfsLayerPrecision(const QgsProject &project, const QString &layerId)
Returns the Layer precision defined in a QGIS project for the WFS GetFeature. 
Handles exporting QgsFeature features to GeoJSON features. 
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive. 
double yMinimum() const
Returns the y minimum value (bottom side of rectangle). 
const QString OGC_NAMESPACE
double xMaximum() const
Returns the x maximum value (right side of rectangle). 
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle...
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
const QRegExp cleanTagNameRegExp("(?![\\\-]).")
bool layerReadPermission(const QgsMapLayer *layer) const
Returns the layer read right. 
QgsServerInterface Class defining interfaces exposed by QGIS Server and made available to plugins...
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string. 
int indexOf(const QString &fieldName) const
Gets the field index from the field name. 
QgsRectangle boundingBox() const
Returns the bounding box of the geometry. 
SERVER_EXPORT QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS. 
This class represents a coordinate reference system (CRS). 
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry. 
static QDomElement geometryToGML(const QgsGeometry &geometry, QDomDocument &doc, QgsOgcUtils::GMLVersion gmlVersion, const QString &srsName, bool invertAxisOrientation, const QString &gmlIdBase, int precision=17)
Exports the geometry to GML. 
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request. 
static QDomElement rectangleToGMLEnvelope(QgsRectangle *env, QDomDocument &doc, int precision=17)
Exports the rectangle to GML3 Envelope. 
const QgsCoordinateReferenceSystem & outputCrs
double xMinimum() const
Returns the x minimum value (left side of rectangle). 
RAII class to restore layer filters on destruction. 
A helper class that centralizes restrictions given by all the access control filter plugins...
void filterFeatures(const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures) const override
Filter the features of the layer. 
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID. 
Exception thrown when data access violates access controls. 
double yMaximum() const
Returns the y maximum value (top side of rectangle). 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request. 
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
Custom exception class for Coordinate Reference System related exceptions. 
virtual QgsAccessControl * accessControls() const =0
Gets the registered access control filters. 
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr. 
QList< int > QgsAttributeList
getFeatureRequest parseGetFeatureParameters(const QgsProject *project)
Transform parameters to getFeatureRequest. 
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer. 
bool nextFeature(QgsFeature &f)
This is the base class for vector data providers. 
Geometry is not required. It may still be returned if e.g. required for a filter condition. 
Represents a vector layer which manages a vector based data sets. 
QStringList layerAttributes(const QgsVectorLayer *layer, const QStringList &attributes) const
Returns the authorized layer attributes. 
Defines a QGIS exception class. 
QgsField field(int fieldIdx) const
Gets field at particular index (must be in range 0..N-1) 
Provides an interface to retrieve and manipulate WFS parameters received from the client...
QString authid() const
Returns the authority identifier for the CRS. 
QgsCoordinateReferenceSystem crs
virtual QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const =0
Returns a GML3 representation of the geometry. 
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched. 
QMap< QString, QString > Parameters
virtual void flush() SIP_THROW(QgsServerException)
Flushes the current output buffer to the network. 
bool isValid() const
Returns whether this CRS is correctly initialized and usable.