47 struct createFeatureParams
70 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes );
72 QDomElement createFieldElement(
const QgsField &
field,
const QVariant &value, QDomDocument &doc );
76 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
78 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
93 QgsWfsParameters mWfsParameters;
106 mWfsParameters.dump();
112 if ( doc.setContent( request.
data(),
true, &errorMsg ) )
114 QDomElement docElem = doc.documentElement();
123 QStringList typeNameList;
126 bool onlyOneLayer = ( aRequest.
queries.size() == 1 );
129 int requestPrecision = 6;
133 QList<getFeatureQuery>::iterator qIt = aRequest.
queries.begin();
134 for ( ; qIt != aRequest.
queries.end(); ++qIt )
136 typeNameList << ( *qIt ).typeName;
142 QMap<QString, QgsMapLayer *> mapLayerMap;
157 if ( typeNameList.contains( name ) )
160 mapLayerMap[name] = layer;
164 requestRect = layer->
extent();
165 requestCrs = layer->
crs();
184 requestRect =
QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
191 for (
const QString &
typeName : typeNameList )
193 if ( !mapLayerMap.contains(
typeName ) )
199 #ifdef HAVE_SERVER_PYTHON_PLUGINS
209 long sentFeatures = 0;
210 long iteratedFeatures = 0;
213 qIt = aRequest.
queries.begin();
214 for ( ; qIt != aRequest.
queries.end(); ++qIt )
220 #ifdef HAVE_SERVER_PYTHON_PLUGINS
238 #ifdef HAVE_SERVER_PYTHON_PLUGINS
245 QMap< int, QString > layerAliasInfo;
247 QgsStringMap::const_iterator aliasIt = aliasMap.constBegin();
248 for ( ; aliasIt != aliasMap.constEnd(); ++aliasIt )
251 if ( attrIndex != -1 )
253 layerAliasInfo.insert( attrIndex, aliasIt.value() );
264 if ( !propertyList.isEmpty() && propertyList.first() != QLatin1String(
"*" ) )
267 QStringList::const_iterator plstIt;
270 QList<QString> propertynames;
271 QList<QString> fieldnames;
278 for ( plstIt = propertyList.constBegin(); plstIt != propertyList.constEnd(); ++plstIt )
281 int fieldNameIdx = propertynames.indexOf( fieldName );
282 if ( fieldNameIdx == -1 )
284 fieldNameIdx = fieldnames.indexOf( fieldName );
286 if ( fieldNameIdx > -1 )
288 idxList.append( fieldNameIdx );
290 else if ( fieldName == QLatin1String(
"geometry" ) )
295 if ( !idxList.isEmpty() )
297 attrIndexes = idxList;
302 if ( !attrIndexes.isEmpty() )
308 int fieldNameIdx = fields.indexOf(
field.
name() );
309 if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
311 attrIndexes.removeOne( fieldNameIdx );
340 #ifdef HAVE_SERVER_PYTHON_PLUGINS
345 QStringList attributes = QStringList();
346 for (
int idx : std::as_const( attrIndexes ) )
359 if ( !pkAttributes.isEmpty() )
362 for (
int idx : pkAttributes )
364 if ( !subsetOfAttrs.contains( idx ) )
366 subsetOfAttrs.prepend( idx );
397 if ( !query.
srsName.isEmpty() )
424 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
428 if ( iteratedFeatures >= aRequest.
startIndex )
440 const bool invertAxis { mWfsParameters.versionAsNumber() >=
QgsProjectVersion( 1, 1, 0 ) &&
442 !
srsName.startsWith( QLatin1String(
"EPSG:" ) ) };
444 const createFeatureParams cfp = { layerPrecision,
457 if ( iteratedFeatures == aRequest.
startIndex )
458 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList, serverIface->
serverSettings() );
460 if ( iteratedFeatures >= aRequest.
startIndex )
470 #ifdef HAVE_SERVER_PYTHON_PLUGINS
472 filterRestorer.reset();
475 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
477 hitGetFeature( request, response, project, aRequest.
outputFormat, sentFeatures, typeNameList, serverIface->
serverSettings() );
482 if ( iteratedFeatures <= aRequest.
startIndex )
483 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList, serverIface->
serverSettings() );
492 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();
493 request.
startIndex = mWfsParameters.startIndexAsInt();
497 QStringList fidList = mWfsParameters.featureIds();
498 bool paramContainsFeatureIds = !fidList.isEmpty();
499 QStringList filterList = mWfsParameters.filters();
500 bool paramContainsFilters = !filterList.isEmpty();
501 QString bbox = mWfsParameters.bbox();
502 bool paramContainsBbox = !bbox.isEmpty();
503 if ( ( paramContainsFeatureIds
504 && ( paramContainsFilters || paramContainsBbox ) )
505 || ( paramContainsFilters
506 && ( paramContainsFeatureIds || paramContainsBbox ) )
507 || ( paramContainsBbox
508 && ( paramContainsFeatureIds || paramContainsFilters ) )
515 QStringList propertyNameList = mWfsParameters.propertyNames();
518 request.
geometryName = mWfsParameters.geometryNameAsString().toUpper();
520 QStringList typeNameList;
522 if ( paramContainsFeatureIds )
525 if ( !propertyNameList.isEmpty() && propertyNameList.size() != fidList.size() )
529 if ( propertyNameList.isEmpty() )
531 for (
int i = 0; i < fidList.size(); ++i )
533 propertyNameList << QStringLiteral(
"*" );
537 QMap<QString, QStringList> fidsMap;
539 QStringList::const_iterator fidIt = fidList.constBegin();
540 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
541 for ( ; fidIt != fidList.constEnd(); ++fidIt )
544 QString fid = *fidIt;
547 QString propertyName;
548 if ( propertyNameIt != propertyNameList.constEnd() )
550 propertyName = *propertyNameIt;
553 if ( !fid.contains(
'.' ) )
558 QString
typeName = fid.section(
'.', 0, 0 );
559 fid = fid.section(
'.', 1, 1 );
560 if ( !typeNameList.contains(
typeName ) )
568 const QString key = QStringLiteral(
"%1:%2" ).arg(
typeName, propertyName );
570 if ( fidsMap.contains( key ) )
572 fids = fidsMap.value( key );
575 fidsMap.insert( key, fids );
577 if ( propertyNameIt != propertyNameList.constEnd() )
583 QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
584 while ( fidsMapIt != fidsMap.constEnd() )
586 QString key = fidsMapIt.key();
590 const QString
typeName = key.section(
':', 0, 0 );
591 const QString propertyName = key.section(
':', 1, 1 );
595 query.
srsName = mWfsParameters.srsName();
598 if ( propertyName != QLatin1String(
"*" ) )
600 QStringList propertyList;
602 const QStringList attrList = propertyName.split(
',' );
603 QStringList::const_iterator alstIt;
604 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
606 QString fieldName = *alstIt;
607 fieldName = fieldName.trimmed();
608 if ( fieldName.contains(
':' ) )
610 fieldName = fieldName.section(
':', 1, 1 );
612 if ( fieldName.contains(
'/' ) )
614 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
618 fieldName = fieldName.section(
'/', 1, 1 );
620 propertyList.append( fieldName );
629 request.
queries.append( query );
635 if ( !mRequestParameters.contains( QStringLiteral(
"TYPENAME" ) ) )
640 typeNameList = mWfsParameters.typeNames();
642 if ( !propertyNameList.isEmpty() && typeNameList.size() != propertyNameList.size() )
646 if ( propertyNameList.isEmpty() )
648 for (
int i = 0; i < typeNameList.size(); ++i )
650 propertyNameList << QStringLiteral(
"*" );
655 QStringList::const_iterator typeNameIt = typeNameList.constBegin();
656 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
657 for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
662 QString propertyName;
663 if ( propertyNameIt != propertyNameList.constEnd() )
665 propertyName = *propertyNameIt;
670 query.
srsName = mWfsParameters.srsName();
673 if ( propertyName != QLatin1String(
"*" ) )
675 QStringList propertyList;
677 const QStringList attrList = propertyName.split(
',' );
678 QStringList::const_iterator alstIt;
679 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
681 QString fieldName = *alstIt;
682 fieldName = fieldName.trimmed();
683 if ( fieldName.contains(
':' ) )
685 fieldName = fieldName.section(
':', 1, 1 );
687 if ( fieldName.contains(
'/' ) )
689 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
693 fieldName = fieldName.section(
'/', 1, 1 );
695 propertyList.append( fieldName );
700 request.
queries.append( query );
702 if ( propertyNameIt != propertyNameList.constEnd() )
709 QStringList expFilterList = mWfsParameters.expFilters();
710 if ( !expFilterList.isEmpty() )
713 if ( request.
queries.size() == expFilterList.size() )
716 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
717 QStringList::const_iterator expFilterIt = expFilterList.constBegin();
718 for ( ; qIt != request.
queries.end(); ++qIt )
722 const QString expFilter = *expFilterIt++;
723 std::shared_ptr<QgsExpression> filter(
new QgsExpression( expFilter ) );
726 if ( filter->hasParserError() )
730 if ( filter->needsGeometry() )
744 if ( paramContainsBbox )
750 QString extentSrsName { mWfsParameters.srsName() };
753 if ( mWfsParameters.bbox().split(
',' ).size() == 5 && ! mWfsParameters.srsName().isEmpty() )
755 QString
crs( mWfsParameters.bbox().split(
',' )[4] );
756 if (
crs != mWfsParameters.srsName() )
786 if ( extentCrs.
isValid() && extentCrs.
hasAxisInverted() && ! extentSrsName.startsWith( QLatin1String(
"EPSG:" ) ) )
790 extent = geom.boundingBox();
794 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
795 for ( ; qIt != request.
queries.end(); ++qIt )
802 else if ( paramContainsFilters )
805 if ( request.
queries.size() != filterList.size() )
811 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
812 QStringList::const_iterator filterIt = filterList.constBegin();
813 for ( ; qIt != request.
queries.end(); ++qIt )
818 if ( filterIt != filterList.constEnd() )
821 if ( !filter.setContent( *filterIt,
true, &errorMsg ) )
827 QDomElement filterElem = filter.firstChildElement();
828 QStringList serverFids;
832 if ( filterIt != filterList.constEnd() )
840 QStringList sortByList = mWfsParameters.sortBy();
841 if ( !sortByList.isEmpty() && request.
queries.size() == sortByList.size() )
844 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
845 QStringList::const_iterator sortByIt = sortByList.constBegin();
846 for ( ; qIt != request.
queries.end(); ++qIt )
851 if ( sortByIt != sortByList.constEnd() )
855 for (
const QString &attribute : sortBy.split(
',' ) )
857 if ( attribute.endsWith( QLatin1String(
" D" ) ) || attribute.endsWith( QLatin1String(
"+D" ) ) )
861 else if ( attribute.endsWith( QLatin1String(
" DESC" ) ) || attribute.endsWith( QLatin1String(
"+DESC" ) ) )
865 else if ( attribute.endsWith( QLatin1String(
" A" ) ) || attribute.endsWith( QLatin1String(
"+A" ) ) )
869 else if ( attribute.endsWith( QLatin1String(
" ASC" ) ) || attribute.endsWith( QLatin1String(
"+ASC" ) ) )
887 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();
888 request.
startIndex = mWfsParameters.startIndexAsInt();
891 QDomNodeList queryNodes = docElem.elementsByTagName( QStringLiteral(
"Query" ) );
892 QDomElement queryElem;
893 for (
int i = 0; i < queryNodes.size(); i++ )
895 queryElem = queryNodes.at( i ).toElement();
897 request.
queries.append( query );
904 QDomNodeList sortByNodes = sortByElem.childNodes();
905 if ( sortByNodes.size() )
907 for (
int i = 0; i < sortByNodes.size(); i++ )
909 QDomElement sortPropElem = sortByNodes.at( i ).toElement();
910 QDomNodeList sortPropChildNodes = sortPropElem.childNodes();
911 if ( sortPropChildNodes.size() )
914 bool ascending =
true;
915 for (
int j = 0; j < sortPropChildNodes.size(); j++ )
917 QDomElement sortPropChildElem = sortPropChildNodes.at( j ).toElement();
918 if ( sortPropChildElem.tagName() == QLatin1String(
"PropertyName" ) )
920 fieldName = sortPropChildElem.text().trimmed();
922 else if ( sortPropChildElem.tagName() == QLatin1String(
"SortOrder" ) )
924 QString sortOrder = sortPropChildElem.text().trimmed().toUpper();
925 if ( sortOrder == QLatin1String(
"DESC" ) || sortOrder == QLatin1String(
"D" ) )
930 if ( fieldName.contains(
':' ) )
932 fieldName = fieldName.section(
':', 1, 1 );
934 if ( fieldName.contains(
'/' ) )
936 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
940 fieldName = fieldName.section(
'/', 1, 1 );
943 if ( !fieldName.isEmpty() )
944 featureRequest.
addOrderBy( fieldName, ascending );
952 QString
typeName = queryElem.attribute( QStringLiteral(
"typeName" ), QString() );
959 QStringList serverFids;
960 QStringList propertyList;
961 QDomNodeList queryChildNodes = queryElem.childNodes();
962 if ( queryChildNodes.size() )
964 QDomElement sortByElem;
965 for (
int q = 0; q < queryChildNodes.size(); q++ )
967 QDomElement queryChildElem = queryChildNodes.at( q ).toElement();
968 if ( queryChildElem.tagName() == QLatin1String(
"PropertyName" ) )
970 QString fieldName = queryChildElem.text().trimmed();
971 if ( fieldName.contains(
':' ) )
973 fieldName = fieldName.section(
':', 1, 1 );
975 if ( fieldName.contains(
'/' ) )
977 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
981 fieldName = fieldName.section(
'/', 1, 1 );
983 propertyList.append( fieldName );
985 else if ( queryChildElem.tagName() == QLatin1String(
"Filter" ) )
989 else if ( queryChildElem.tagName() == QLatin1String(
"SortBy" ) )
991 sortByElem = queryChildElem;
998 QString
srsName = queryElem.attribute( QStringLiteral(
"srsName" ), QString() );
1011 static QSet< QString > sParamFilter
1013 QStringLiteral(
"REQUEST" ),
1014 QStringLiteral(
"FORMAT" ),
1015 QStringLiteral(
"OUTPUTFORMAT" ),
1016 QStringLiteral(
"BBOX" ),
1017 QStringLiteral(
"FEATUREID" ),
1018 QStringLiteral(
"TYPENAME" ),
1019 QStringLiteral(
"FILTER" ),
1020 QStringLiteral(
"EXP_FILTER" ),
1021 QStringLiteral(
"MAXFEATURES" ),
1022 QStringLiteral(
"STARTINDEX" ),
1023 QStringLiteral(
"PROPERTYNAME" ),
1024 QStringLiteral(
"_DC" )
1029 int numberOfFeatures,
const QStringList &typeNames,
const QgsServerSettings *settings )
1031 QDateTime now = QDateTime::currentDateTime();
1034 if ( format == QgsWfsParameters::Format::GeoJSON )
1036 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1037 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1038 fcString += QStringLiteral(
" \"timeStamp\": \"%1\"\n" ).arg( now.toString( Qt::ISODate ) );
1039 fcString += QStringLiteral(
" \"numberOfFeatures\": %1\n" ).arg( QString::number( numberOfFeatures ) );
1040 fcString += QLatin1Char(
'}' );
1044 if ( format == QgsWfsParameters::Format::GML2 )
1045 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1047 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1050 QString hrefString =
serviceUrl( request, project, *settings );
1052 QUrl mapUrl( hrefString );
1054 QUrlQuery query( mapUrl );
1055 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1057 if ( mWfsParameters.version().isEmpty() )
1060 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1062 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1064 for (
auto param : query.queryItems() )
1066 if ( sParamFilter.contains( param.first.toUpper() ) )
1067 query.removeAllQueryItems( param.first );
1070 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1071 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1074 if ( format == QgsWfsParameters::Format::GML2 )
1075 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1077 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1080 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1082 mapUrl.setQuery( query );
1084 hrefString = mapUrl.toString();
1087 if ( mWfsParameters.version().isEmpty() || mWfsParameters.versionAsNumber() >=
QgsProjectVersion( 1, 1, 0 ) )
1088 wfsSchema = QStringLiteral(
"http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" );
1090 wfsSchema = QStringLiteral(
"http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" );
1093 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1097 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1098 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1100 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1101 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" " + wfsSchema +
" " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1102 fcString +=
"\n timeStamp=\"" + now.toString( Qt::ISODate ) +
"\"";
1103 fcString +=
"\n numberOfFeatures=\"" + QString::number( numberOfFeatures ) +
"\"";
1104 fcString += QLatin1String(
">\n" );
1105 fcString += QLatin1String(
"</wfs:FeatureCollection>" );
1108 response.
write( fcString.toUtf8() );
1117 std::unique_ptr< QgsRectangle > transformedRect;
1119 if ( format == QgsWfsParameters::Format::GeoJSON )
1121 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1134 rect = transformedRect.get();
1145 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1147 fcString += QLatin1String(
" \"features\": [\n" );
1148 response.
write( fcString.toUtf8() );
1152 if ( format == QgsWfsParameters::Format::GML2 )
1153 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1155 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1158 QString hrefString =
serviceUrl( request, project, *settings );
1160 QUrl mapUrl( hrefString );
1162 QUrlQuery query( mapUrl );
1163 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1165 if ( mWfsParameters.version().isEmpty() )
1168 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1170 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1172 const auto queryItems {query.queryItems()};
1173 for (
auto param : std::as_const( queryItems ) )
1175 if ( sParamFilter.contains( param.first.toUpper() ) )
1176 query.removeAllQueryItems( param.first );
1179 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1180 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1183 if ( format == QgsWfsParameters::Format::GML2 )
1184 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1186 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1189 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1191 mapUrl.setQuery( query );
1193 hrefString = mapUrl.toString();
1196 if ( mWfsParameters.version().isEmpty() || mWfsParameters.versionAsNumber() >=
QgsProjectVersion( 1, 1, 0 ) )
1197 wfsSchema = QStringLiteral(
"http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" );
1199 wfsSchema = QStringLiteral(
"http://schemas.opengis.net/wfs/1.0.0/wfs.xsd" );
1202 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1206 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1207 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1209 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1210 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" " + wfsSchema +
" " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1211 fcString += QLatin1String(
">\n" );
1213 response.
write( fcString.toUtf8() );
1217 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1218 if ( format == QgsWfsParameters::Format::GML3 )
1222 const bool invertAxis { mWfsParameters.versionAsNumber() >=
QgsProjectVersion( 1, 1, 0 ) &&
1224 !
srsName.startsWith( QLatin1String(
"EPSG:" ) ) };
1226 if ( !envElem.isNull() )
1230 envElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1232 bbElem.appendChild( envElem );
1233 doc.appendChild( bbElem );
1239 if ( !boxElem.isNull() )
1243 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1245 bbElem.appendChild( boxElem );
1246 doc.appendChild( bbElem );
1249 response.
write( doc.toByteArray() );
1260 if ( format == QgsWfsParameters::Format::GeoJSON )
1264 fcString += QLatin1String(
" " );
1266 fcString += QLatin1String(
" ," );
1267 mJsonExporter.setSourceCrs( params.crs );
1268 mJsonExporter.setIncludeGeometry(
false );
1269 mJsonExporter.setIncludeAttributes( !params.attributeIndexes.isEmpty() );
1270 mJsonExporter.setAttributes( params.attributeIndexes );
1271 fcString += createFeatureGeoJSON( feature, params, pkAttributes );
1272 fcString += QLatin1String(
"\n" );
1274 response.
write( fcString.toUtf8() );
1278 QDomDocument gmlDoc;
1279 QDomElement featureElement;
1280 if ( format == QgsWfsParameters::Format::GML3 )
1282 featureElement = createFeatureGML3( feature, gmlDoc, params, project, pkAttributes );
1283 gmlDoc.appendChild( featureElement );
1287 featureElement = createFeatureGML2( feature, gmlDoc, params, project, pkAttributes );
1288 gmlDoc.appendChild( featureElement );
1290 response.
write( gmlDoc.toByteArray() );
1300 if ( format == QgsWfsParameters::Format::GeoJSON )
1302 fcString += QLatin1String(
" ]\n" );
1303 fcString += QLatin1Char(
'}' );
1307 fcString = QStringLiteral(
"</wfs:FeatureCollection>\n" );
1309 response.
write( fcString.toUtf8() );
1313 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes )
1323 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1325 mJsonExporter.setIncludeGeometry(
true );
1326 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1331 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1337 return mJsonExporter.exportFeature( f, QVariantMap(),
id );
1341 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1344 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1347 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1349 typeNameElement.setAttribute( QStringLiteral(
"fid" ),
id );
1350 featureElement.appendChild( typeNameElement );
1354 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1356 int prec = params.precision;
1365 crs = params.outputCrs;
1367 prec = std::min( params.precision + 3, 6 );
1375 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1376 QDomElement gmlElem;
1378 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1382 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1393 gmlElem = abstractGeom->
asGml2( doc, prec,
"http://www.opengis.net/gml" );
1396 if ( !gmlElem.isNull() )
1399 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1404 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1405 gmlElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1408 bbElem.appendChild( boxElem );
1409 typeNameElement.appendChild( bbElem );
1411 geomElem.appendChild( gmlElem );
1412 typeNameElement.appendChild( geomElem );
1419 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1421 int idx = params.attributeIndexes[i];
1422 if ( idx >= fields.
count() )
1427 const QDomElement fieldElem = createFieldElement( fields.
at( idx ), featureAttributes[idx], doc );
1428 typeNameElement.appendChild( fieldElem );
1431 return featureElement;
1434 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1437 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1440 QDomElement typeNameElement = doc.createElement( QStringLiteral(
"qgs:" ) + params.typeName );
1442 typeNameElement.setAttribute( QStringLiteral(
"gml:id" ),
id );
1443 featureElement.appendChild( typeNameElement );
1447 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1449 int prec = params.precision;
1458 crs = params.outputCrs;
1460 prec = std::min( params.precision + 3, 6 );
1468 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1469 QDomElement gmlElem;
1471 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1475 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1486 gmlElem = abstractGeom->
asGml3( doc, prec,
"http://www.opengis.net/gml", params.hasAxisInverted ? QgsAbstractGeometry::AxisOrder::YX : QgsAbstractGeometry::AxisOrder::XY );
1489 if ( !gmlElem.isNull() )
1492 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1495 if (
crs.
isValid() && params.srsName.isEmpty() )
1497 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1498 gmlElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1500 else if ( !params.srsName.isEmpty() )
1502 gmlElem.setAttribute( QStringLiteral(
"srsName" ), params.srsName );
1505 bbElem.appendChild( boxElem );
1506 typeNameElement.appendChild( bbElem );
1508 geomElem.appendChild( gmlElem );
1509 typeNameElement.appendChild( geomElem );
1516 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1518 int idx = params.attributeIndexes[i];
1519 if ( idx >= fields.
count() )
1524 const QDomElement fieldElem = createFieldElement( fields.
at( idx ), featureAttributes[idx], doc );
1525 typeNameElement.appendChild( fieldElem );
1528 return featureElement;
1531 QDomElement createFieldElement(
const QgsField &
field,
const QVariant &value, QDomDocument &doc )
1535 QDomElement fieldElem = doc.createElement( QStringLiteral(
"qgs:" ) + attributeName );
1536 if ( value.isNull() )
1538 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1542 const QString fieldText = encodeValueToText( value, setup );
1544 if ( fieldText.indexOf(
'<' ) != -1 || fieldText.indexOf(
'&' ) != -1 )
1546 fieldElem.appendChild( doc.createCDATASection( fieldText ) );
1550 fieldElem.appendChild( doc.createTextNode( fieldText ) );
1558 if ( value.isNull() )
1561 if ( setup.
type() == QStringLiteral(
"DateTime" ) )
1563 const QVariantMap config = setup.
config();
1565 QDateTime date = value.toDateTime();
1567 if ( date.isValid() )
1569 return date.toString( fieldFormat );
1572 else if ( setup.
type() == QStringLiteral(
"Range" ) )
1574 const QVariantMap config = setup.
config();
1575 if ( config.contains( QStringLiteral(
"Precision" ) ) )
1579 int precision( config[ QStringLiteral(
"Precision" ) ].toInt( &ok ) );
1581 return QString::number( value.toDouble(),
'f',
precision );
1585 switch ( value.type() )
1588 case QVariant::UInt:
1589 case QVariant::LongLong:
1590 case QVariant::ULongLong:
1591 case QVariant::Double:
1592 return value.toString();
1594 case QVariant::Bool:
1595 return value.toBool() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" );
1597 case QVariant::StringList:
1598 case QVariant::List:
1603 case QVariant::String:
1604 return value.toString();
@ Success
Operation succeeded.
Abstract base class for all geometries.
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.
This class represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool createFromUserInput(const QString &definition)
Set up this CRS from various text formats.
bool hasAxisInverted() const
Returns whether axis is inverted (e.g., for WMS 1.3) for the CRS.
Custom exception class for Coordinate Reference System related exceptions.
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...
Class for 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)
This class wraps a request for features to a vector layer (or directly its vector data provider).
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 & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & addOrderBy(const QString &expression, bool ascending=true)
Adds a new OrderByClause, appending it as the least important one.
Flags 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.
@ 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.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
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.
ConfigurationFlags configurationFlags
@ HideFromWfs
Field is not available if layer is served as WFS from QGIS server.
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Container of fields for a vector layer.
int count() const
Returns number of items.
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).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A geometry is the spatial representation of a feature.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
QgsGeometry centroid() const
Returns the center of mass of a geometry.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Handles exporting QgsFeature features to GeoJSON features.
static Q_INVOKABLE QString encodeValue(const QVariant &value)
Encodes a value to a JSON string representation, adding appropriate quotations and escaping where req...
Base class for all map layer types.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
RAII class to restore layer filters on destruction.
static void applyAccessControlLayerFilters(const QgsAccessControl *accessControl, QgsMapLayer *mapLayer, QHash< QgsMapLayer *, QString > &originalLayerFilters)
Apply filter from AccessControl.
static QDomElement rectangleToGMLEnvelope(QgsRectangle *env, QDomDocument &doc, int precision=17)
Exports the rectangle to GML3 Envelope.
static QDomElement rectangleToGMLBox(QgsRectangle *box, QDomDocument &doc, int precision=17)
Exports the rectangle to GML2 Box.
A class to describe 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.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
bool isEmpty() const
Returns true if the rectangle is empty.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
QgsServerInterface Class defining 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.
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
QgsServerParameters serverParameters() const
Returns parameters.
QgsServerRequest::Parameters parameters() const
Returns a map of query parameters with keys converted to uppercase.
QMap< QString, QString > Parameters
virtual QByteArray data() const
Returns post/put data Check for QByteArray::isNull() to check if data is available.
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
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() SIP_THROW(QgsServerException)
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...
Provides a way to retrieve settings by prioritizing according to environment variables,...
This is the 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 data sets.
Q_INVOKABLE QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsAttributeList attributeList() const
Returns list of attribute indexes.
QgsStringMap attributeAliases() const
Returns a map of field name to attribute alias.
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 bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
@ VectorLayer
Vector layer.
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 QString getServerFid(const QgsFeature &feature, const QgsAttributeList &pkAttributes)
Returns the feature id based on primary keys.
SERVER_EXPORT QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS.
SERVER_EXPORT int wfsLayerPrecision(const QgsProject &project, const QString &layerId)
Returns the Layer precision defined in a QGIS project for the WFS GetFeature.
QString layerTypeName(const QgsMapLayer *layer)
Returns typename from vector layer.
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
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.
const QRegExp cleanTagNameRegExp("(?![\\w\\d\\.-]).")
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QMap< QString, QString > QgsStringMap
QList< int > QgsAttributeList
const QString & geometryName
const QgsCoordinateReferenceSystem & outputCrs
const QgsCoordinateReferenceSystem & crs
const QgsAttributeList & attributeIndexes
QgsFeatureRequest featureRequest
QgsWfsParameters::Format outputFormat
QList< getFeatureQuery > queries