46 struct createFeatureParams
63 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes );
67 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
69 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
84 QgsWfsParameters mWfsParameters;
97 mWfsParameters.dump();
103 if ( doc.setContent( mRequestParameters.value( QStringLiteral(
"REQUEST_BODY" ) ),
true, &errorMsg ) )
105 QDomElement docElem = doc.documentElement();
114 QStringList typeNameList;
117 bool onlyOneLayer = ( aRequest.
queries.size() == 1 );
120 int requestPrecision = 6;
124 QList<getFeatureQuery>::iterator qIt = aRequest.
queries.begin();
125 for ( ; qIt != aRequest.
queries.end(); ++qIt )
127 typeNameList << ( *qIt ).typeName;
133 QMap<QString, QgsMapLayer *> mapLayerMap;
134 for (
int i = 0; i < wfsLayerIds.size(); ++i )
148 if ( typeNameList.contains( name ) )
151 mapLayerMap[name] = layer;
155 requestRect = layer->
extent();
156 requestCrs = layer->
crs();
165 requestRect = transform.transform( layer->
extent() );
175 requestRect =
QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
181 #ifdef HAVE_SERVER_PYTHON_PLUGINS 191 long sentFeatures = 0;
192 long iteratedFeatures = 0;
195 qIt = aRequest.
queries.begin();
196 for ( ; qIt != aRequest.
queries.end(); ++qIt )
201 if ( !mapLayerMap.keys().contains( typeName ) )
207 #ifdef HAVE_SERVER_PYTHON_PLUGINS 225 #ifdef HAVE_SERVER_PYTHON_PLUGINS 232 QMap< int, QString > layerAliasInfo;
234 QgsStringMap::const_iterator aliasIt = aliasMap.constBegin();
235 for ( ; aliasIt != aliasMap.constEnd(); ++aliasIt )
238 if ( attrIndex != -1 )
240 layerAliasInfo.insert( attrIndex, aliasIt.value() );
251 if ( !propertyList.isEmpty() && propertyList.first() != QStringLiteral(
"*" ) )
254 QStringList::const_iterator plstIt;
257 QList<QString> propertynames;
258 QList<QString> fieldnames;
259 for (
int idx = 0; idx < fields.
count(); ++idx )
261 fieldnames.append( fields[idx].name() );
265 for ( plstIt = propertyList.constBegin(); plstIt != propertyList.constEnd(); ++plstIt )
268 int fieldNameIdx = propertynames.indexOf( fieldName );
269 if ( fieldNameIdx == -1 )
271 fieldNameIdx = fieldnames.indexOf( fieldName );
273 if ( fieldNameIdx > -1 )
275 idxList.append( fieldNameIdx );
277 else if ( fieldName == QStringLiteral(
"geometry" ) )
282 if ( !idxList.isEmpty() )
284 attrIndexes = idxList;
290 if ( !attrIndexes.isEmpty() && !layerExcludedAttributes.isEmpty() )
292 foreach (
const QString &excludedAttribute, layerExcludedAttributes )
294 int fieldNameIdx = fields.
indexOf( excludedAttribute );
295 if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
297 attrIndexes.removeOne( fieldNameIdx );
325 #ifdef HAVE_SERVER_PYTHON_PLUGINS 330 QStringList attributes = QStringList();
331 for (
int idx : attrIndexes )
358 geometryName = QLatin1String(
"NONE" );
362 if ( !query.
srsName.isEmpty() )
387 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
391 if ( iteratedFeatures >= aRequest.
startIndex )
400 const createFeatureParams cfp = { layerPrecision,
410 if ( iteratedFeatures == aRequest.
startIndex )
411 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
413 if ( iteratedFeatures >= aRequest.
startIndex )
423 #ifdef HAVE_SERVER_PYTHON_PLUGINS 425 filterRestorer.reset();
428 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
430 hitGetFeature( request, response, project, aRequest.
outputFormat, sentFeatures, typeNameList );
435 if ( iteratedFeatures <= aRequest.
startIndex )
436 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
445 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
446 request.
startIndex = mWfsParameters.startIndexAsInt();
450 QStringList fidList = mWfsParameters.featureIds();
451 bool paramContainsFeatureIds = !fidList.isEmpty();
452 QStringList filterList = mWfsParameters.filters();
453 bool paramContainsFilters = !filterList.isEmpty();
454 QString bbox = mWfsParameters.bbox();
455 bool paramContainsBbox = !bbox.isEmpty();
456 if ( ( paramContainsFeatureIds
457 && ( paramContainsFilters || paramContainsBbox ) )
458 || ( paramContainsFilters
459 && ( paramContainsFeatureIds || paramContainsBbox ) )
460 || ( paramContainsBbox
461 && ( paramContainsFeatureIds || paramContainsFilters ) )
468 QStringList propertyNameList = mWfsParameters.propertyNames();
471 request.
geometryName = mWfsParameters.geometryNameAsString().toUpper();
473 QStringList typeNameList;
475 if ( paramContainsFeatureIds )
478 if ( !propertyNameList.isEmpty() && propertyNameList.size() != fidList.size() )
482 if ( propertyNameList.isEmpty() )
484 for (
int i = 0; i < fidList.size(); ++i )
486 propertyNameList << QStringLiteral(
"*" );
490 QMap<QString, QStringList> fidsMap;
492 QStringList::const_iterator fidIt = fidList.constBegin();
493 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
494 for ( ; fidIt != fidList.constEnd(); ++fidIt )
497 QString fid = *fidIt;
500 QString propertyName;
501 if ( propertyNameIt != propertyNameList.constEnd() )
503 propertyName = *propertyNameIt;
506 if ( !fid.contains(
'.' ) )
511 QString
typeName = fid.section(
'.', 0, 0 );
512 fid = fid.section(
'.', 1, 1 );
513 if ( !typeNameList.contains( typeName ) )
519 QString key = QStringLiteral(
"%1(%2)" ).arg( typeName ).arg( propertyName );
521 if ( fidsMap.contains( key ) )
523 fids = fidsMap.value( key );
526 fidsMap.insert( key, fids );
528 if ( propertyNameIt != propertyNameList.constEnd() )
534 QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
535 while ( fidsMapIt != fidsMap.constEnd() )
537 QString key = fidsMapIt.key();
540 QRegExp rx(
"([^()]+)\\(([^()]+)\\)" );
541 if ( rx.indexIn( key, 0 ) == -1 )
546 QString propertyName = rx.cap( 2 );
550 query.
srsName = mWfsParameters.srsName();
553 if ( propertyName != QStringLiteral(
"*" ) )
555 QStringList propertyList;
557 const QStringList attrList = propertyName.split(
',' );
558 QStringList::const_iterator alstIt;
559 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
561 QString fieldName = *alstIt;
562 fieldName = fieldName.trimmed();
563 if ( fieldName.contains(
':' ) )
565 fieldName = fieldName.section(
':', 1, 1 );
567 if ( fieldName.contains(
'/' ) )
569 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
573 fieldName = fieldName.section(
'/', 1, 1 );
575 propertyList.append( fieldName );
584 request.
queries.append( query );
590 if ( !mRequestParameters.contains( QStringLiteral(
"TYPENAME" ) ) )
595 typeNameList = mWfsParameters.typeNames();
597 if ( !propertyNameList.isEmpty() && typeNameList.size() != propertyNameList.size() )
601 if ( propertyNameList.isEmpty() )
603 for (
int i = 0; i < typeNameList.size(); ++i )
605 propertyNameList << QStringLiteral(
"*" );
610 QStringList::const_iterator typeNameIt = typeNameList.constBegin();
611 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
612 for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
615 typeName = typeName.trimmed();
617 QString propertyName;
618 if ( propertyNameIt != propertyNameList.constEnd() )
620 propertyName = *propertyNameIt;
625 query.
srsName = mWfsParameters.srsName();
628 if ( propertyName != QStringLiteral(
"*" ) )
630 QStringList propertyList;
632 const QStringList attrList = propertyName.split(
',' );
633 QStringList::const_iterator alstIt;
634 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
636 QString fieldName = *alstIt;
637 fieldName = fieldName.trimmed();
638 if ( fieldName.contains(
':' ) )
640 fieldName = fieldName.section(
':', 1, 1 );
642 if ( fieldName.contains(
'/' ) )
644 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
648 fieldName = fieldName.section(
'/', 1, 1 );
650 propertyList.append( fieldName );
655 request.
queries.append( query );
657 if ( propertyNameIt != propertyNameList.constEnd() )
664 QStringList expFilterList = mWfsParameters.expFilters();
665 if ( !expFilterList.isEmpty() )
668 if ( request.
queries.size() == expFilterList.size() )
671 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
672 QStringList::const_iterator expFilterIt = expFilterList.constBegin();
673 for ( ; qIt != request.
queries.end(); ++qIt )
678 if ( expFilterIt != expFilterList.constEnd() )
680 expFilter = *expFilterIt;
682 std::shared_ptr<QgsExpression> filter(
new QgsExpression( expFilter ) );
685 if ( filter->hasParserError() )
689 if ( filter->needsGeometry() )
703 if ( paramContainsBbox )
710 if ( mWfsParameters.bbox().split(
',' ).size() == 5 && ! mWfsParameters.srsName().isEmpty() )
712 QString
crs( mWfsParameters.bbox().split(
',' )[4] );
713 if (
crs != mWfsParameters.srsName() )
717 if ( sourceCrs.
isValid() && destinationCrs.isValid( ) )
725 if ( extentGeom.
transform( transform ) == 0 )
739 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
740 for ( ; qIt != request.
queries.end(); ++qIt )
747 else if ( paramContainsFilters )
750 if ( request.
queries.size() != filterList.size() )
756 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
757 QStringList::const_iterator filterIt = filterList.constBegin();
758 for ( ; qIt != request.
queries.end(); ++qIt )
763 if ( filterIt != filterList.constEnd() )
766 if ( !filter.setContent( *filterIt,
true, &errorMsg ) )
772 QDomElement filterElem = filter.firstChildElement();
773 QStringList serverFids;
777 if ( filterIt != filterList.constEnd() )
785 QStringList sortByList = mWfsParameters.sortBy();
786 if ( !sortByList.isEmpty() && request.
queries.size() == sortByList.size() )
789 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
790 QStringList::const_iterator sortByIt = sortByList.constBegin();
791 for ( ; qIt != request.
queries.end(); ++qIt )
796 if ( sortByIt != sortByList.constEnd() )
800 for (
const QString &attribute : sortBy.split(
',' ) )
802 if ( attribute.endsWith( QLatin1String(
" D" ) ) || attribute.endsWith( QLatin1String(
"+D" ) ) )
806 else if ( attribute.endsWith( QLatin1String(
" DESC" ) ) || attribute.endsWith( QLatin1String(
"+DESC" ) ) )
810 else if ( attribute.endsWith( QLatin1String(
" A" ) ) || attribute.endsWith( QLatin1String(
"+A" ) ) )
814 else if ( attribute.endsWith( QLatin1String(
" ASC" ) ) || attribute.endsWith( QLatin1String(
"+ASC" ) ) )
832 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
833 request.
startIndex = mWfsParameters.startIndexAsInt();
836 QDomNodeList queryNodes = docElem.elementsByTagName( QStringLiteral(
"Query" ) );
837 QDomElement queryElem;
838 for (
int i = 0; i < queryNodes.size(); i++ )
840 queryElem = queryNodes.at( i ).toElement();
842 request.
queries.append( query );
849 QDomNodeList sortByNodes = sortByElem.childNodes();
850 if ( sortByNodes.size() )
852 for (
int i = 0; i < sortByNodes.size(); i++ )
854 QDomElement sortPropElem = sortByNodes.at( i ).toElement();
855 QDomNodeList sortPropChildNodes = sortPropElem.childNodes();
856 if ( sortPropChildNodes.size() )
859 bool ascending =
true;
860 for (
int j = 0; j < sortPropChildNodes.size(); j++ )
862 QDomElement sortPropChildElem = sortPropChildNodes.at( j ).toElement();
863 if ( sortPropChildElem.tagName() == QLatin1String(
"PropertyName" ) )
865 fieldName = sortPropChildElem.text().trimmed();
867 else if ( sortPropChildElem.tagName() == QLatin1String(
"SortOrder" ) )
869 QString sortOrder = sortPropChildElem.text().trimmed().toUpper();
870 if ( sortOrder == QLatin1String(
"DESC" ) || sortOrder == QLatin1String(
"D" ) )
875 if ( fieldName.contains(
':' ) )
877 fieldName = fieldName.section(
':', 1, 1 );
879 if ( fieldName.contains(
'/' ) )
881 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
885 fieldName = fieldName.section(
'/', 1, 1 );
888 if ( !fieldName.isEmpty() )
889 featureRequest.
addOrderBy( fieldName, ascending );
897 QString
typeName = queryElem.attribute( QStringLiteral(
"typeName" ), QString() );
898 if ( typeName.contains(
':' ) )
900 typeName = typeName.section(
':', 1, 1 );
904 QStringList serverFids;
905 QStringList propertyList;
906 QDomNodeList queryChildNodes = queryElem.childNodes();
907 if ( queryChildNodes.size() )
909 QDomElement sortByElem;
910 for (
int q = 0; q < queryChildNodes.size(); q++ )
912 QDomElement queryChildElem = queryChildNodes.at( q ).toElement();
913 if ( queryChildElem.tagName() == QLatin1String(
"PropertyName" ) )
915 QString fieldName = queryChildElem.text().trimmed();
916 if ( fieldName.contains(
':' ) )
918 fieldName = fieldName.section(
':', 1, 1 );
920 if ( fieldName.contains(
'/' ) )
922 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
926 fieldName = fieldName.section(
'/', 1, 1 );
928 propertyList.append( fieldName );
930 else if ( queryChildElem.tagName() == QLatin1String(
"Filter" ) )
934 else if ( queryChildElem.tagName() == QLatin1String(
"SortBy" ) )
936 sortByElem = queryChildElem;
943 QString srsName = queryElem.attribute( QStringLiteral(
"srsName" ), QString() );
956 static QSet< QString > sParamFilter
958 QStringLiteral(
"REQUEST" ),
959 QStringLiteral(
"FORMAT" ),
960 QStringLiteral(
"OUTPUTFORMAT" ),
961 QStringLiteral(
"BBOX" ),
962 QStringLiteral(
"FEATUREID" ),
963 QStringLiteral(
"TYPENAME" ),
964 QStringLiteral(
"FILTER" ),
965 QStringLiteral(
"EXP_FILTER" ),
966 QStringLiteral(
"MAXFEATURES" ),
967 QStringLiteral(
"STARTINDEX" ),
968 QStringLiteral(
"PROPERTYNAME" ),
969 QStringLiteral(
"_DC" )
974 int numberOfFeatures,
const QStringList &typeNames )
976 QDateTime now = QDateTime::currentDateTime();
979 if ( format == QgsWfsParameters::Format::GeoJSON )
981 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
982 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
983 fcString += QStringLiteral(
" \"timeStamp\": \"%1\"\n" ).arg( now.toString( Qt::ISODate ) );
984 fcString += QStringLiteral(
" \"numberOfFeatures\": %1\n" ).arg( QString::number( numberOfFeatures ) );
985 fcString += QLatin1String(
"}" );
989 if ( format == QgsWfsParameters::Format::GML2 )
990 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
992 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
995 QString hrefString =
serviceUrl( request, project );
997 QUrl mapUrl( hrefString );
999 QUrlQuery query( mapUrl );
1000 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1002 if ( mWfsParameters.version().isEmpty() )
1005 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1007 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1009 for (
auto param : query.queryItems() )
1011 if ( sParamFilter.contains( param.first.toUpper() ) )
1012 query.removeAllQueryItems( param.first );
1015 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1016 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1019 if ( format == QgsWfsParameters::Format::GML2 )
1020 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1022 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1025 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1027 mapUrl.setQuery( query );
1029 hrefString = mapUrl.toString();
1032 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1036 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1037 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1039 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1040 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1041 fcString +=
"\n timeStamp=\"" + now.toString( Qt::ISODate ) +
"\"";
1042 fcString +=
"\n numberOfFeatures=\"" + QString::number( numberOfFeatures ) +
"\"";
1043 fcString += QLatin1String(
">\n" );
1044 fcString += QStringLiteral(
"</wfs:FeatureCollection>" );
1047 response.
write( fcString.toUtf8() );
1056 std::unique_ptr< QgsRectangle > transformedRect;
1058 if ( format == QgsWfsParameters::Format::GeoJSON )
1060 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1070 if ( exportGeom.
transform( transform ) == 0 )
1073 rect = transformedRect.get();
1084 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1086 fcString += QLatin1String(
" \"features\": [\n" );
1087 response.
write( fcString.toUtf8() );
1091 if ( format == QgsWfsParameters::Format::GML2 )
1092 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1094 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1097 QString hrefString =
serviceUrl( request, project );
1099 QUrl mapUrl( hrefString );
1101 QUrlQuery query( mapUrl );
1102 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1104 if ( mWfsParameters.version().isEmpty() )
1107 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1109 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1111 for (
auto param : query.queryItems() )
1113 if ( sParamFilter.contains( param.first.toUpper() ) )
1114 query.removeAllQueryItems( param.first );
1117 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1118 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1121 if ( format == QgsWfsParameters::Format::GML2 )
1122 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1124 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1127 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1129 mapUrl.setQuery( query );
1131 hrefString = mapUrl.toString();
1134 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1138 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1139 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1141 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1142 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1143 fcString += QLatin1String(
">\n" );
1145 response.
write( fcString.toUtf8() );
1149 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1150 if ( format == QgsWfsParameters::Format::GML3 )
1153 if ( !envElem.isNull() )
1157 envElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1159 bbElem.appendChild( envElem );
1160 doc.appendChild( bbElem );
1166 if ( !boxElem.isNull() )
1170 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1172 bbElem.appendChild( boxElem );
1173 doc.appendChild( bbElem );
1176 response.
write( doc.toByteArray() );
1187 if ( format == QgsWfsParameters::Format::GeoJSON )
1191 fcString += QLatin1String(
" " );
1193 fcString += QLatin1String(
" ," );
1194 mJsonExporter.setSourceCrs( params.crs );
1195 mJsonExporter.setIncludeGeometry(
false );
1196 mJsonExporter.setIncludeAttributes( !params.attributeIndexes.isEmpty() );
1197 mJsonExporter.setAttributes( params.attributeIndexes );
1198 fcString += createFeatureGeoJSON( feature, params, pkAttributes );
1199 fcString += QLatin1String(
"\n" );
1201 response.
write( fcString.toUtf8() );
1205 QDomDocument gmlDoc;
1206 QDomElement featureElement;
1207 if ( format == QgsWfsParameters::Format::GML3 )
1209 featureElement = createFeatureGML3( feature, gmlDoc, params, project, pkAttributes );
1210 gmlDoc.appendChild( featureElement );
1214 featureElement = createFeatureGML2( feature, gmlDoc, params, project, pkAttributes );
1215 gmlDoc.appendChild( featureElement );
1217 response.
write( gmlDoc.toByteArray() );
1227 if ( format == QgsWfsParameters::Format::GeoJSON )
1229 fcString += QLatin1String(
" ]\n" );
1230 fcString += QLatin1String(
"}" );
1234 fcString = QStringLiteral(
"</wfs:FeatureCollection>\n" );
1236 response.
write( fcString.toUtf8() );
1240 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes )
1250 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1252 mJsonExporter.setIncludeGeometry(
true );
1253 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1258 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1264 return mJsonExporter.exportFeature( f, QVariantMap(),
id );
1268 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1271 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1274 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1276 typeNameElement.setAttribute( QStringLiteral(
"fid" ),
id );
1277 featureElement.appendChild( typeNameElement );
1281 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1283 int prec = params.precision;
1289 if ( transformed.
transform( mTransform ) == 0 )
1292 crs = params.outputCrs;
1293 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1294 prec = std::min( params.precision + 3, 6 );
1302 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1303 QDomElement gmlElem;
1304 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1309 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1319 gmlElem = abstractGeom->
asGml2( doc, prec,
"http://www.opengis.net/gml" );
1323 if ( !gmlElem.isNull() )
1326 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1331 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1332 gmlElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1335 bbElem.appendChild( boxElem );
1336 typeNameElement.appendChild( bbElem );
1338 geomElem.appendChild( gmlElem );
1339 typeNameElement.appendChild( geomElem );
1346 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1348 int idx = params.attributeIndexes[i];
1349 if ( idx >= fields.
count() )
1355 QString attributeName = field.
name();
1357 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1358 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1359 if ( featureAttributes[idx].isNull() )
1361 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1363 fieldElem.appendChild( fieldText );
1364 typeNameElement.appendChild( fieldElem );
1367 return featureElement;
1370 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1373 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1376 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1378 typeNameElement.setAttribute( QStringLiteral(
"gml:id" ),
id );
1379 featureElement.appendChild( typeNameElement );
1383 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1385 int prec = params.precision;
1391 if ( transformed.
transform( mTransform ) == 0 )
1394 crs = params.outputCrs;
1395 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1396 prec = std::min( params.precision + 3, 6 );
1404 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1405 QDomElement gmlElem;
1406 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1411 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1421 gmlElem = abstractGeom->
asGml3( doc, prec,
"http://www.opengis.net/gml" );
1425 if ( !gmlElem.isNull() )
1428 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1433 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1434 gmlElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1437 bbElem.appendChild( boxElem );
1438 typeNameElement.appendChild( bbElem );
1440 geomElem.appendChild( gmlElem );
1441 typeNameElement.appendChild( geomElem );
1448 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1450 int idx = params.attributeIndexes[i];
1451 if ( idx >= fields.
count() )
1459 QString attributeName = field.
name();
1461 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1462 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1463 if ( featureAttributes[idx].isNull() )
1465 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1467 fieldElem.appendChild( fieldText );
1468 typeNameElement.appendChild( fieldElem );
1471 return featureElement;
1476 if ( value.isNull() )
1479 if ( setup.
type() == QStringLiteral(
"DateTime" ) )
1482 const QVariantMap config = setup.
config();
1483 const QString fieldFormat = config.value( QStringLiteral(
"field_format" ), fieldFormatter.
defaultFormat( value.type() ) ).toString();
1484 QDateTime date = value.toDateTime();
1486 if ( date.isValid() )
1488 return date.toString( fieldFormat );
1491 else if ( setup.
type() == QStringLiteral(
"Range" ) )
1493 const QVariantMap config = setup.
config();
1494 if ( config.contains( QStringLiteral(
"Precision" ) ) )
1498 int precision( config[ QStringLiteral(
"Precision" ) ].toInt( &ok ) );
1500 return QString::number( value.toDouble(),
'f',
precision );
1504 switch ( value.type() )
1507 case QVariant::UInt:
1508 case QVariant::LongLong:
1509 case QVariant::ULongLong:
1510 case QVariant::Double:
1511 return value.toString();
1513 case QVariant::Bool:
1514 return value.toBool() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" );
1516 case QVariant::StringList:
1517 case QVariant::List:
1523 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1524 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
1530 case QVariant::String:
1532 QString v = value.toString();
1535 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1536 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
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.
QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
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.
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.
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.
static QDomElement geometryToGML(const QgsGeometry &geometry, QDomDocument &doc, QgsOgcUtils::GMLVersion gmlVersion, const QString &srsName, bool invertAxisOrientation, const QString &gmlIdBase, int precision=17)
Exports the geometry to GML.
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.