47 struct createFeatureParams
66 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes );
70 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
72 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
87 QgsWfsParameters mWfsParameters;
100 mWfsParameters.dump();
106 if ( doc.setContent( request.
data(),
true, &errorMsg ) )
108 QDomElement docElem = doc.documentElement();
117 QStringList typeNameList;
120 bool onlyOneLayer = ( aRequest.
queries.size() == 1 );
123 int requestPrecision = 6;
127 QList<getFeatureQuery>::iterator qIt = aRequest.
queries.begin();
128 for ( ; qIt != aRequest.
queries.end(); ++qIt )
130 typeNameList << ( *qIt ).typeName;
136 QMap<QString, QgsMapLayer *> mapLayerMap;
151 if ( typeNameList.contains( name ) )
154 mapLayerMap[name] = layer;
158 requestRect = layer->
extent();
159 requestCrs = layer->
crs();
178 requestRect =
QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
184 #ifdef HAVE_SERVER_PYTHON_PLUGINS
194 long sentFeatures = 0;
195 long iteratedFeatures = 0;
198 qIt = aRequest.
queries.begin();
199 for ( ; qIt != aRequest.
queries.end(); ++qIt )
204 if ( !mapLayerMap.contains(
typeName ) )
210 #ifdef HAVE_SERVER_PYTHON_PLUGINS
228 #ifdef HAVE_SERVER_PYTHON_PLUGINS
235 QMap< int, QString > layerAliasInfo;
237 QgsStringMap::const_iterator aliasIt = aliasMap.constBegin();
238 for ( ; aliasIt != aliasMap.constEnd(); ++aliasIt )
241 if ( attrIndex != -1 )
243 layerAliasInfo.insert( attrIndex, aliasIt.value() );
254 if ( !propertyList.isEmpty() && propertyList.first() != QLatin1String(
"*" ) )
257 QStringList::const_iterator plstIt;
260 QList<QString> propertynames;
261 QList<QString> fieldnames;
268 for ( plstIt = propertyList.constBegin(); plstIt != propertyList.constEnd(); ++plstIt )
271 int fieldNameIdx = propertynames.indexOf( fieldName );
272 if ( fieldNameIdx == -1 )
274 fieldNameIdx = fieldnames.indexOf( fieldName );
276 if ( fieldNameIdx > -1 )
278 idxList.append( fieldNameIdx );
280 else if ( fieldName == QLatin1String(
"geometry" ) )
285 if ( !idxList.isEmpty() )
287 attrIndexes = idxList;
292 if ( !attrIndexes.isEmpty() )
298 int fieldNameIdx = fields.indexOf(
field.
name() );
299 if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
301 attrIndexes.removeOne( fieldNameIdx );
330 #ifdef HAVE_SERVER_PYTHON_PLUGINS
335 QStringList attributes = QStringList();
336 for (
int idx : qgis::as_const( attrIndexes ) )
349 if ( !pkAttributes.isEmpty() )
352 for (
int idx : pkAttributes )
354 if ( !subsetOfAttrs.contains( idx ) )
356 subsetOfAttrs.prepend( idx );
387 if ( !query.
srsName.isEmpty() )
414 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
418 if ( iteratedFeatures >= aRequest.
startIndex )
427 const createFeatureParams cfp = { layerPrecision,
438 if ( iteratedFeatures == aRequest.
startIndex )
439 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
441 if ( iteratedFeatures >= aRequest.
startIndex )
451 #ifdef HAVE_SERVER_PYTHON_PLUGINS
453 filterRestorer.reset();
456 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
458 hitGetFeature( request, response, project, aRequest.
outputFormat, sentFeatures, typeNameList );
463 if ( iteratedFeatures <= aRequest.
startIndex )
464 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
473 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();
474 request.
startIndex = mWfsParameters.startIndexAsInt();
478 QStringList fidList = mWfsParameters.featureIds();
479 bool paramContainsFeatureIds = !fidList.isEmpty();
480 QStringList filterList = mWfsParameters.filters();
481 bool paramContainsFilters = !filterList.isEmpty();
482 QString bbox = mWfsParameters.bbox();
483 bool paramContainsBbox = !bbox.isEmpty();
484 if ( ( paramContainsFeatureIds
485 && ( paramContainsFilters || paramContainsBbox ) )
486 || ( paramContainsFilters
487 && ( paramContainsFeatureIds || paramContainsBbox ) )
488 || ( paramContainsBbox
489 && ( paramContainsFeatureIds || paramContainsFilters ) )
496 QStringList propertyNameList = mWfsParameters.propertyNames();
499 request.
geometryName = mWfsParameters.geometryNameAsString().toUpper();
501 QStringList typeNameList;
503 if ( paramContainsFeatureIds )
506 if ( !propertyNameList.isEmpty() && propertyNameList.size() != fidList.size() )
510 if ( propertyNameList.isEmpty() )
512 for (
int i = 0; i < fidList.size(); ++i )
514 propertyNameList << QStringLiteral(
"*" );
518 QMap<QString, QStringList> fidsMap;
520 QStringList::const_iterator fidIt = fidList.constBegin();
521 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
522 for ( ; fidIt != fidList.constEnd(); ++fidIt )
525 QString fid = *fidIt;
528 QString propertyName;
529 if ( propertyNameIt != propertyNameList.constEnd() )
531 propertyName = *propertyNameIt;
534 if ( !fid.contains(
'.' ) )
539 QString
typeName = fid.section(
'.', 0, 0 );
540 fid = fid.section(
'.', 1, 1 );
541 if ( !typeNameList.contains(
typeName ) )
547 QString key = QStringLiteral(
"%1(%2)" ).arg(
typeName, propertyName );
549 if ( fidsMap.contains( key ) )
551 fids = fidsMap.value( key );
554 fidsMap.insert( key, fids );
556 if ( propertyNameIt != propertyNameList.constEnd() )
562 QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
563 while ( fidsMapIt != fidsMap.constEnd() )
565 QString key = fidsMapIt.key();
568 QRegExp rx(
"([^()]+)\\(([^()]+)\\)" );
569 if ( rx.indexIn( key, 0 ) == -1 )
574 QString propertyName = rx.cap( 2 );
578 query.
srsName = mWfsParameters.srsName();
581 if ( propertyName != QLatin1String(
"*" ) )
583 QStringList propertyList;
585 const QStringList attrList = propertyName.split(
',' );
586 QStringList::const_iterator alstIt;
587 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
589 QString fieldName = *alstIt;
590 fieldName = fieldName.trimmed();
591 if ( fieldName.contains(
':' ) )
593 fieldName = fieldName.section(
':', 1, 1 );
595 if ( fieldName.contains(
'/' ) )
597 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
601 fieldName = fieldName.section(
'/', 1, 1 );
603 propertyList.append( fieldName );
612 request.
queries.append( query );
618 if ( !mRequestParameters.contains( QStringLiteral(
"TYPENAME" ) ) )
623 typeNameList = mWfsParameters.typeNames();
625 if ( !propertyNameList.isEmpty() && typeNameList.size() != propertyNameList.size() )
629 if ( propertyNameList.isEmpty() )
631 for (
int i = 0; i < typeNameList.size(); ++i )
633 propertyNameList << QStringLiteral(
"*" );
638 QStringList::const_iterator typeNameIt = typeNameList.constBegin();
639 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
640 for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
645 QString propertyName;
646 if ( propertyNameIt != propertyNameList.constEnd() )
648 propertyName = *propertyNameIt;
653 query.
srsName = mWfsParameters.srsName();
656 if ( propertyName != QLatin1String(
"*" ) )
658 QStringList propertyList;
660 const QStringList attrList = propertyName.split(
',' );
661 QStringList::const_iterator alstIt;
662 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
664 QString fieldName = *alstIt;
665 fieldName = fieldName.trimmed();
666 if ( fieldName.contains(
':' ) )
668 fieldName = fieldName.section(
':', 1, 1 );
670 if ( fieldName.contains(
'/' ) )
672 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
676 fieldName = fieldName.section(
'/', 1, 1 );
678 propertyList.append( fieldName );
683 request.
queries.append( query );
685 if ( propertyNameIt != propertyNameList.constEnd() )
692 QStringList expFilterList = mWfsParameters.expFilters();
693 if ( !expFilterList.isEmpty() )
696 if ( request.
queries.size() == expFilterList.size() )
699 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
700 QStringList::const_iterator expFilterIt = expFilterList.constBegin();
701 for ( ; qIt != request.
queries.end(); ++qIt )
706 if ( expFilterIt != expFilterList.constEnd() )
708 expFilter = *expFilterIt;
710 std::shared_ptr<QgsExpression> filter(
new QgsExpression( expFilter ) );
713 if ( filter->hasParserError() )
717 if ( filter->needsGeometry() )
731 if ( paramContainsBbox )
737 QString extentSrsName { mWfsParameters.srsName() };
740 if ( mWfsParameters.bbox().split(
',' ).size() == 5 && ! mWfsParameters.srsName().isEmpty() )
742 QString
crs( mWfsParameters.bbox().split(
',' )[4] );
743 if (
crs != mWfsParameters.srsName() )
756 if ( extentGeom.
transform( transform ) == 0 )
773 if ( extentCrs.
isValid() && extentCrs.
hasAxisInverted() && ! extentSrsName.startsWith( QLatin1String(
"EPSG:" ) ) )
777 extent = geom.boundingBox();
781 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
782 for ( ; qIt != request.
queries.end(); ++qIt )
789 else if ( paramContainsFilters )
792 if ( request.
queries.size() != filterList.size() )
798 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
799 QStringList::const_iterator filterIt = filterList.constBegin();
800 for ( ; qIt != request.
queries.end(); ++qIt )
805 if ( filterIt != filterList.constEnd() )
808 if ( !filter.setContent( *filterIt,
true, &errorMsg ) )
814 QDomElement filterElem = filter.firstChildElement();
815 QStringList serverFids;
819 if ( filterIt != filterList.constEnd() )
827 QStringList sortByList = mWfsParameters.sortBy();
828 if ( !sortByList.isEmpty() && request.
queries.size() == sortByList.size() )
831 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
832 QStringList::const_iterator sortByIt = sortByList.constBegin();
833 for ( ; qIt != request.
queries.end(); ++qIt )
838 if ( sortByIt != sortByList.constEnd() )
842 for (
const QString &attribute : sortBy.split(
',' ) )
844 if ( attribute.endsWith( QLatin1String(
" D" ) ) || attribute.endsWith( QLatin1String(
"+D" ) ) )
848 else if ( attribute.endsWith( QLatin1String(
" DESC" ) ) || attribute.endsWith( QLatin1String(
"+DESC" ) ) )
852 else if ( attribute.endsWith( QLatin1String(
" A" ) ) || attribute.endsWith( QLatin1String(
"+A" ) ) )
856 else if ( attribute.endsWith( QLatin1String(
" ASC" ) ) || attribute.endsWith( QLatin1String(
"+ASC" ) ) )
874 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();
875 request.
startIndex = mWfsParameters.startIndexAsInt();
878 QDomNodeList queryNodes = docElem.elementsByTagName( QStringLiteral(
"Query" ) );
879 QDomElement queryElem;
880 for (
int i = 0; i < queryNodes.size(); i++ )
882 queryElem = queryNodes.at( i ).toElement();
884 request.
queries.append( query );
891 QDomNodeList sortByNodes = sortByElem.childNodes();
892 if ( sortByNodes.size() )
894 for (
int i = 0; i < sortByNodes.size(); i++ )
896 QDomElement sortPropElem = sortByNodes.at( i ).toElement();
897 QDomNodeList sortPropChildNodes = sortPropElem.childNodes();
898 if ( sortPropChildNodes.size() )
901 bool ascending =
true;
902 for (
int j = 0; j < sortPropChildNodes.size(); j++ )
904 QDomElement sortPropChildElem = sortPropChildNodes.at( j ).toElement();
905 if ( sortPropChildElem.tagName() == QLatin1String(
"PropertyName" ) )
907 fieldName = sortPropChildElem.text().trimmed();
909 else if ( sortPropChildElem.tagName() == QLatin1String(
"SortOrder" ) )
911 QString sortOrder = sortPropChildElem.text().trimmed().toUpper();
912 if ( sortOrder == QLatin1String(
"DESC" ) || sortOrder == QLatin1String(
"D" ) )
917 if ( fieldName.contains(
':' ) )
919 fieldName = fieldName.section(
':', 1, 1 );
921 if ( fieldName.contains(
'/' ) )
923 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
927 fieldName = fieldName.section(
'/', 1, 1 );
930 if ( !fieldName.isEmpty() )
931 featureRequest.
addOrderBy( fieldName, ascending );
939 QString
typeName = queryElem.attribute( QStringLiteral(
"typeName" ), QString() );
946 QStringList serverFids;
947 QStringList propertyList;
948 QDomNodeList queryChildNodes = queryElem.childNodes();
949 if ( queryChildNodes.size() )
951 QDomElement sortByElem;
952 for (
int q = 0; q < queryChildNodes.size(); q++ )
954 QDomElement queryChildElem = queryChildNodes.at( q ).toElement();
955 if ( queryChildElem.tagName() == QLatin1String(
"PropertyName" ) )
957 QString fieldName = queryChildElem.text().trimmed();
958 if ( fieldName.contains(
':' ) )
960 fieldName = fieldName.section(
':', 1, 1 );
962 if ( fieldName.contains(
'/' ) )
964 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
968 fieldName = fieldName.section(
'/', 1, 1 );
970 propertyList.append( fieldName );
972 else if ( queryChildElem.tagName() == QLatin1String(
"Filter" ) )
976 else if ( queryChildElem.tagName() == QLatin1String(
"SortBy" ) )
978 sortByElem = queryChildElem;
985 QString srsName = queryElem.attribute( QStringLiteral(
"srsName" ), QString() );
998 static QSet< QString > sParamFilter
1000 QStringLiteral(
"REQUEST" ),
1001 QStringLiteral(
"FORMAT" ),
1002 QStringLiteral(
"OUTPUTFORMAT" ),
1003 QStringLiteral(
"BBOX" ),
1004 QStringLiteral(
"FEATUREID" ),
1005 QStringLiteral(
"TYPENAME" ),
1006 QStringLiteral(
"FILTER" ),
1007 QStringLiteral(
"EXP_FILTER" ),
1008 QStringLiteral(
"MAXFEATURES" ),
1009 QStringLiteral(
"STARTINDEX" ),
1010 QStringLiteral(
"PROPERTYNAME" ),
1011 QStringLiteral(
"_DC" )
1016 int numberOfFeatures,
const QStringList &typeNames )
1018 QDateTime now = QDateTime::currentDateTime();
1021 if ( format == QgsWfsParameters::Format::GeoJSON )
1023 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1024 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1025 fcString += QStringLiteral(
" \"timeStamp\": \"%1\"\n" ).arg( now.toString( Qt::ISODate ) );
1026 fcString += QStringLiteral(
" \"numberOfFeatures\": %1\n" ).arg( QString::number( numberOfFeatures ) );
1027 fcString += QLatin1Char(
'}' );
1031 if ( format == QgsWfsParameters::Format::GML2 )
1032 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1034 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1037 QString hrefString =
serviceUrl( request, project );
1039 QUrl mapUrl( hrefString );
1041 QUrlQuery query( mapUrl );
1042 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1044 if ( mWfsParameters.version().isEmpty() )
1047 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1049 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1051 for (
auto param : query.queryItems() )
1053 if ( sParamFilter.contains( param.first.toUpper() ) )
1054 query.removeAllQueryItems( param.first );
1057 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1058 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1061 if ( format == QgsWfsParameters::Format::GML2 )
1062 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1064 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1067 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1069 mapUrl.setQuery( query );
1071 hrefString = mapUrl.toString();
1074 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1078 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1079 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1081 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1082 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1083 fcString +=
"\n timeStamp=\"" + now.toString( Qt::ISODate ) +
"\"";
1084 fcString +=
"\n numberOfFeatures=\"" + QString::number( numberOfFeatures ) +
"\"";
1085 fcString += QLatin1String(
">\n" );
1086 fcString += QLatin1String(
"</wfs:FeatureCollection>" );
1089 response.
write( fcString.toUtf8() );
1098 std::unique_ptr< QgsRectangle > transformedRect;
1100 if ( format == QgsWfsParameters::Format::GeoJSON )
1102 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1112 if ( exportGeom.
transform( transform ) == 0 )
1115 rect = transformedRect.get();
1126 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1128 fcString += QLatin1String(
" \"features\": [\n" );
1129 response.
write( fcString.toUtf8() );
1133 if ( format == QgsWfsParameters::Format::GML2 )
1134 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1136 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1139 QString hrefString =
serviceUrl( request, project );
1141 QUrl mapUrl( hrefString );
1143 QUrlQuery query( mapUrl );
1144 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1146 if ( mWfsParameters.version().isEmpty() )
1149 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1151 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1153 for (
auto param : query.queryItems() )
1155 if ( sParamFilter.contains( param.first.toUpper() ) )
1156 query.removeAllQueryItems( param.first );
1159 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1160 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1163 if ( format == QgsWfsParameters::Format::GML2 )
1164 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1166 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1169 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1171 mapUrl.setQuery( query );
1173 hrefString = mapUrl.toString();
1176 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1180 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1181 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1183 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1184 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1185 fcString += QLatin1String(
">\n" );
1187 response.
write( fcString.toUtf8() );
1191 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1192 if ( format == QgsWfsParameters::Format::GML3 )
1195 if ( !envElem.isNull() )
1199 envElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1201 bbElem.appendChild( envElem );
1202 doc.appendChild( bbElem );
1208 if ( !boxElem.isNull() )
1212 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1214 bbElem.appendChild( boxElem );
1215 doc.appendChild( bbElem );
1218 response.
write( doc.toByteArray() );
1229 if ( format == QgsWfsParameters::Format::GeoJSON )
1233 fcString += QLatin1String(
" " );
1235 fcString += QLatin1String(
" ," );
1236 mJsonExporter.setSourceCrs( params.crs );
1237 mJsonExporter.setIncludeGeometry(
false );
1238 mJsonExporter.setIncludeAttributes( !params.attributeIndexes.isEmpty() );
1239 mJsonExporter.setAttributes( params.attributeIndexes );
1240 fcString += createFeatureGeoJSON( feature, params, pkAttributes );
1241 fcString += QLatin1String(
"\n" );
1243 response.
write( fcString.toUtf8() );
1247 QDomDocument gmlDoc;
1248 QDomElement featureElement;
1249 if ( format == QgsWfsParameters::Format::GML3 )
1251 featureElement = createFeatureGML3( feature, gmlDoc, params, project, pkAttributes );
1252 gmlDoc.appendChild( featureElement );
1256 featureElement = createFeatureGML2( feature, gmlDoc, params, project, pkAttributes );
1257 gmlDoc.appendChild( featureElement );
1259 response.
write( gmlDoc.toByteArray() );
1269 if ( format == QgsWfsParameters::Format::GeoJSON )
1271 fcString += QLatin1String(
" ]\n" );
1272 fcString += QLatin1Char(
'}' );
1276 fcString = QStringLiteral(
"</wfs:FeatureCollection>\n" );
1278 response.
write( fcString.toUtf8() );
1282 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes )
1292 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1294 mJsonExporter.setIncludeGeometry(
true );
1295 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1300 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1306 return mJsonExporter.exportFeature( f, QVariantMap(),
id );
1310 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1313 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1316 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1318 typeNameElement.setAttribute( QStringLiteral(
"fid" ),
id );
1319 featureElement.appendChild( typeNameElement );
1323 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1325 int prec = params.precision;
1331 if ( transformed.
transform( mTransform ) == 0 )
1334 crs = params.outputCrs;
1336 prec = std::min( params.precision + 3, 6 );
1344 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1345 QDomElement gmlElem;
1347 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1351 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1362 gmlElem = abstractGeom->
asGml2( doc, prec,
"http://www.opengis.net/gml" );
1365 if ( !gmlElem.isNull() )
1368 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1373 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1374 gmlElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1377 bbElem.appendChild( boxElem );
1378 typeNameElement.appendChild( bbElem );
1380 geomElem.appendChild( gmlElem );
1381 typeNameElement.appendChild( geomElem );
1388 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1390 int idx = params.attributeIndexes[i];
1391 if ( idx >= fields.
count() )
1399 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1400 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1401 if ( featureAttributes[idx].isNull() )
1403 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1405 fieldElem.appendChild( fieldText );
1406 typeNameElement.appendChild( fieldElem );
1409 return featureElement;
1412 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1415 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1418 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1420 typeNameElement.setAttribute( QStringLiteral(
"gml:id" ),
id );
1421 featureElement.appendChild( typeNameElement );
1425 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1427 int prec = params.precision;
1433 if ( transformed.
transform( mTransform ) == 0 )
1436 crs = params.outputCrs;
1438 prec = std::min( params.precision + 3, 6 );
1446 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1447 QDomElement gmlElem;
1449 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1453 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1464 gmlElem = abstractGeom->
asGml3( doc, prec,
"http://www.opengis.net/gml" );
1467 if ( !gmlElem.isNull() )
1470 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1475 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1476 gmlElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1479 bbElem.appendChild( boxElem );
1480 typeNameElement.appendChild( bbElem );
1482 geomElem.appendChild( gmlElem );
1483 typeNameElement.appendChild( geomElem );
1490 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1492 int idx = params.attributeIndexes[i];
1493 if ( idx >= fields.
count() )
1503 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1504 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1505 if ( featureAttributes[idx].isNull() )
1507 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1509 fieldElem.appendChild( fieldText );
1510 typeNameElement.appendChild( fieldElem );
1513 return featureElement;
1518 if ( value.isNull() )
1521 if ( setup.
type() == QStringLiteral(
"DateTime" ) )
1524 const QVariantMap config = setup.
config();
1525 const QString fieldFormat = config.value( QStringLiteral(
"field_format" ), fieldFormatter.
defaultFormat( value.type() ) ).toString();
1526 QDateTime date = value.toDateTime();
1528 if ( date.isValid() )
1530 return date.toString( fieldFormat );
1533 else if ( setup.
type() == QStringLiteral(
"Range" ) )
1535 const QVariantMap config = setup.
config();
1536 if ( config.contains( QStringLiteral(
"Precision" ) ) )
1540 int precision( config[ QStringLiteral(
"Precision" ) ].toInt( &ok ) );
1542 return QString::number( value.toDouble(),
'f',
precision );
1546 switch ( value.type() )
1549 case QVariant::UInt:
1550 case QVariant::LongLong:
1551 case QVariant::ULongLong:
1552 case QVariant::Double:
1553 return value.toString();
1555 case QVariant::Bool:
1556 return value.toBool() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" );
1558 case QVariant::StringList:
1559 case QVariant::List:
1565 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1566 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
1572 case QVariant::String:
1574 QString v = value.toString();
1577 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1578 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
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 & 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.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
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.
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken.
const Flags & flags() const
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
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
Gets field at particular index (must be in range 0..N-1)
QgsField at(int i) const
Gets 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.)
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.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
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 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::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.
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
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...
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.
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.
QString serviceUrl(const QgsServerRequest &request, const QgsProject *project)
Service URL string.
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