47 struct createFeatureParams
70 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes );
74 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
76 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
91 QgsWfsParameters mWfsParameters;
104 mWfsParameters.dump();
110 if ( doc.setContent( request.
data(),
true, &errorMsg ) )
112 QDomElement docElem = doc.documentElement();
121 QStringList typeNameList;
124 bool onlyOneLayer = ( aRequest.
queries.size() == 1 );
127 int requestPrecision = 6;
131 QList<getFeatureQuery>::iterator qIt = aRequest.
queries.begin();
132 for ( ; qIt != aRequest.
queries.end(); ++qIt )
134 typeNameList << ( *qIt ).typeName;
140 QMap<QString, QgsMapLayer *> mapLayerMap;
155 if ( typeNameList.contains( name ) )
158 mapLayerMap[name] = layer;
162 requestRect = layer->
extent();
163 requestCrs = layer->
crs();
182 requestRect =
QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
188 #ifdef HAVE_SERVER_PYTHON_PLUGINS
198 long sentFeatures = 0;
199 long iteratedFeatures = 0;
202 qIt = aRequest.
queries.begin();
203 for ( ; qIt != aRequest.
queries.end(); ++qIt )
208 if ( !mapLayerMap.contains(
typeName ) )
214 #ifdef HAVE_SERVER_PYTHON_PLUGINS
232 #ifdef HAVE_SERVER_PYTHON_PLUGINS
239 QMap< int, QString > layerAliasInfo;
241 QgsStringMap::const_iterator aliasIt = aliasMap.constBegin();
242 for ( ; aliasIt != aliasMap.constEnd(); ++aliasIt )
245 if ( attrIndex != -1 )
247 layerAliasInfo.insert( attrIndex, aliasIt.value() );
258 if ( !propertyList.isEmpty() && propertyList.first() != QLatin1String(
"*" ) )
261 QStringList::const_iterator plstIt;
264 QList<QString> propertynames;
265 QList<QString> fieldnames;
272 for ( plstIt = propertyList.constBegin(); plstIt != propertyList.constEnd(); ++plstIt )
275 int fieldNameIdx = propertynames.indexOf( fieldName );
276 if ( fieldNameIdx == -1 )
278 fieldNameIdx = fieldnames.indexOf( fieldName );
280 if ( fieldNameIdx > -1 )
282 idxList.append( fieldNameIdx );
284 else if ( fieldName == QLatin1String(
"geometry" ) )
289 if ( !idxList.isEmpty() )
291 attrIndexes = idxList;
296 if ( !attrIndexes.isEmpty() )
302 int fieldNameIdx = fields.indexOf(
field.
name() );
303 if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
305 attrIndexes.removeOne( fieldNameIdx );
334 #ifdef HAVE_SERVER_PYTHON_PLUGINS
339 QStringList attributes = QStringList();
340 for (
int idx : std::as_const( attrIndexes ) )
353 if ( !pkAttributes.isEmpty() )
356 for (
int idx : pkAttributes )
358 if ( !subsetOfAttrs.contains( idx ) )
360 subsetOfAttrs.prepend( idx );
391 if ( !query.
srsName.isEmpty() )
418 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
422 if ( iteratedFeatures >= aRequest.
startIndex )
434 const bool invertAxis { mWfsParameters.versionAsNumber() >=
QgsProjectVersion( 1, 1, 0 ) &&
436 !
srsName.startsWith( QLatin1String(
"EPSG:" ) ) };
438 const createFeatureParams cfp = { layerPrecision,
451 if ( iteratedFeatures == aRequest.
startIndex )
452 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList, serverIface->
serverSettings() );
454 if ( iteratedFeatures >= aRequest.
startIndex )
464 #ifdef HAVE_SERVER_PYTHON_PLUGINS
466 filterRestorer.reset();
469 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
471 hitGetFeature( request, response, project, aRequest.
outputFormat, sentFeatures, typeNameList, serverIface->
serverSettings() );
476 if ( iteratedFeatures <= aRequest.
startIndex )
477 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList, serverIface->
serverSettings() );
486 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();
487 request.
startIndex = mWfsParameters.startIndexAsInt();
491 QStringList fidList = mWfsParameters.featureIds();
492 bool paramContainsFeatureIds = !fidList.isEmpty();
493 QStringList filterList = mWfsParameters.filters();
494 bool paramContainsFilters = !filterList.isEmpty();
495 QString bbox = mWfsParameters.bbox();
496 bool paramContainsBbox = !bbox.isEmpty();
497 if ( ( paramContainsFeatureIds
498 && ( paramContainsFilters || paramContainsBbox ) )
499 || ( paramContainsFilters
500 && ( paramContainsFeatureIds || paramContainsBbox ) )
501 || ( paramContainsBbox
502 && ( paramContainsFeatureIds || paramContainsFilters ) )
509 QStringList propertyNameList = mWfsParameters.propertyNames();
512 request.
geometryName = mWfsParameters.geometryNameAsString().toUpper();
514 QStringList typeNameList;
516 if ( paramContainsFeatureIds )
519 if ( !propertyNameList.isEmpty() && propertyNameList.size() != fidList.size() )
523 if ( propertyNameList.isEmpty() )
525 for (
int i = 0; i < fidList.size(); ++i )
527 propertyNameList << QStringLiteral(
"*" );
531 QMap<QString, QStringList> fidsMap;
533 QStringList::const_iterator fidIt = fidList.constBegin();
534 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
535 for ( ; fidIt != fidList.constEnd(); ++fidIt )
538 QString fid = *fidIt;
541 QString propertyName;
542 if ( propertyNameIt != propertyNameList.constEnd() )
544 propertyName = *propertyNameIt;
547 if ( !fid.contains(
'.' ) )
552 QString
typeName = fid.section(
'.', 0, 0 );
553 fid = fid.section(
'.', 1, 1 );
554 if ( !typeNameList.contains(
typeName ) )
560 QString key = QStringLiteral(
"%1(%2)" ).arg(
typeName, propertyName );
562 if ( fidsMap.contains( key ) )
564 fids = fidsMap.value( key );
567 fidsMap.insert( key, fids );
569 if ( propertyNameIt != propertyNameList.constEnd() )
575 QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
576 while ( fidsMapIt != fidsMap.constEnd() )
578 QString key = fidsMapIt.key();
581 QRegExp rx(
"([^()]+)\\(([^()]+)\\)" );
582 if ( rx.indexIn( key, 0 ) == -1 )
587 QString propertyName = rx.cap( 2 );
591 query.
srsName = mWfsParameters.srsName();
594 if ( propertyName != QLatin1String(
"*" ) )
596 QStringList propertyList;
598 const QStringList attrList = propertyName.split(
',' );
599 QStringList::const_iterator alstIt;
600 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
602 QString fieldName = *alstIt;
603 fieldName = fieldName.trimmed();
604 if ( fieldName.contains(
':' ) )
606 fieldName = fieldName.section(
':', 1, 1 );
608 if ( fieldName.contains(
'/' ) )
610 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
614 fieldName = fieldName.section(
'/', 1, 1 );
616 propertyList.append( fieldName );
625 request.
queries.append( query );
631 if ( !mRequestParameters.contains( QStringLiteral(
"TYPENAME" ) ) )
636 typeNameList = mWfsParameters.typeNames();
638 if ( !propertyNameList.isEmpty() && typeNameList.size() != propertyNameList.size() )
642 if ( propertyNameList.isEmpty() )
644 for (
int i = 0; i < typeNameList.size(); ++i )
646 propertyNameList << QStringLiteral(
"*" );
651 QStringList::const_iterator typeNameIt = typeNameList.constBegin();
652 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
653 for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
658 QString propertyName;
659 if ( propertyNameIt != propertyNameList.constEnd() )
661 propertyName = *propertyNameIt;
666 query.
srsName = mWfsParameters.srsName();
669 if ( propertyName != QLatin1String(
"*" ) )
671 QStringList propertyList;
673 const QStringList attrList = propertyName.split(
',' );
674 QStringList::const_iterator alstIt;
675 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
677 QString fieldName = *alstIt;
678 fieldName = fieldName.trimmed();
679 if ( fieldName.contains(
':' ) )
681 fieldName = fieldName.section(
':', 1, 1 );
683 if ( fieldName.contains(
'/' ) )
685 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
689 fieldName = fieldName.section(
'/', 1, 1 );
691 propertyList.append( fieldName );
696 request.
queries.append( query );
698 if ( propertyNameIt != propertyNameList.constEnd() )
705 QStringList expFilterList = mWfsParameters.expFilters();
706 if ( !expFilterList.isEmpty() )
709 if ( request.
queries.size() == expFilterList.size() )
712 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
713 QStringList::const_iterator expFilterIt = expFilterList.constBegin();
714 for ( ; qIt != request.
queries.end(); ++qIt )
719 if ( expFilterIt != expFilterList.constEnd() )
721 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() )
1232 envElem.setAttribute( QStringLiteral(
"srsName" ),
srsName );
1236 envElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1239 bbElem.appendChild( envElem );
1240 doc.appendChild( bbElem );
1246 if ( !boxElem.isNull() )
1250 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1252 bbElem.appendChild( boxElem );
1253 doc.appendChild( bbElem );
1256 response.
write( doc.toByteArray() );
1267 if ( format == QgsWfsParameters::Format::GeoJSON )
1271 fcString += QLatin1String(
" " );
1273 fcString += QLatin1String(
" ," );
1274 mJsonExporter.setSourceCrs( params.crs );
1275 mJsonExporter.setIncludeGeometry(
false );
1276 mJsonExporter.setIncludeAttributes( !params.attributeIndexes.isEmpty() );
1277 mJsonExporter.setAttributes( params.attributeIndexes );
1278 fcString += createFeatureGeoJSON( feature, params, pkAttributes );
1279 fcString += QLatin1String(
"\n" );
1281 response.
write( fcString.toUtf8() );
1285 QDomDocument gmlDoc;
1286 QDomElement featureElement;
1287 if ( format == QgsWfsParameters::Format::GML3 )
1289 featureElement = createFeatureGML3( feature, gmlDoc, params, project, pkAttributes );
1290 gmlDoc.appendChild( featureElement );
1294 featureElement = createFeatureGML2( feature, gmlDoc, params, project, pkAttributes );
1295 gmlDoc.appendChild( featureElement );
1297 response.
write( gmlDoc.toByteArray() );
1307 if ( format == QgsWfsParameters::Format::GeoJSON )
1309 fcString += QLatin1String(
" ]\n" );
1310 fcString += QLatin1Char(
'}' );
1314 fcString = QStringLiteral(
"</wfs:FeatureCollection>\n" );
1316 response.
write( fcString.toUtf8() );
1320 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes )
1330 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1332 mJsonExporter.setIncludeGeometry(
true );
1333 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1338 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1344 return mJsonExporter.exportFeature( f, QVariantMap(),
id );
1348 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1351 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1354 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1356 typeNameElement.setAttribute( QStringLiteral(
"fid" ),
id );
1357 featureElement.appendChild( typeNameElement );
1361 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1363 int prec = params.precision;
1372 crs = params.outputCrs;
1374 prec = std::min( params.precision + 3, 6 );
1382 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1383 QDomElement gmlElem;
1385 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1389 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1400 gmlElem = abstractGeom->
asGml2( doc, prec,
"http://www.opengis.net/gml" );
1403 if ( !gmlElem.isNull() )
1406 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1411 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1412 gmlElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1415 bbElem.appendChild( boxElem );
1416 typeNameElement.appendChild( bbElem );
1418 geomElem.appendChild( gmlElem );
1419 typeNameElement.appendChild( geomElem );
1426 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1428 int idx = params.attributeIndexes[i];
1429 if ( idx >= fields.
count() )
1437 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1438 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1439 if ( featureAttributes[idx].isNull() )
1441 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1443 fieldElem.appendChild( fieldText );
1444 typeNameElement.appendChild( fieldElem );
1447 return featureElement;
1450 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1453 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1456 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1458 typeNameElement.setAttribute( QStringLiteral(
"gml:id" ),
id );
1459 featureElement.appendChild( typeNameElement );
1463 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1465 int prec = params.precision;
1474 crs = params.outputCrs;
1476 prec = std::min( params.precision + 3, 6 );
1484 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1485 QDomElement gmlElem;
1487 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1491 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1502 gmlElem = abstractGeom->
asGml3( doc, prec,
"http://www.opengis.net/gml", params.hasAxisInverted ? QgsAbstractGeometry::AxisOrder::YX : QgsAbstractGeometry::AxisOrder::XY );
1505 if ( !gmlElem.isNull() )
1508 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1513 boxElem.setAttribute( QStringLiteral(
"srsName" ), params.srsName );
1514 gmlElem.setAttribute( QStringLiteral(
"srsName" ), params.srsName );
1517 bbElem.appendChild( boxElem );
1518 typeNameElement.appendChild( bbElem );
1520 geomElem.appendChild( gmlElem );
1521 typeNameElement.appendChild( geomElem );
1528 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1530 int idx = params.attributeIndexes[i];
1531 if ( idx >= fields.
count() )
1541 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1542 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1543 if ( featureAttributes[idx].isNull() )
1545 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1547 fieldElem.appendChild( fieldText );
1548 typeNameElement.appendChild( fieldElem );
1551 return featureElement;
1556 if ( value.isNull() )
1559 if ( setup.
type() == QStringLiteral(
"DateTime" ) )
1562 const QVariantMap config = setup.
config();
1563 const QString fieldFormat = config.value( QStringLiteral(
"field_format" ), fieldFormatter.
defaultFormat( value.type() ) ).toString();
1564 QDateTime date = value.toDateTime();
1566 if ( date.isValid() )
1568 return date.toString( fieldFormat );
1571 else if ( setup.
type() == QStringLiteral(
"Range" ) )
1573 const QVariantMap config = setup.
config();
1574 if ( config.contains( QStringLiteral(
"Precision" ) ) )
1578 int precision( config[ QStringLiteral(
"Precision" ) ].toInt( &ok ) );
1580 return QString::number( value.toDouble(),
'f',
precision );
1584 switch ( value.type() )
1587 case QVariant::UInt:
1588 case QVariant::LongLong:
1589 case QVariant::ULongLong:
1590 case QVariant::Double:
1591 return value.toString();
1593 case QVariant::Bool:
1594 return value.toBool() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" );
1596 case QVariant::StringList:
1597 case QVariant::List:
1603 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1604 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
1610 case QVariant::String:
1612 QString v = value.toString();
1615 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1616 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
@ 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.
QString authid() const
Returns the authority identifier for the CRS.
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
Fields is 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.
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