44#include <QRegularExpression>
51 struct createFeatureParams
55 const QgsCoordinateReferenceSystem &crs;
59 const QString &typeName;
63 const QString &geometryName;
65 const QgsCoordinateReferenceSystem &outputCrs;
67 bool forceGeomToMulti;
69 const QString &srsName;
74 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes );
76 QDomElement createFieldElement(
const QgsField &field,
const QVariant &value, QDomDocument &doc );
78 QString encodeValueToText(
const QVariant &value,
const QgsEditorWidgetSetup &setup );
80 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
82 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
84 void hitGetFeature(
const QgsServerRequest &request, QgsServerResponse &response,
const QgsProject *project,
QgsWfsParameters::Format format,
int numberOfFeatures,
const QStringList &typeNames,
const QgsServerSettings *serverSettings );
86 void startGetFeature(
const QgsServerRequest &request, QgsServerResponse &response,
const QgsProject *project,
QgsWfsParameters::Format format,
int prec, QgsCoordinateReferenceSystem &crs, QgsRectangle *rect,
const QStringList &typeNames,
const QgsServerSettings *settings );
95 QgsJsonExporter mJsonExporter;
116 mWfsParameters.dump();
122 if ( doc.setContent( request.
data(),
true, &errorMsg ) )
124 QDomElement docElem = doc.documentElement();
133 QStringList typeNameList;
136 bool onlyOneLayer = ( aRequest.
queries.size() == 1 );
139 int requestPrecision = 6;
143 QList<getFeatureQuery>::iterator qIt = aRequest.
queries.begin();
144 for ( ; qIt != aRequest.
queries.end(); ++qIt )
146 typeNameList << ( *qIt ).typeName;
152 QMap<QString, QgsMapLayer *> mapLayerMap;
153 for (
int i = 0; i < wfsLayerIds.size(); ++i )
167 if ( typeNameList.contains( name ) )
170 mapLayerMap[name] = layer;
174 requestRect = layer->
extent();
175 requestCrs = layer->
crs();
194 requestRect =
QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
201 for (
const QString &typeName : typeNameList )
203 if ( !mapLayerMap.contains( typeName ) )
209#ifdef HAVE_SERVER_PYTHON_PLUGINS
213 auto filterRestorer = std::make_unique<QgsOWSServerFilterRestorer>();
215 ( void ) serverIface;
219 long sentFeatures = 0;
220 long iteratedFeatures = 0;
223 qIt = aRequest.
queries.begin();
224 for ( ; qIt != aRequest.
queries.end(); ++qIt )
230#ifdef HAVE_SERVER_PYTHON_PLUGINS
248#ifdef HAVE_SERVER_PYTHON_PLUGINS
255 QMap<int, QString> layerAliasInfo;
257 QgsStringMap::const_iterator aliasIt = aliasMap.constBegin();
258 for ( ; aliasIt != aliasMap.constEnd(); ++aliasIt )
261 if ( attrIndex != -1 )
263 layerAliasInfo.insert( attrIndex, aliasIt.value() );
273 bool withGeom =
true;
274 if ( !propertyList.isEmpty() && propertyList.first() != QLatin1String(
"*" ) )
277 QStringList::const_iterator plstIt;
280 QList<QString> propertynames;
281 QList<QString> fieldnames;
282 for (
const QgsField &field : fields )
284 fieldnames.append( field.name() );
285 const thread_local QRegularExpression sCleanTagNameRegExp( QStringLiteral(
"[^\\w\\.-_]" ), QRegularExpression::PatternOption::UseUnicodePropertiesOption );
286 propertynames.append( field.name().replace(
' ',
'_' ).replace( sCleanTagNameRegExp, QString() ) );
289 for ( plstIt = propertyList.constBegin(); plstIt != propertyList.constEnd(); ++plstIt )
292 int fieldNameIdx = propertynames.indexOf( fieldName );
293 if ( fieldNameIdx == -1 )
295 fieldNameIdx = fieldnames.indexOf( fieldName );
297 if ( fieldNameIdx > -1 )
299 idxList.append( fieldNameIdx );
301 else if ( fieldName == QLatin1String(
"geometry" ) )
306 if ( !idxList.isEmpty() )
308 attrIndexes = idxList;
313 if ( !attrIndexes.isEmpty() )
315 for (
const QgsField &field : fields )
319 int fieldNameIdx = fields.indexOf( field.name() );
320 if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
322 attrIndexes.removeOne( fieldNameIdx );
355#ifdef HAVE_SERVER_PYTHON_PLUGINS
376 QStringList attributes = QStringList();
377 for (
int idx : std::as_const( attrIndexes ) )
391 if ( !pkAttributes.isEmpty() )
394 for (
int idx : pkAttributes )
396 if ( !subsetOfAttrs.contains( idx ) )
398 subsetOfAttrs.prepend( idx );
425 geometryName = QLatin1String(
"NONE" );
433 QString outputSrsName;
434 if ( !query.
srsName.isEmpty() )
438 else if ( !requestSrsName.isEmpty() )
440 outputSrsName = requestSrsName;
482 if ( iteratedFeatures >= aRequest.
startIndex )
496 const bool invertAxis { mWfsParameters.versionAsNumber() >=
QgsProjectVersion( 1, 1, 0 ) && outputCrs.
hasAxisInverted() && !outputSrsName.startsWith( QLatin1String(
"EPSG:" ) ) };
498 const createFeatureParams cfp = { layerPrecision, layerCrs, attrIndexes, typeName, withGeom, geometryName, outputCrs, forceGeomToMulti, outputSrsName, invertAxis };
505 if ( iteratedFeatures == aRequest.
startIndex )
506 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList, serverIface->
serverSettings() );
508 if ( iteratedFeatures >= aRequest.
startIndex )
518#ifdef HAVE_SERVER_PYTHON_PLUGINS
520 filterRestorer.reset();
525 hitGetFeature( request, response, project, aRequest.
outputFormat, sentFeatures, typeNameList, serverIface->
serverSettings() );
530 if ( iteratedFeatures <= aRequest.
startIndex )
531 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList, serverIface->
serverSettings() );
539 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();
540 request.
startIndex = mWfsParameters.startIndexAsInt();
544 QStringList fidList = mWfsParameters.featureIds();
545 bool paramContainsFeatureIds = !fidList.isEmpty();
546 QStringList filterList = mWfsParameters.filters();
547 bool paramContainsFilters = !filterList.isEmpty();
548 QString bbox = mWfsParameters.bbox();
549 bool paramContainsBbox = !bbox.isEmpty();
550 if ( ( paramContainsFeatureIds
551 && ( paramContainsFilters || paramContainsBbox ) )
552 || ( paramContainsFilters && ( paramContainsFeatureIds || paramContainsBbox ) )
553 || ( paramContainsBbox && ( paramContainsFeatureIds || paramContainsFilters ) ) )
559 QStringList propertyNameList = mWfsParameters.propertyNames();
562 request.
geometryName = mWfsParameters.geometryNameAsString().toUpper();
564 QStringList typeNameList;
566 if ( paramContainsFeatureIds )
569 if ( !propertyNameList.isEmpty() && propertyNameList.size() != fidList.size() )
573 if ( propertyNameList.isEmpty() )
575 for (
int i = 0; i < fidList.size(); ++i )
577 propertyNameList << QStringLiteral(
"*" );
581 QMap<QString, QStringList> fidsMap;
583 QStringList::const_iterator fidIt = fidList.constBegin();
584 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
585 for ( ; fidIt != fidList.constEnd(); ++fidIt )
588 QString fid = *fidIt;
591 QString propertyName;
592 if ( propertyNameIt != propertyNameList.constEnd() )
594 propertyName = *propertyNameIt;
597 if ( !fid.contains(
'.' ) )
602 QString typeName = fid.section(
'.', 0, 0 );
603 fid = fid.section(
'.', 1, 1 );
604 if ( !typeNameList.contains( typeName ) )
606 typeNameList << typeName;
612 const QString key = QStringLiteral(
"%1:%2" ).arg( typeName, propertyName );
614 if ( fidsMap.contains( key ) )
616 fids = fidsMap.value( key );
619 fidsMap.insert( key, fids );
621 if ( propertyNameIt != propertyNameList.constEnd() )
627 QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
628 while ( fidsMapIt != fidsMap.constEnd() )
630 QString key = fidsMapIt.key();
634 const QString typeName = key.section(
':', 0, 0 );
635 const QString propertyName = key.section(
':', 1, 1 );
639 query.
srsName = mWfsParameters.srsName();
642 if ( propertyName != QLatin1String(
"*" ) )
644 QStringList propertyList;
646 const QStringList attrList = propertyName.split(
',' );
647 QStringList::const_iterator alstIt;
648 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
650 QString fieldName = *alstIt;
651 fieldName = fieldName.trimmed();
652 if ( fieldName.contains(
':' ) )
654 fieldName = fieldName.section(
':', 1, 1 );
656 if ( fieldName.contains(
'/' ) )
658 if ( fieldName.section(
'/', 0, 0 ) != typeName )
662 fieldName = fieldName.section(
'/', 1, 1 );
664 propertyList.append( fieldName );
671 request.
queries.append( query );
677 if ( !mRequestParameters.contains( QStringLiteral(
"TYPENAME" ) ) )
682 typeNameList = mWfsParameters.typeNames();
684 if ( !propertyNameList.isEmpty() && typeNameList.size() != propertyNameList.size() )
688 if ( propertyNameList.isEmpty() )
690 for (
int i = 0; i < typeNameList.size(); ++i )
692 propertyNameList << QStringLiteral(
"*" );
697 QStringList::const_iterator typeNameIt = typeNameList.constBegin();
698 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
699 for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
701 QString typeName = *typeNameIt;
702 typeName = typeName.trimmed();
704 QString propertyName;
705 if ( propertyNameIt != propertyNameList.constEnd() )
707 propertyName = *propertyNameIt;
712 query.
srsName = mWfsParameters.srsName();
715 if ( propertyName != QLatin1String(
"*" ) )
717 QStringList propertyList;
719 const QStringList attrList = propertyName.split(
',' );
720 QStringList::const_iterator alstIt;
721 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
723 QString fieldName = *alstIt;
724 fieldName = fieldName.trimmed();
725 if ( fieldName.contains(
':' ) )
727 fieldName = fieldName.section(
':', 1, 1 );
729 if ( fieldName.contains(
'/' ) )
731 if ( fieldName.section(
'/', 0, 0 ) != typeName )
735 fieldName = fieldName.section(
'/', 1, 1 );
737 propertyList.append( fieldName );
742 request.
queries.append( query );
744 if ( propertyNameIt != propertyNameList.constEnd() )
751 QStringList expFilterList = mWfsParameters.expFilters();
752 if ( !expFilterList.isEmpty() )
755 if ( request.
queries.size() == expFilterList.size() )
758 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
759 QStringList::const_iterator expFilterIt = expFilterList.constBegin();
760 for ( ; qIt != request.
queries.end(); ++qIt )
764 const QString expFilter = *expFilterIt++;
765 std::shared_ptr<QgsExpression> filter(
new QgsExpression( expFilter ) );
768 if ( filter->hasParserError() )
772 if ( filter->needsGeometry() )
786 if ( paramContainsBbox )
791 QString extentSrsName { mWfsParameters.srsName() };
794 if ( mWfsParameters.bbox().split(
',' ).size() == 5 && !mWfsParameters.srsName().isEmpty() )
796 QString crs( mWfsParameters.bbox().split(
',' )[4] );
797 if ( crs != mWfsParameters.srsName() )
827 if ( extentCrs.
isValid() && extentCrs.
hasAxisInverted() && !extentSrsName.startsWith( QLatin1String(
"EPSG:" ) ) )
835 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
836 for ( ; qIt != request.
queries.end(); ++qIt )
842 else if ( paramContainsFilters )
845 if ( request.
queries.size() != filterList.size() )
851 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
852 QStringList::const_iterator filterIt = filterList.constBegin();
853 for ( ; qIt != request.
queries.end(); ++qIt )
858 if ( filterIt != filterList.constEnd() )
861 if ( !filter.setContent( *filterIt,
true, &errorMsg ) )
867 QDomElement filterElem = filter.firstChildElement();
868 QStringList serverFids;
872 if ( filterIt != filterList.constEnd() )
879 QStringList sortByList = mWfsParameters.sortBy();
880 if ( !sortByList.isEmpty() && request.
queries.size() == sortByList.size() )
883 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
884 QStringList::const_iterator sortByIt = sortByList.constBegin();
885 for ( ; qIt != request.
queries.end(); ++qIt )
890 if ( sortByIt != sortByList.constEnd() )
894 for (
const QString &attribute : sortBy.split(
',' ) )
896 if ( attribute.endsWith( QLatin1String(
" D" ) ) || attribute.endsWith( QLatin1String(
"+D" ) ) )
900 else if ( attribute.endsWith( QLatin1String(
" DESC" ) ) || attribute.endsWith( QLatin1String(
"+DESC" ) ) )
904 else if ( attribute.endsWith( QLatin1String(
" A" ) ) || attribute.endsWith( QLatin1String(
"+A" ) ) )
908 else if ( attribute.endsWith( QLatin1String(
" ASC" ) ) || attribute.endsWith( QLatin1String(
"+ASC" ) ) )
926 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();
927 request.
startIndex = mWfsParameters.startIndexAsInt();
930 QDomNodeList queryNodes = docElem.elementsByTagName( QStringLiteral(
"Query" ) );
931 QDomElement queryElem;
932 for (
int i = 0; i < queryNodes.size(); i++ )
934 queryElem = queryNodes.at( i ).toElement();
936 request.
queries.append( query );
943 QDomNodeList sortByNodes = sortByElem.childNodes();
944 if ( sortByNodes.size() )
946 for (
int i = 0; i < sortByNodes.size(); i++ )
948 QDomElement sortPropElem = sortByNodes.at( i ).toElement();
949 QDomNodeList sortPropChildNodes = sortPropElem.childNodes();
950 if ( sortPropChildNodes.size() )
953 bool ascending =
true;
954 for (
int j = 0; j < sortPropChildNodes.size(); j++ )
956 QDomElement sortPropChildElem = sortPropChildNodes.at( j ).toElement();
957 if ( sortPropChildElem.tagName() == QLatin1String(
"PropertyName" ) )
959 fieldName = sortPropChildElem.text().trimmed();
961 else if ( sortPropChildElem.tagName() == QLatin1String(
"SortOrder" ) )
963 QString sortOrder = sortPropChildElem.text().trimmed().toUpper();
964 if ( sortOrder == QLatin1String(
"DESC" ) || sortOrder == QLatin1String(
"D" ) )
969 if ( fieldName.contains(
':' ) )
971 fieldName = fieldName.section(
':', 1, 1 );
973 if ( fieldName.contains(
'/' ) )
975 if ( fieldName.section(
'/', 0, 0 ) != typeName )
979 fieldName = fieldName.section(
'/', 1, 1 );
982 if ( !fieldName.isEmpty() )
983 featureRequest.
addOrderBy( fieldName, ascending );
991 QString typeName = queryElem.attribute( QStringLiteral(
"typeName" ), QString() );
992 if ( typeName.contains(
':' ) )
994 typeName = typeName.section(
':', 1, 1 );
998 QStringList serverFids;
999 QStringList propertyList;
1000 QDomNodeList queryChildNodes = queryElem.childNodes();
1001 if ( queryChildNodes.size() )
1003 QDomElement sortByElem;
1004 for (
int q = 0; q < queryChildNodes.size(); q++ )
1006 QDomElement queryChildElem = queryChildNodes.at( q ).toElement();
1007 if ( queryChildElem.tagName() == QLatin1String(
"PropertyName" ) )
1009 QString fieldName = queryChildElem.text().trimmed();
1010 if ( fieldName.contains(
':' ) )
1012 fieldName = fieldName.section(
':', 1, 1 );
1014 if ( fieldName.contains(
'/' ) )
1016 if ( fieldName.section(
'/', 0, 0 ) != typeName )
1020 fieldName = fieldName.section(
'/', 1, 1 );
1022 propertyList.append( fieldName );
1024 else if ( queryChildElem.tagName() == QLatin1String(
"Filter" ) )
1026 featureRequest =
parseFilterElement( typeName, queryChildElem, serverFids, project );
1028 else if ( queryChildElem.tagName() == QLatin1String(
"SortBy" ) )
1030 sortByElem = queryChildElem;
1037 QString srsName = queryElem.attribute( QStringLiteral(
"srsName" ), QString() );
1050 static QSet<QString> sParamFilter {
1051 QStringLiteral(
"REQUEST" ),
1052 QStringLiteral(
"FORMAT" ),
1053 QStringLiteral(
"OUTPUTFORMAT" ),
1054 QStringLiteral(
"BBOX" ),
1055 QStringLiteral(
"FEATUREID" ),
1056 QStringLiteral(
"TYPENAME" ),
1057 QStringLiteral(
"FILTER" ),
1058 QStringLiteral(
"EXP_FILTER" ),
1059 QStringLiteral(
"MAXFEATURES" ),
1060 QStringLiteral(
"STARTINDEX" ),
1061 QStringLiteral(
"PROPERTYNAME" ),
1062 QStringLiteral(
"_DC" )
1066 void hitGetFeature(
const QgsServerRequest &request, QgsServerResponse &response,
const QgsProject *project,
QgsWfsParameters::Format format,
int numberOfFeatures,
const QStringList &typeNames,
const QgsServerSettings *settings )
1068 QDateTime now = QDateTime::currentDateTime();
1073 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1074 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1075 fcString += QStringLiteral(
" \"timeStamp\": \"%1\",\n" ).arg( now.toString( Qt::ISODate ) );
1076 fcString += QStringLiteral(
" \"numberOfFeatures\": %1\n" ).arg( QString::number( numberOfFeatures ) );
1077 fcString += QLatin1Char(
'}' );
1082 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1084 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1087 QString hrefString =
serviceUrl( request, project, *settings );
1089 QUrl mapUrl( hrefString );
1091 QUrlQuery query( mapUrl );
1092 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1094 if ( mWfsParameters.version().isEmpty() )
1096 else if ( mWfsParameters.versionAsNumber() >= QgsProjectVersion( 1, 1, 0 ) )
1097 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1099 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1101 const auto constItems { query.queryItems() };
1102 for (
const auto ¶m : std::as_const( constItems ) )
1104 if ( sParamFilter.contains( param.first.toUpper() ) )
1105 query.removeAllQueryItems( param.first );
1108 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1109 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1110 if ( mWfsParameters.versionAsNumber() >= QgsProjectVersion( 1, 1, 0 ) )
1113 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1115 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1118 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1120 mapUrl.setQuery( query );
1122 hrefString = mapUrl.toString();
1125 if ( mWfsParameters.version().isEmpty() || mWfsParameters.versionAsNumber() >= QgsProjectVersion( 1, 1, 0 ) )
1126 wfsSchema = QStringLiteral(
"http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" );
1128 wfsSchema = QStringLiteral(
"http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" );
1131 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1135 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1136 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1138 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1139 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" " + wfsSchema +
" " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1140 fcString +=
"\n timeStamp=\"" + now.toString( Qt::ISODate ) +
"\"";
1141 fcString +=
"\n numberOfFeatures=\"" + QString::number( numberOfFeatures ) +
"\"";
1142 fcString += QLatin1String(
">\n" );
1143 fcString += QLatin1String(
"</wfs:FeatureCollection>" );
1146 response.
write( fcString.toUtf8() );
1150 void startGetFeature(
const QgsServerRequest &request, QgsServerResponse &response,
const QgsProject *project,
QgsWfsParameters::Format format,
int prec, QgsCoordinateReferenceSystem &crs, QgsRectangle *rect,
const QStringList &typeNames,
const QgsServerSettings *settings )
1154 std::unique_ptr<QgsRectangle> transformedRect;
1158 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1163 QgsCoordinateTransform transform;
1165 transform.
setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral(
"EPSG:4326" ) ) );
1170 transformedRect = std::make_unique<QgsRectangle>( exportGeom.
boundingBox() );
1171 rect = transformedRect.get();
1174 catch ( QgsException &cse )
1180 rect =
new QgsRectangle( rect->
intersect( QgsRectangle( -180.0, -90.0, 180.0, 90.0 ) ) );
1182 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1186 const QgsCoordinateReferenceSystem destinationCrs { srsName.isEmpty() ? QStringLiteral(
"EPSG:4326" ) : srsName };
1187 if ( !destinationCrs.
isValid() )
1194 for (
const auto &it : value.items() )
1196 fcString +=
" \"" + QString::fromStdString( it.key() ) +
"\": " + QString::fromStdString( it.value().dump() ) +
",\n";
1199 fcString += QLatin1String(
" \"features\": [\n" );
1200 response.
write( fcString.toUtf8() );
1205 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1207 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1210 QString hrefString =
serviceUrl( request, project, *settings );
1212 QUrl mapUrl( hrefString );
1214 QUrlQuery query( mapUrl );
1215 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1217 if ( mWfsParameters.version().isEmpty() )
1219 else if ( mWfsParameters.versionAsNumber() >= QgsProjectVersion( 1, 1, 0 ) )
1220 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1222 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1224 const auto queryItems { query.queryItems() };
1225 for (
auto param : std::as_const( queryItems ) )
1227 if ( sParamFilter.contains( param.first.toUpper() ) )
1228 query.removeAllQueryItems( param.first );
1231 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1232 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1233 if ( mWfsParameters.versionAsNumber() >= QgsProjectVersion( 1, 1, 0 ) )
1236 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1238 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1241 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1243 mapUrl.setQuery( query );
1245 hrefString = mapUrl.toString();
1248 if ( mWfsParameters.version().isEmpty() || mWfsParameters.versionAsNumber() >= QgsProjectVersion( 1, 1, 0 ) )
1249 wfsSchema = QStringLiteral(
"http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" );
1251 wfsSchema = QStringLiteral(
"http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" );
1254 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1258 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1259 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1261 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1262 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" " + wfsSchema +
" " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1263 fcString += QLatin1String(
">\n" );
1265 response.
write( fcString.toUtf8() );
1269 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1274 const QString outputSrsName = !requestSrsName.isEmpty() ? requestSrsName :
getSrsNameFromVersion( crs );
1275 QgsCoordinateReferenceSystem outputCrs;
1278 QgsCoordinateTransform transform;
1281 QgsRectangle crsCorrectedRect { rect ? *rect : QgsRectangle() };
1287 catch ( QgsException &cse )
1297 const bool invertAxis { mWfsParameters.versionAsNumber() >= QgsProjectVersion( 1, 1, 0 ) && outputCrs.
hasAxisInverted() && !outputSrsName.startsWith( QLatin1String(
"EPSG:" ) ) };
1300 if ( !envElem.isNull() )
1302 if ( crs.
isValid() && outputSrsName.isEmpty() )
1306 bbElem.appendChild( envElem );
1307 doc.appendChild( bbElem );
1313 if ( !boxElem.isNull() )
1319 bbElem.appendChild( boxElem );
1320 doc.appendChild( bbElem );
1323 response.
write( doc.toByteArray() );
1328 void setGetFeature( QgsServerResponse &response,
QgsWfsParameters::Format format,
const QgsFeature &feature,
int featIdx,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1337 fcString += QLatin1String(
" " );
1339 fcString += QLatin1String(
" ," );
1341 const QgsCoordinateReferenceSystem destinationCrs { params.srsName.isEmpty() ? QStringLiteral(
"EPSG:4326" ) : params.srsName };
1342 if ( !destinationCrs.
isValid() )
1347 mJsonExporter.setDestinationCrs( destinationCrs );
1348 mJsonExporter.setTransformGeometries(
true );
1349 mJsonExporter.setSourceCrs( params.crs );
1350 mJsonExporter.setIncludeGeometry(
false );
1351 mJsonExporter.setIncludeAttributes( !params.attributeIndexes.isEmpty() );
1352 mJsonExporter.setAttributes( params.attributeIndexes );
1353 fcString += createFeatureGeoJSON( feature, params, pkAttributes );
1354 fcString += QLatin1String(
"\n" );
1356 response.
write( fcString.toUtf8() );
1360 QDomDocument gmlDoc;
1361 QDomElement featureElement;
1364 featureElement = createFeatureGML3( feature, gmlDoc, params, project, pkAttributes );
1365 gmlDoc.appendChild( featureElement );
1369 featureElement = createFeatureGML2( feature, gmlDoc, params, project, pkAttributes );
1370 gmlDoc.appendChild( featureElement );
1372 response.
write( gmlDoc.toByteArray() );
1384 fcString += QLatin1String(
" ]\n" );
1385 fcString += QLatin1Char(
'}' );
1389 fcString = QStringLiteral(
"</wfs:FeatureCollection>\n" );
1391 response.
write( fcString.toUtf8() );
1395 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes )
1403 QgsFeature f( feature );
1404 QgsGeometry geom = feature.
geometry();
1405 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1407 mJsonExporter.setIncludeGeometry(
true );
1408 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1413 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1419 return mJsonExporter.exportFeature( f, QVariantMap(),
id );
1423 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1426 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1429 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1431 typeNameElement.setAttribute( QStringLiteral(
"fid" ),
id );
1432 featureElement.appendChild( typeNameElement );
1435 QgsGeometry geom = feature.
geometry();
1436 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1438 int prec = params.precision;
1439 QgsCoordinateReferenceSystem crs = params.crs;
1440 QgsCoordinateTransform mTransform( crs, params.outputCrs, project );
1443 QgsGeometry transformed = geom;
1447 crs = params.outputCrs;
1448 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1449 prec = std::min( params.precision + 3, 6 );
1452 catch ( QgsCsException &cse )
1457 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1458 QDomElement gmlElem;
1459 QgsGeometry cloneGeom( geom );
1460 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1464 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1470 cloneGeom.convertToMultiType();
1472 const QgsAbstractGeometry *abstractGeom = cloneGeom.constGet();
1475 gmlElem = abstractGeom->
asGml2( doc, prec,
"http://www.opengis.net/gml" );
1478 if ( !gmlElem.isNull() )
1481 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1490 bbElem.appendChild( boxElem );
1491 typeNameElement.appendChild( bbElem );
1493 geomElem.appendChild( gmlElem );
1494 typeNameElement.appendChild( geomElem );
1499 const QgsAttributes featureAttributes = feature.
attributes();
1500 const QgsFields fields = feature.
fields();
1501 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1503 int idx = params.attributeIndexes[i];
1509 const QDomElement fieldElem = createFieldElement( fields.
at( idx ), featureAttributes[idx], doc );
1510 typeNameElement.appendChild( fieldElem );
1513 return featureElement;
1516 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1519 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1522 QDomElement typeNameElement = doc.createElement( QStringLiteral(
"qgs:" ) + params.typeName );
1524 typeNameElement.setAttribute( QStringLiteral(
"gml:id" ),
id );
1525 featureElement.appendChild( typeNameElement );
1528 QgsGeometry geom = feature.
geometry();
1529 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1531 int prec = params.precision;
1532 QgsCoordinateReferenceSystem crs = params.crs;
1533 QgsCoordinateTransform mTransform( crs, params.outputCrs, project );
1536 QgsGeometry transformed = geom;
1540 crs = params.outputCrs;
1541 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1542 prec = std::min( params.precision + 3, 6 );
1545 catch ( QgsCsException &cse )
1550 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1551 QDomElement gmlElem;
1552 QgsGeometry cloneGeom( geom );
1553 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1557 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1563 cloneGeom.convertToMultiType();
1565 const QgsAbstractGeometry *abstractGeom = cloneGeom.constGet();
1571 if ( !gmlElem.isNull() )
1574 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1577 if ( crs.
isValid() && params.srsName.isEmpty() )
1582 else if ( !params.srsName.isEmpty() )
1584 gmlElem.setAttribute( QStringLiteral(
"srsName" ), params.srsName );
1587 bbElem.appendChild( boxElem );
1588 typeNameElement.appendChild( bbElem );
1590 geomElem.appendChild( gmlElem );
1591 typeNameElement.appendChild( geomElem );
1596 const QgsAttributes featureAttributes = feature.
attributes();
1597 const QgsFields fields = feature.
fields();
1598 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1600 int idx = params.attributeIndexes[i];
1606 const QDomElement fieldElem = createFieldElement( fields.
at( idx ), featureAttributes[idx], doc );
1607 typeNameElement.appendChild( fieldElem );
1610 return featureElement;
1613 QDomElement createFieldElement(
const QgsField &field,
const QVariant &value, QDomDocument &doc )
1616 const thread_local QRegularExpression sCleanTagNameRegExp( QStringLiteral(
"[^\\w\\.-_]" ), QRegularExpression::PatternOption::UseUnicodePropertiesOption );
1617 const QString attributeName = field.
name().replace(
' ',
'_' ).replace( sCleanTagNameRegExp, QString() );
1618 QDomElement fieldElem = doc.createElement( QStringLiteral(
"qgs:" ) + attributeName );
1621 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1625 const QString fieldText = encodeValueToText( value, setup );
1627 if ( fieldText.indexOf(
'<' ) != -1 || fieldText.indexOf(
'&' ) != -1 )
1629 fieldElem.appendChild( doc.createCDATASection( fieldText ) );
1633 fieldElem.appendChild( doc.createTextNode( fieldText ) );
1639 QString encodeValueToText(
const QVariant &value,
const QgsEditorWidgetSetup &setup )
1644 if ( setup.
type() == QLatin1String(
"DateTime" ) )
1647 if ( value.userType() == QMetaType::Type::QTime )
1653 const QVariantMap config = setup.
config();
1659 QDateTime date = value.toDateTime();
1661 if ( !date.isValid() )
1663 date = QDateTime::fromString( value.toString(), fieldFormat );
1666 if ( date.isValid() )
1668 return date.toString( fieldFormat );
1671 return value.toString();
1673 else if ( setup.
type() == QLatin1String(
"Range" ) )
1675 const QVariantMap config = setup.
config();
1676 if ( config.contains( QStringLiteral(
"Precision" ) ) )
1680 int precision( config[QStringLiteral(
"Precision" )].toInt( &ok ) );
1682 return QString::number( value.toDouble(),
'f', precision );
1686 switch ( value.userType() )
1688 case QMetaType::Type::Int:
1689 case QMetaType::Type::UInt:
1690 case QMetaType::Type::LongLong:
1691 case QMetaType::Type::ULongLong:
1692 case QMetaType::Type::Double:
1693 return value.toString();
1695 case QMetaType::Type::Bool:
1696 return value.toBool() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" );
1698 case QMetaType::Type::QStringList:
1699 case QMetaType::Type::QVariantList:
1700 case QMetaType::Type::QVariantMap:
1704 case QMetaType::Type::QString:
1705 return value.toString();
@ Success
Operation succeeded.
@ Fid
Filter using feature ID.
@ Fids
Filter using feature IDs.
@ NoFilter
No filter is applied.
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ NoFlags
No flags are set.
@ HideFromWfs
Field is not available if layer is served as WFS from QGIS server.
@ XY
X comes before Y (or lon before lat).
@ YX
Y comes before X (or lat before lon).
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.
virtual void swapXy()=0
Swaps the x and y coordinates from the geometry.
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.
A helper class that centralizes restrictions given by all the access control filter plugins.
QStringList layerAttributes(const QgsVectorLayer *layer, const QStringList &attributes) const override
Returns the authorized layer attributes.
void filterFeatures(const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures) const override
Filter the features of the layer.
bool layerReadPermission(const QgsMapLayer *layer) const
Returns the layer read right.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QString toOgcUrn() const
Returns the crs as OGC URN (format: urn:ogc:def:crs:OGC:1.3:CRS84) Returns an empty string on failure...
bool createFromUserInput(const QString &definition)
Set up this CRS from various text formats.
bool hasAxisInverted() const
Returns whether the axis order is inverted for the CRS compared to the order east/north (longitude/la...
Defines a QGIS exception class.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Handles parsing and evaluation of expressions (formerly called "search strings").
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setLimit(long long limit)
Set the maximum number of features to request.
QgsRectangle filterRect() const
Returns the rectangle from which features will be taken.
QgsFeatureRequest & addOrderBy(const QString &expression, bool ascending=true)
Adds a new OrderByClause, appending it as the least important one.
Qgis::FeatureRequestFilterType filterType() const
Returns the attribute/ID filter type which is currently set on this request.
Qgis::FeatureRequestFlags flags() const
Returns the flags which affect how features are fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
bool acceptFeature(const QgsFeature &feature)
Check if a feature is accepted by this requests filter.
QgsAttributeList subsetOfAttributes() const
Returns the subset of attributes which at least need to be fetched.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool isValid() const
Returns the validity of this feature.
Encapsulate a field in an attribute table or data source.
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Container of fields for a vector layer.
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A geometry is the spatial representation of a feature.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
QgsGeometry centroid() const
Returns the center of mass of a geometry.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.).
static Q_INVOKABLE QString encodeValue(const QVariant &value)
Encodes a value to a JSON string representation, adding appropriate quotations and escaping where req...
static void addCrsInfo(json &value, const QgsCoordinateReferenceSystem &crs)
Add crs information entry in json object regarding old GeoJSON specification format if it differs fro...
QString wfsTypeName() const
Returns WFS typename for the layer.
Base class for all map layer types.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
QgsMapLayerServerProperties * serverProperties()
Returns QGIS Server Properties for the map layer.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
static void applyAccessControlLayerFilters(const QgsAccessControl *accessControl, QgsMapLayer *mapLayer, QHash< QgsMapLayer *, QString > &originalLayerFilters)
Apply filter from AccessControl.
static QDomElement rectangleToGMLEnvelope(const QgsRectangle *env, QDomDocument &doc, int precision=17)
Exports the rectangle to GML3 Envelope.
static QDomElement rectangleToGMLBox(const QgsRectangle *box, QDomDocument &doc, int precision=17)
Exports the rectangle to GML2 Box.
Describes the version of a project.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
A rectangle specified with double values.
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
static QgsFeatureRequest updateFeatureRequestFromServerFids(QgsFeatureRequest &featureRequest, const QStringList &serverFids, const QgsVectorDataProvider *provider)
Returns the feature request based on feature ids build with primary keys.
static QString getServerFid(const QgsFeature &feature, const QgsAttributeList &pkAttributes)
Returns the feature id based on primary keys.
Defines interfaces exposed by QGIS Server and made available to plugins.
virtual QgsAccessControl * accessControls() const =0
Gets the registered access control filters.
virtual QgsServerSettings * serverSettings()=0
Returns the server settings.
QString value(const QString &key) const
Returns the value of a parameter.
static QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS.
static int wfsLayerPrecision(const QgsProject &project, const QString &layerId)
Returns the Layer precision defined in a QGIS project for the WFS GetFeature.
Defines requests passed to QgsService classes.
QgsServerParameters serverParameters() const
Returns parameters.
QgsServerRequest::Parameters parameters() const
Returns a map of query parameters with keys converted to uppercase.
QUrl url() const
Returns the request URL as seen by QGIS server.
QMap< QString, QString > Parameters
virtual QByteArray data() const
Returns post/put data Check for QByteArray::isNull() to check if data is available.
Defines the response interface passed to QgsService.
virtual void write(const QString &data)
Write string This is a convenient method that will write directly to the underlying I/O device.
virtual void flush()
Flushes the current output buffer to the network.
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...
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Base class for vector data providers.
virtual QgsAttributeList pkAttributeIndexes() const
Returns list of indexes of fields that make up the primary key.
Represents a vector layer which manages a vector based dataset.
Q_INVOKABLE QgsAttributeList attributeList() const
Returns list of attribute indexes.
Q_INVOKABLE Qgis::WkbType wkbType() const final
Returns the WKBType or WKBUnknown in case of error.
QgsStringMap attributeAliases() const
Returns a map of field name to attribute alias.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
QgsVectorDataProvider * dataProvider() final
Returns the layer's data provider, it may be nullptr.
Exception thrown when data access violates access controls.
Provides an interface to retrieve and manipulate WFS parameters received from the client.
Format
Output format for the response.
static Q_INVOKABLE bool isMultiType(Qgis::WkbType type)
Returns true if the WKB type is a multi type.
QString implementationVersion()
Returns the highest version supported by this implementation.
QString serviceUrl(const QgsServerRequest &request, const QgsProject *project, const QgsServerSettings &settings)
Service URL string.
const QString OGC_NAMESPACE
const QString GML_NAMESPACE
QString getSrsNameFromVersion(const QgsCoordinateReferenceSystem &crs)
const QString WFS_NAMESPACE
getFeatureRequest parseGetFeatureRequestBody(QDomElement &docElem, const QgsProject *project)
Transform RequestBody root element to getFeatureRequest.
getFeatureQuery parseQueryElement(QDomElement &queryElem, const QgsProject *project)
Transform Query element to getFeatureQuery.
const QString QGS_NAMESPACE
getFeatureRequest parseGetFeatureParameters(const QgsProject *project)
Transform parameters to getFeatureRequest.
void parseSortByElement(QDomElement &sortByElem, QgsFeatureRequest &featureRequest, const QString &typeName)
Add SortBy element to featureRequest.
void writeGetFeature(QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response)
Output WFS GetFeature response.
QgsFeatureRequest parseFilterElement(const QString &typeName, QDomElement &filterElem, QgsProject *project)
Transform a Filter element to a feature request.
#define Q_NOWARN_DEPRECATED_POP
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
#define Q_NOWARN_DEPRECATED_PUSH
QMap< QString, QString > QgsStringMap
QList< int > QgsAttributeList
QgsFeatureRequest featureRequest
QList< getFeatureQuery > queries
QgsWfsParameters::Format outputFormat