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( mRequestParameters.value( QStringLiteral(
"REQUEST_BODY" ) ),
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;
137 for (
int i = 0; i < wfsLayerIds.size(); ++i )
151 if ( typeNameList.contains( name ) )
154 mapLayerMap[name] = layer;
158 requestRect = layer->
extent();
159 requestCrs = layer->
crs();
168 requestRect = transform.transform( layer->
extent() );
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.keys().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() != QStringLiteral(
"*" ) )
257 QStringList::const_iterator plstIt;
260 QList<QString> propertynames;
261 QList<QString> fieldnames;
262 for (
int idx = 0; idx < fields.
count(); ++idx )
264 fieldnames.append( fields[idx].name() );
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 == QStringLiteral(
"geometry" ) )
285 if ( !idxList.isEmpty() )
287 attrIndexes = idxList;
293 if ( !attrIndexes.isEmpty() && !layerExcludedAttributes.isEmpty() )
295 foreach (
const QString &excludedAttribute, layerExcludedAttributes )
297 int fieldNameIdx = fields.
indexOf( excludedAttribute );
298 if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
300 attrIndexes.removeOne( fieldNameIdx );
329 #ifdef HAVE_SERVER_PYTHON_PLUGINS 334 QStringList attributes = QStringList();
335 for (
int idx : attrIndexes )
348 if ( !pkAttributes.isEmpty() )
351 for (
int idx : pkAttributes )
353 if ( !subsetOfAttrs.contains( idx ) )
355 subsetOfAttrs.prepend( idx );
382 geometryName = QLatin1String(
"NONE" );
386 if ( !query.
srsName.isEmpty() )
413 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
417 if ( iteratedFeatures >= aRequest.
startIndex )
426 const createFeatureParams cfp = { layerPrecision,
437 if ( iteratedFeatures == aRequest.
startIndex )
438 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
440 if ( iteratedFeatures >= aRequest.
startIndex )
450 #ifdef HAVE_SERVER_PYTHON_PLUGINS 452 filterRestorer.reset();
455 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
457 hitGetFeature( request, response, project, aRequest.
outputFormat, sentFeatures, typeNameList );
462 if ( iteratedFeatures <= aRequest.
startIndex )
463 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
472 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
473 request.
startIndex = mWfsParameters.startIndexAsInt();
477 QStringList fidList = mWfsParameters.featureIds();
478 bool paramContainsFeatureIds = !fidList.isEmpty();
479 QStringList filterList = mWfsParameters.filters();
480 bool paramContainsFilters = !filterList.isEmpty();
481 QString bbox = mWfsParameters.bbox();
482 bool paramContainsBbox = !bbox.isEmpty();
483 if ( ( paramContainsFeatureIds
484 && ( paramContainsFilters || paramContainsBbox ) )
485 || ( paramContainsFilters
486 && ( paramContainsFeatureIds || paramContainsBbox ) )
487 || ( paramContainsBbox
488 && ( paramContainsFeatureIds || paramContainsFilters ) )
495 QStringList propertyNameList = mWfsParameters.propertyNames();
498 request.
geometryName = mWfsParameters.geometryNameAsString().toUpper();
500 QStringList typeNameList;
502 if ( paramContainsFeatureIds )
505 if ( !propertyNameList.isEmpty() && propertyNameList.size() != fidList.size() )
509 if ( propertyNameList.isEmpty() )
511 for (
int i = 0; i < fidList.size(); ++i )
513 propertyNameList << QStringLiteral(
"*" );
517 QMap<QString, QStringList> fidsMap;
519 QStringList::const_iterator fidIt = fidList.constBegin();
520 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
521 for ( ; fidIt != fidList.constEnd(); ++fidIt )
524 QString fid = *fidIt;
527 QString propertyName;
528 if ( propertyNameIt != propertyNameList.constEnd() )
530 propertyName = *propertyNameIt;
533 if ( !fid.contains(
'.' ) )
538 QString
typeName = fid.section(
'.', 0, 0 );
539 fid = fid.section(
'.', 1, 1 );
540 if ( !typeNameList.contains( typeName ) )
546 QString key = QStringLiteral(
"%1(%2)" ).arg( typeName ).arg( propertyName );
548 if ( fidsMap.contains( key ) )
550 fids = fidsMap.value( key );
553 fidsMap.insert( key, fids );
555 if ( propertyNameIt != propertyNameList.constEnd() )
561 QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
562 while ( fidsMapIt != fidsMap.constEnd() )
564 QString key = fidsMapIt.key();
567 QRegExp rx(
"([^()]+)\\(([^()]+)\\)" );
568 if ( rx.indexIn( key, 0 ) == -1 )
573 QString propertyName = rx.cap( 2 );
577 query.
srsName = mWfsParameters.srsName();
580 if ( propertyName != QStringLiteral(
"*" ) )
582 QStringList propertyList;
584 const QStringList attrList = propertyName.split(
',' );
585 QStringList::const_iterator alstIt;
586 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
588 QString fieldName = *alstIt;
589 fieldName = fieldName.trimmed();
590 if ( fieldName.contains(
':' ) )
592 fieldName = fieldName.section(
':', 1, 1 );
594 if ( fieldName.contains(
'/' ) )
596 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
600 fieldName = fieldName.section(
'/', 1, 1 );
602 propertyList.append( fieldName );
611 request.
queries.append( query );
617 if ( !mRequestParameters.contains( QStringLiteral(
"TYPENAME" ) ) )
622 typeNameList = mWfsParameters.typeNames();
624 if ( !propertyNameList.isEmpty() && typeNameList.size() != propertyNameList.size() )
628 if ( propertyNameList.isEmpty() )
630 for (
int i = 0; i < typeNameList.size(); ++i )
632 propertyNameList << QStringLiteral(
"*" );
637 QStringList::const_iterator typeNameIt = typeNameList.constBegin();
638 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
639 for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
642 typeName = typeName.trimmed();
644 QString propertyName;
645 if ( propertyNameIt != propertyNameList.constEnd() )
647 propertyName = *propertyNameIt;
652 query.
srsName = mWfsParameters.srsName();
655 if ( propertyName != QStringLiteral(
"*" ) )
657 QStringList propertyList;
659 const QStringList attrList = propertyName.split(
',' );
660 QStringList::const_iterator alstIt;
661 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
663 QString fieldName = *alstIt;
664 fieldName = fieldName.trimmed();
665 if ( fieldName.contains(
':' ) )
667 fieldName = fieldName.section(
':', 1, 1 );
669 if ( fieldName.contains(
'/' ) )
671 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
675 fieldName = fieldName.section(
'/', 1, 1 );
677 propertyList.append( fieldName );
682 request.
queries.append( query );
684 if ( propertyNameIt != propertyNameList.constEnd() )
691 QStringList expFilterList = mWfsParameters.expFilters();
692 if ( !expFilterList.isEmpty() )
695 if ( request.
queries.size() == expFilterList.size() )
698 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
699 QStringList::const_iterator expFilterIt = expFilterList.constBegin();
700 for ( ; qIt != request.
queries.end(); ++qIt )
705 if ( expFilterIt != expFilterList.constEnd() )
707 expFilter = *expFilterIt;
709 std::shared_ptr<QgsExpression> filter(
new QgsExpression( expFilter ) );
712 if ( filter->hasParserError() )
716 if ( filter->needsGeometry() )
730 if ( paramContainsBbox )
737 if ( mWfsParameters.bbox().split(
',' ).size() == 5 && ! mWfsParameters.srsName().isEmpty() )
739 QString
crs( mWfsParameters.bbox().split(
',' )[4] );
740 if (
crs != mWfsParameters.srsName() )
744 if ( sourceCrs.
isValid() && destinationCrs.isValid( ) )
752 if ( extentGeom.
transform( transform ) == 0 )
766 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
767 for ( ; qIt != request.
queries.end(); ++qIt )
774 else if ( paramContainsFilters )
777 if ( request.
queries.size() != filterList.size() )
783 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
784 QStringList::const_iterator filterIt = filterList.constBegin();
785 for ( ; qIt != request.
queries.end(); ++qIt )
790 if ( filterIt != filterList.constEnd() )
793 if ( !filter.setContent( *filterIt,
true, &errorMsg ) )
799 QDomElement filterElem = filter.firstChildElement();
800 QStringList serverFids;
804 if ( filterIt != filterList.constEnd() )
812 QStringList sortByList = mWfsParameters.sortBy();
813 if ( !sortByList.isEmpty() && request.
queries.size() == sortByList.size() )
816 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
817 QStringList::const_iterator sortByIt = sortByList.constBegin();
818 for ( ; qIt != request.
queries.end(); ++qIt )
823 if ( sortByIt != sortByList.constEnd() )
827 for (
const QString &attribute : sortBy.split(
',' ) )
829 if ( attribute.endsWith( QLatin1String(
" D" ) ) || attribute.endsWith( QLatin1String(
"+D" ) ) )
833 else if ( attribute.endsWith( QLatin1String(
" DESC" ) ) || attribute.endsWith( QLatin1String(
"+DESC" ) ) )
837 else if ( attribute.endsWith( QLatin1String(
" A" ) ) || attribute.endsWith( QLatin1String(
"+A" ) ) )
841 else if ( attribute.endsWith( QLatin1String(
" ASC" ) ) || attribute.endsWith( QLatin1String(
"+ASC" ) ) )
859 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
860 request.
startIndex = mWfsParameters.startIndexAsInt();
863 QDomNodeList queryNodes = docElem.elementsByTagName( QStringLiteral(
"Query" ) );
864 QDomElement queryElem;
865 for (
int i = 0; i < queryNodes.size(); i++ )
867 queryElem = queryNodes.at( i ).toElement();
869 request.
queries.append( query );
876 QDomNodeList sortByNodes = sortByElem.childNodes();
877 if ( sortByNodes.size() )
879 for (
int i = 0; i < sortByNodes.size(); i++ )
881 QDomElement sortPropElem = sortByNodes.at( i ).toElement();
882 QDomNodeList sortPropChildNodes = sortPropElem.childNodes();
883 if ( sortPropChildNodes.size() )
886 bool ascending =
true;
887 for (
int j = 0; j < sortPropChildNodes.size(); j++ )
889 QDomElement sortPropChildElem = sortPropChildNodes.at( j ).toElement();
890 if ( sortPropChildElem.tagName() == QLatin1String(
"PropertyName" ) )
892 fieldName = sortPropChildElem.text().trimmed();
894 else if ( sortPropChildElem.tagName() == QLatin1String(
"SortOrder" ) )
896 QString sortOrder = sortPropChildElem.text().trimmed().toUpper();
897 if ( sortOrder == QLatin1String(
"DESC" ) || sortOrder == QLatin1String(
"D" ) )
902 if ( fieldName.contains(
':' ) )
904 fieldName = fieldName.section(
':', 1, 1 );
906 if ( fieldName.contains(
'/' ) )
908 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
912 fieldName = fieldName.section(
'/', 1, 1 );
915 if ( !fieldName.isEmpty() )
916 featureRequest.
addOrderBy( fieldName, ascending );
924 QString
typeName = queryElem.attribute( QStringLiteral(
"typeName" ), QString() );
925 if ( typeName.contains(
':' ) )
927 typeName = typeName.section(
':', 1, 1 );
931 QStringList serverFids;
932 QStringList propertyList;
933 QDomNodeList queryChildNodes = queryElem.childNodes();
934 if ( queryChildNodes.size() )
936 QDomElement sortByElem;
937 for (
int q = 0; q < queryChildNodes.size(); q++ )
939 QDomElement queryChildElem = queryChildNodes.at( q ).toElement();
940 if ( queryChildElem.tagName() == QLatin1String(
"PropertyName" ) )
942 QString fieldName = queryChildElem.text().trimmed();
943 if ( fieldName.contains(
':' ) )
945 fieldName = fieldName.section(
':', 1, 1 );
947 if ( fieldName.contains(
'/' ) )
949 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
953 fieldName = fieldName.section(
'/', 1, 1 );
955 propertyList.append( fieldName );
957 else if ( queryChildElem.tagName() == QLatin1String(
"Filter" ) )
961 else if ( queryChildElem.tagName() == QLatin1String(
"SortBy" ) )
963 sortByElem = queryChildElem;
970 QString srsName = queryElem.attribute( QStringLiteral(
"srsName" ), QString() );
983 static QSet< QString > sParamFilter
985 QStringLiteral(
"REQUEST" ),
986 QStringLiteral(
"FORMAT" ),
987 QStringLiteral(
"OUTPUTFORMAT" ),
988 QStringLiteral(
"BBOX" ),
989 QStringLiteral(
"FEATUREID" ),
990 QStringLiteral(
"TYPENAME" ),
991 QStringLiteral(
"FILTER" ),
992 QStringLiteral(
"EXP_FILTER" ),
993 QStringLiteral(
"MAXFEATURES" ),
994 QStringLiteral(
"STARTINDEX" ),
995 QStringLiteral(
"PROPERTYNAME" ),
996 QStringLiteral(
"_DC" )
1001 int numberOfFeatures,
const QStringList &typeNames )
1003 QDateTime now = QDateTime::currentDateTime();
1006 if ( format == QgsWfsParameters::Format::GeoJSON )
1008 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1009 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1010 fcString += QStringLiteral(
" \"timeStamp\": \"%1\"\n" ).arg( now.toString( Qt::ISODate ) );
1011 fcString += QStringLiteral(
" \"numberOfFeatures\": %1\n" ).arg( QString::number( numberOfFeatures ) );
1012 fcString += QLatin1String(
"}" );
1016 if ( format == QgsWfsParameters::Format::GML2 )
1017 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1019 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1022 QString hrefString =
serviceUrl( request, project );
1024 QUrl mapUrl( hrefString );
1026 QUrlQuery query( mapUrl );
1027 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1029 if ( mWfsParameters.version().isEmpty() )
1032 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1034 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1036 for (
auto param : query.queryItems() )
1038 if ( sParamFilter.contains( param.first.toUpper() ) )
1039 query.removeAllQueryItems( param.first );
1042 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1043 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1046 if ( format == QgsWfsParameters::Format::GML2 )
1047 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1049 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1052 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1054 mapUrl.setQuery( query );
1056 hrefString = mapUrl.toString();
1059 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1063 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1064 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1066 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1067 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1068 fcString +=
"\n timeStamp=\"" + now.toString( Qt::ISODate ) +
"\"";
1069 fcString +=
"\n numberOfFeatures=\"" + QString::number( numberOfFeatures ) +
"\"";
1070 fcString += QLatin1String(
">\n" );
1071 fcString += QStringLiteral(
"</wfs:FeatureCollection>" );
1074 response.
write( fcString.toUtf8() );
1083 std::unique_ptr< QgsRectangle > transformedRect;
1085 if ( format == QgsWfsParameters::Format::GeoJSON )
1087 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1097 if ( exportGeom.
transform( transform ) == 0 )
1100 rect = transformedRect.get();
1111 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1113 fcString += QLatin1String(
" \"features\": [\n" );
1114 response.
write( fcString.toUtf8() );
1118 if ( format == QgsWfsParameters::Format::GML2 )
1119 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1121 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1124 QString hrefString =
serviceUrl( request, project );
1126 QUrl mapUrl( hrefString );
1128 QUrlQuery query( mapUrl );
1129 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1131 if ( mWfsParameters.version().isEmpty() )
1134 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1136 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1138 for (
auto param : query.queryItems() )
1140 if ( sParamFilter.contains( param.first.toUpper() ) )
1141 query.removeAllQueryItems( param.first );
1144 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1145 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1148 if ( format == QgsWfsParameters::Format::GML2 )
1149 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1151 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1154 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1156 mapUrl.setQuery( query );
1158 hrefString = mapUrl.toString();
1161 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1165 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1166 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1168 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1169 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1170 fcString += QLatin1String(
">\n" );
1172 response.
write( fcString.toUtf8() );
1176 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1177 if ( format == QgsWfsParameters::Format::GML3 )
1180 if ( !envElem.isNull() )
1184 envElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1186 bbElem.appendChild( envElem );
1187 doc.appendChild( bbElem );
1193 if ( !boxElem.isNull() )
1197 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1199 bbElem.appendChild( boxElem );
1200 doc.appendChild( bbElem );
1203 response.
write( doc.toByteArray() );
1214 if ( format == QgsWfsParameters::Format::GeoJSON )
1218 fcString += QLatin1String(
" " );
1220 fcString += QLatin1String(
" ," );
1221 mJsonExporter.setSourceCrs( params.crs );
1222 mJsonExporter.setIncludeGeometry(
false );
1223 mJsonExporter.setIncludeAttributes( !params.attributeIndexes.isEmpty() );
1224 mJsonExporter.setAttributes( params.attributeIndexes );
1225 fcString += createFeatureGeoJSON( feature, params, pkAttributes );
1226 fcString += QLatin1String(
"\n" );
1228 response.
write( fcString.toUtf8() );
1232 QDomDocument gmlDoc;
1233 QDomElement featureElement;
1234 if ( format == QgsWfsParameters::Format::GML3 )
1236 featureElement = createFeatureGML3( feature, gmlDoc, params, project, pkAttributes );
1237 gmlDoc.appendChild( featureElement );
1241 featureElement = createFeatureGML2( feature, gmlDoc, params, project, pkAttributes );
1242 gmlDoc.appendChild( featureElement );
1244 response.
write( gmlDoc.toByteArray() );
1254 if ( format == QgsWfsParameters::Format::GeoJSON )
1256 fcString += QLatin1String(
" ]\n" );
1257 fcString += QLatin1String(
"}" );
1261 fcString = QStringLiteral(
"</wfs:FeatureCollection>\n" );
1263 response.
write( fcString.toUtf8() );
1267 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes )
1277 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1279 mJsonExporter.setIncludeGeometry(
true );
1280 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1285 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1291 return mJsonExporter.exportFeature( f, QVariantMap(),
id );
1295 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1298 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1301 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1303 typeNameElement.setAttribute( QStringLiteral(
"fid" ),
id );
1304 featureElement.appendChild( typeNameElement );
1308 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1310 int prec = params.precision;
1316 if ( transformed.
transform( mTransform ) == 0 )
1319 crs = params.outputCrs;
1320 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1321 prec = std::min( params.precision + 3, 6 );
1329 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1330 QDomElement gmlElem;
1332 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1336 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1347 gmlElem = abstractGeom->
asGml2( doc, prec,
"http://www.opengis.net/gml" );
1350 if ( !gmlElem.isNull() )
1353 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1358 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1359 gmlElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1362 bbElem.appendChild( boxElem );
1363 typeNameElement.appendChild( bbElem );
1365 geomElem.appendChild( gmlElem );
1366 typeNameElement.appendChild( geomElem );
1373 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1375 int idx = params.attributeIndexes[i];
1376 if ( idx >= fields.
count() )
1382 QString attributeName = field.
name();
1384 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1385 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1386 if ( featureAttributes[idx].isNull() )
1388 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1390 fieldElem.appendChild( fieldText );
1391 typeNameElement.appendChild( fieldElem );
1394 return featureElement;
1397 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1400 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1403 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1405 typeNameElement.setAttribute( QStringLiteral(
"gml:id" ),
id );
1406 featureElement.appendChild( typeNameElement );
1410 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1412 int prec = params.precision;
1418 if ( transformed.
transform( mTransform ) == 0 )
1421 crs = params.outputCrs;
1422 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1423 prec = std::min( params.precision + 3, 6 );
1431 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1432 QDomElement gmlElem;
1434 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1438 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1449 gmlElem = abstractGeom->
asGml3( doc, prec,
"http://www.opengis.net/gml" );
1452 if ( !gmlElem.isNull() )
1455 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1460 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1461 gmlElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1464 bbElem.appendChild( boxElem );
1465 typeNameElement.appendChild( bbElem );
1467 geomElem.appendChild( gmlElem );
1468 typeNameElement.appendChild( geomElem );
1475 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1477 int idx = params.attributeIndexes[i];
1478 if ( idx >= fields.
count() )
1486 QString attributeName = field.
name();
1488 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1489 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1490 if ( featureAttributes[idx].isNull() )
1492 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1494 fieldElem.appendChild( fieldText );
1495 typeNameElement.appendChild( fieldElem );
1498 return featureElement;
1503 if ( value.isNull() )
1506 if ( setup.
type() == QStringLiteral(
"DateTime" ) )
1509 const QVariantMap config = setup.
config();
1510 const QString fieldFormat = config.value( QStringLiteral(
"field_format" ), fieldFormatter.
defaultFormat( value.type() ) ).toString();
1511 QDateTime date = value.toDateTime();
1513 if ( date.isValid() )
1515 return date.toString( fieldFormat );
1518 else if ( setup.
type() == QStringLiteral(
"Range" ) )
1520 const QVariantMap config = setup.
config();
1521 if ( config.contains( QStringLiteral(
"Precision" ) ) )
1525 int precision( config[ QStringLiteral(
"Precision" ) ].toInt( &ok ) );
1527 return QString::number( value.toDouble(),
'f',
precision );
1531 switch ( value.type() )
1534 case QVariant::UInt:
1535 case QVariant::LongLong:
1536 case QVariant::ULongLong:
1537 case QVariant::Double:
1538 return value.toString();
1540 case QVariant::Bool:
1541 return value.toBool() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" );
1543 case QVariant::StringList:
1544 case QVariant::List:
1550 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1551 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
1557 case QVariant::String:
1559 QString v = value.toString();
1562 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1563 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
void writeGetFeature(QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response)
Output WFS GetFeature response.
bool isValid() const
Returns the validity of this feature.
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsStringMap attributeAliases() const
Returns a map of field name to attribute alias.
Wrapper for iterator of features from vector data provider or vector layer.
virtual void setHeader(const QString &key, const QString &value)=0
Set Header entry Add Header entry to the response Note that it is usually an error to set Header afte...
A rectangle specified with double values.
Base class for all map layer types.
QgsFeatureRequest featureRequest
QgsMapLayerType type() const
Returns the type of the layer.
const Flags & flags() const
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
getFeatureRequest parseGetFeatureRequestBody(QDomElement &docElem, const QgsProject *project)
Transform RequestBody root element to getFeatureRequest.
const QString QGS_NAMESPACE
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
QSet< QString > excludeAttributesWfs() const
A set of attributes that are not advertised in WFS requests with QGIS server.
SERVER_EXPORT QString getServerFid(const QgsFeature &feature, const QgsAttributeList &pkAttributes)
Returns the feature id based on primary keys.
Q_INVOKABLE QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
virtual QgsAttributeList pkAttributeIndexes() const
Returns list of indexes of fields that make up the primary key.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Container of fields for a vector layer.
A geometry is the spatial representation of a feature.
QgsFeatureRequest & addOrderBy(const QString &expression, bool ascending=true)
Adds a new OrderByClause, appending it as the least important one.
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
QgsGeometry centroid() const
Returns the center of mass of a geometry.
static QDomElement rectangleToGMLBox(QgsRectangle *box, QDomDocument &doc, int precision=17)
Exports the rectangle to GML2 Box.
virtual QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const =0
Returns a GML2 representation of the geometry.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
const QgsCoordinateReferenceSystem & crs
const QgsAttributeList & attributeIndexes
void parseSortByElement(QDomElement &sortByElem, QgsFeatureRequest &featureRequest, const QString &typeName)
Add SortBy element to featureRequest.
virtual void write(const QString &data)
Write string This is a convenient method that will write directly to the underlying I/O device...
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken.
int count() const
Returns number of items.
QMap< QString, QString > QgsStringMap
QString layerTypeName(const QgsMapLayer *layer)
Returns typename from vector layer.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
static void applyAccessControlLayerFilters(const QgsAccessControl *accessControl, QgsMapLayer *mapLayer, QHash< QgsMapLayer *, QString > &originalLayerFilters)
Apply filter from AccessControl.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
QString serviceUrl(const QgsServerRequest &request, const QgsProject *project)
Service URL string.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
static QString encodeValue(const QVariant &value)
Encodes a value to a JSON string representation, adding appropriate quotations and escaping where req...
const QString & geometryName
bool isEmpty() const
Returns true if the rectangle is empty.
getFeatureQuery parseQueryElement(QDomElement &queryElem, const QgsProject *project)
Transform Query element to getFeatureQuery.
QgsServerRequest::Parameters parameters() const
Returns a map of query parameters with keys converted to uppercase.
A class to describe the version of a project.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QgsWfsParameters::Format outputFormat
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
const QString GML_NAMESPACE
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< getFeatureQuery > queries
const QString WFS_NAMESPACE
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
QgsFeatureRequest parseFilterElement(const QString &typeName, QDomElement &filterElem, const QgsProject *project)
Transform a Filter element to a feature request.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
QString implementationVersion()
Returns the highest version supported by this implementation.
QgsAttributeList attributeList() const
Returns list of attribute indexes.
Format
Output format for the response.
Encapsulate a field in an attribute table or data source.
Abstract base class for all geometries.
SERVER_EXPORT QgsFeatureRequest updateFeatureRequestFromServerFids(QgsFeatureRequest &featureRequest, const QStringList &serverFids, const QgsVectorDataProvider *provider)
Returns the feature request based on feature ids build with primary keys.
SERVER_EXPORT int wfsLayerPrecision(const QgsProject &project, const QString &layerId)
Returns the Layer precision defined in a QGIS project for the WFS GetFeature.
QgsAttributeList subsetOfAttributes() const
Returns the subset of attributes which at least need to be fetched.
Handles exporting QgsFeature features to GeoJSON features.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
const QString OGC_NAMESPACE
double xMaximum() const
Returns the x maximum value (right side of rectangle).
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle...
QgsServerRequest Class defining request interface passed to services QgsService::executeRequest() met...
const QRegExp cleanTagNameRegExp("(?![\\\-]).")
bool layerReadPermission(const QgsMapLayer *layer) const
Returns the layer read right.
QgsServerInterface Class defining interfaces exposed by QGIS Server and made available to plugins...
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
SERVER_EXPORT QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS.
This class represents a coordinate reference system (CRS).
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
static QDomElement rectangleToGMLEnvelope(QgsRectangle *env, QDomDocument &doc, int precision=17)
Exports the rectangle to GML3 Envelope.
const QgsCoordinateReferenceSystem & outputCrs
double xMinimum() const
Returns the x minimum value (left side of rectangle).
RAII class to restore layer filters on destruction.
A helper class that centralizes restrictions given by all the access control filter plugins...
void filterFeatures(const QgsVectorLayer *layer, QgsFeatureRequest &filterFeatures) const override
Filter the features of the layer.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
Exception thrown when data access violates access controls.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsServerResponse Class defining response interface passed to services QgsService::executeRequest() m...
Custom exception class for Coordinate Reference System related exceptions.
virtual QgsAccessControl * accessControls() const =0
Gets the registered access control filters.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
QList< int > QgsAttributeList
getFeatureRequest parseGetFeatureParameters(const QgsProject *project)
Transform parameters to getFeatureRequest.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool nextFeature(QgsFeature &f)
This is the base class for vector data providers.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Represents a vector layer which manages a vector based data sets.
QStringList layerAttributes(const QgsVectorLayer *layer, const QStringList &attributes) const
Returns the authorized layer attributes.
Defines a QGIS exception class.
QgsField field(int fieldIdx) const
Gets field at particular index (must be in range 0..N-1)
Provides an interface to retrieve and manipulate WFS parameters received from the client...
QString authid() const
Returns the authority identifier for the CRS.
QgsCoordinateReferenceSystem crs
virtual QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const =0
Returns a GML3 representation of the geometry.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QMap< QString, QString > Parameters
virtual void flush() SIP_THROW(QgsServerException)
Flushes the current output buffer to the network.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.