45 struct createFeatureParams
62 QString createFeatureGeoJSON(
QgsFeature *feat,
const createFeatureParams ¶ms );
66 QDomElement createFeatureGML2(
QgsFeature *feat, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project );
68 QDomElement createFeatureGML3(
QgsFeature *feat, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project );
78 const createFeatureParams ¶ms,
const QgsProject *project );
83 QgsWfsParameters mWfsParameters;
96 mWfsParameters.dump();
102 if ( doc.setContent( mRequestParameters.value( QStringLiteral(
"REQUEST_BODY" ) ),
true, &errorMsg ) )
104 QDomElement docElem = doc.documentElement();
113 QStringList typeNameList;
116 bool onlyOneLayer = ( aRequest.
queries.size() == 1 );
119 int requestPrecision = 6;
123 QList<getFeatureQuery>::iterator qIt = aRequest.
queries.begin();
124 for ( ; qIt != aRequest.
queries.end(); ++qIt )
126 typeNameList << ( *qIt ).typeName;
132 QMap<QString, QgsMapLayer *> mapLayerMap;
133 for (
int i = 0; i < wfsLayerIds.size(); ++i )
140 if ( layer->
type() != QgsMapLayer::LayerType::VectorLayer )
147 if ( typeNameList.contains( name ) )
150 mapLayerMap[name] = layer;
154 requestRect = layer->
extent();
155 requestCrs = layer->
crs();
164 requestRect = transform.transform( layer->
extent() );
174 requestRect =
QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
187 long sentFeatures = 0;
188 long iteratedFeatures = 0;
191 qIt = aRequest.
queries.begin();
192 for ( ; qIt != aRequest.
queries.end(); ++qIt )
197 if ( !mapLayerMap.keys().contains( typeName ) )
227 QMap< int, QString > layerAliasInfo;
229 QgsStringMap::const_iterator aliasIt = aliasMap.constBegin();
230 for ( ; aliasIt != aliasMap.constEnd(); ++aliasIt )
233 if ( attrIndex != -1 )
235 layerAliasInfo.insert( attrIndex, aliasIt.value() );
246 if ( !propertyList.isEmpty() && propertyList.first() != QStringLiteral(
"*" ) )
249 QStringList::const_iterator plstIt;
252 QList<QString> propertynames;
253 QList<QString> fieldnames;
254 for (
int idx = 0; idx < fields.
count(); ++idx )
256 fieldnames.append( fields[idx].name() );
260 for ( plstIt = propertyList.begin(); plstIt != propertyList.end(); ++plstIt )
263 int fieldNameIdx = propertynames.indexOf( fieldName );
264 if ( fieldNameIdx == -1 )
266 fieldNameIdx = fieldnames.indexOf( fieldName );
268 if ( fieldNameIdx > -1 )
270 idxList.append( fieldNameIdx );
272 else if ( fieldName == QStringLiteral(
"geometry" ) )
277 if ( !idxList.isEmpty() )
279 attrIndexes = idxList;
285 if ( !attrIndexes.isEmpty() && !layerExcludedAttributes.isEmpty() )
287 foreach (
const QString &excludedAttribute, layerExcludedAttributes )
289 int fieldNameIdx = fields.
indexOf( excludedAttribute );
290 if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
292 attrIndexes.removeOne( fieldNameIdx );
320 QStringList attributes = QStringList();
321 for (
int idx : attrIndexes )
348 geometryName = QLatin1String(
"NONE" );
352 if ( !query.
srsName.isEmpty() )
377 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
381 if ( iteratedFeatures >= aRequest.
startIndex )
390 const createFeatureParams cfp = { layerPrecision,
400 if ( iteratedFeatures == aRequest.
startIndex )
401 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
403 if ( iteratedFeatures >= aRequest.
startIndex )
405 setGetFeature( response, aRequest.
outputFormat, &feature, sentFeatures, cfp, project );
413 #ifdef HAVE_SERVER_PYTHON_PLUGINS 415 filterRestorer.reset();
418 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
420 hitGetFeature( request, response, project, aRequest.
outputFormat, sentFeatures, typeNameList );
425 if ( iteratedFeatures <= aRequest.
startIndex )
426 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
435 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
436 request.
startIndex = mWfsParameters.startIndexAsInt();
440 QStringList fidList = mWfsParameters.featureIds();
441 bool paramContainsFeatureIds = !fidList.isEmpty();
442 QStringList filterList = mWfsParameters.filters();
443 bool paramContainsFilters = !filterList.isEmpty();
444 QString bbox = mWfsParameters.bbox();
445 bool paramContainsBbox = !bbox.isEmpty();
446 if ( ( paramContainsFeatureIds
447 && ( paramContainsFilters || paramContainsBbox ) )
448 || ( paramContainsFilters
449 && ( paramContainsFeatureIds || paramContainsBbox ) )
450 || ( paramContainsBbox
451 && ( paramContainsFeatureIds || paramContainsFilters ) )
458 QStringList propertyNameList = mWfsParameters.propertyNames();
461 request.
geometryName = mWfsParameters.geometryNameAsString().toUpper();
463 QStringList typeNameList;
465 if ( paramContainsFeatureIds )
468 if ( !propertyNameList.isEmpty() && propertyNameList.size() != fidList.size() )
472 if ( propertyNameList.isEmpty() )
474 for (
int i = 0; i < fidList.size(); ++i )
476 propertyNameList << QStringLiteral(
"*" );
480 QMap<QString, QgsFeatureIds> fidsMap;
482 QStringList::const_iterator fidIt = fidList.constBegin();
483 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
484 for ( ; fidIt != fidList.constEnd(); ++fidIt )
487 QString fid = *fidIt;
490 QString propertyName;
491 if ( propertyNameIt != propertyNameList.constEnd() )
493 propertyName = *propertyNameIt;
496 if ( !fid.contains(
'.' ) )
501 QString
typeName = fid.section(
'.', 0, 0 );
502 fid = fid.section(
'.', 1, 1 );
503 if ( !typeNameList.contains( typeName ) )
509 QString key = QStringLiteral(
"%1(%2)" ).arg( typeName ).arg( propertyName );
511 if ( fidsMap.contains( key ) )
513 fids = fidsMap.value( key );
515 fids.insert( fid.toInt() );
516 fidsMap.insert( key, fids );
518 if ( propertyNameIt != propertyNameList.constEnd() )
524 QMap<QString, QgsFeatureIds>::const_iterator fidsMapIt = fidsMap.constBegin();
525 while ( fidsMapIt != fidsMap.constEnd() )
527 QString key = fidsMapIt.key();
530 QRegExp rx(
"([^()]+)\\(([^()]+)\\)" );
531 if ( rx.indexIn( key, 0 ) == -1 )
536 QString propertyName = rx.cap( 2 );
540 query.
srsName = mWfsParameters.srsName();
543 if ( propertyName != QStringLiteral(
"*" ) )
545 QStringList propertyList;
547 QStringList attrList = propertyName.split(
',' );
548 QStringList::const_iterator alstIt;
549 for ( alstIt = attrList.begin(); alstIt != attrList.end(); ++alstIt )
551 QString fieldName = *alstIt;
552 fieldName = fieldName.trimmed();
553 if ( fieldName.contains(
':' ) )
555 fieldName = fieldName.section(
':', 1, 1 );
557 if ( fieldName.contains(
'/' ) )
559 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
563 fieldName = fieldName.section(
'/', 1, 1 );
565 propertyList.append( fieldName );
574 request.
queries.append( query );
580 if ( !mRequestParameters.contains( QStringLiteral(
"TYPENAME" ) ) )
585 typeNameList = mWfsParameters.typeNames();
587 if ( !propertyNameList.isEmpty() && typeNameList.size() != propertyNameList.size() )
591 if ( propertyNameList.isEmpty() )
593 for (
int i = 0; i < typeNameList.size(); ++i )
595 propertyNameList << QStringLiteral(
"*" );
600 QStringList::const_iterator typeNameIt = typeNameList.constBegin();
601 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
602 for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
605 typeName = typeName.trimmed();
607 QString propertyName;
608 if ( propertyNameIt != propertyNameList.constEnd() )
610 propertyName = *propertyNameIt;
615 query.
srsName = mWfsParameters.srsName();
618 if ( propertyName != QStringLiteral(
"*" ) )
620 QStringList propertyList;
622 QStringList attrList = propertyName.split(
',' );
623 QStringList::const_iterator alstIt;
624 for ( alstIt = attrList.begin(); alstIt != attrList.end(); ++alstIt )
626 QString fieldName = *alstIt;
627 fieldName = fieldName.trimmed();
628 if ( fieldName.contains(
':' ) )
630 fieldName = fieldName.section(
':', 1, 1 );
632 if ( fieldName.contains(
'/' ) )
634 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
638 fieldName = fieldName.section(
'/', 1, 1 );
640 propertyList.append( fieldName );
645 request.
queries.append( query );
647 if ( propertyNameIt != propertyNameList.constEnd() )
654 QStringList expFilterList = mWfsParameters.expFilters();
655 if ( !expFilterList.isEmpty() )
658 if ( request.
queries.size() == expFilterList.size() )
661 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
662 QStringList::const_iterator expFilterIt = expFilterList.constBegin();
663 for ( ; qIt != request.
queries.end(); ++qIt )
668 if ( expFilterIt != expFilterList.constEnd() )
670 expFilter = *expFilterIt;
672 std::shared_ptr<QgsExpression> filter(
new QgsExpression( expFilter ) );
675 if ( filter->hasParserError() )
679 if ( filter->needsGeometry() )
693 if ( paramContainsBbox )
700 if ( mWfsParameters.bbox().split(
',' ).size() == 5 && ! mWfsParameters.srsName().isEmpty() )
702 QString
crs( mWfsParameters.bbox().split(
',' )[4] );
703 if (
crs != mWfsParameters.srsName() )
707 if ( sourceCrs.
isValid() && destinationCrs.isValid( ) )
715 if ( extentGeom.
transform( transform ) == 0 )
729 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
730 for ( ; qIt != request.
queries.end(); ++qIt )
737 else if ( paramContainsFilters )
740 if ( request.
queries.size() != filterList.size() )
746 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
747 QStringList::const_iterator filterIt = filterList.constBegin();
748 for ( ; qIt != request.
queries.end(); ++qIt )
753 if ( filterIt != filterList.constEnd() )
756 if ( !filter.setContent( *filterIt,
true, &errorMsg ) )
762 QDomElement filterElem = filter.firstChildElement();
765 if ( filterIt != filterList.constEnd() )
773 QStringList sortByList = mWfsParameters.sortBy();
774 if ( !sortByList.isEmpty() && request.
queries.size() == sortByList.size() )
777 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
778 QStringList::const_iterator sortByIt = sortByList.constBegin();
779 for ( ; qIt != request.
queries.end(); ++qIt )
784 if ( sortByIt != sortByList.constEnd() )
788 for (
const QString &attribute : sortBy.split(
',' ) )
790 if ( attribute.endsWith( QLatin1String(
" D" ) ) || attribute.endsWith( QLatin1String(
"+D" ) ) )
794 else if ( attribute.endsWith( QLatin1String(
" DESC" ) ) || attribute.endsWith( QLatin1String(
"+DESC" ) ) )
798 else if ( attribute.endsWith( QLatin1String(
" A" ) ) || attribute.endsWith( QLatin1String(
"+A" ) ) )
802 else if ( attribute.endsWith( QLatin1String(
" ASC" ) ) || attribute.endsWith( QLatin1String(
"+ASC" ) ) )
820 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
821 request.
startIndex = mWfsParameters.startIndexAsInt();
824 QDomNodeList queryNodes = docElem.elementsByTagName( QStringLiteral(
"Query" ) );
825 QDomElement queryElem;
826 for (
int i = 0; i < queryNodes.size(); i++ )
828 queryElem = queryNodes.at( i ).toElement();
830 request.
queries.append( query );
837 QDomNodeList sortByNodes = sortByElem.childNodes();
838 if ( sortByNodes.size() )
840 for (
int i = 0; i < sortByNodes.size(); i++ )
842 QDomElement sortPropElem = sortByNodes.at( i ).toElement();
843 QDomNodeList sortPropChildNodes = sortPropElem.childNodes();
844 if ( sortPropChildNodes.size() )
847 bool ascending =
true;
848 for (
int j = 0; j < sortPropChildNodes.size(); j++ )
850 QDomElement sortPropChildElem = sortPropChildNodes.at( j ).toElement();
851 if ( sortPropChildElem.tagName() == QLatin1String(
"PropertyName" ) )
853 fieldName = sortPropChildElem.text().trimmed();
855 else if ( sortPropChildElem.tagName() == QLatin1String(
"SortOrder" ) )
857 QString sortOrder = sortPropChildElem.text().trimmed().toUpper();
858 if ( sortOrder == QLatin1String(
"DESC" ) || sortOrder == QLatin1String(
"D" ) )
863 if ( fieldName.contains(
':' ) )
865 fieldName = fieldName.section(
':', 1, 1 );
867 if ( fieldName.contains(
'/' ) )
869 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
873 fieldName = fieldName.section(
'/', 1, 1 );
876 if ( !fieldName.isEmpty() )
877 featureRequest.
addOrderBy( fieldName, ascending );
885 QString
typeName = queryElem.attribute( QStringLiteral(
"typeName" ), QString() );
886 if ( typeName.contains(
':' ) )
888 typeName = typeName.section(
':', 1, 1 );
892 QStringList propertyList;
893 QDomNodeList queryChildNodes = queryElem.childNodes();
894 if ( queryChildNodes.size() )
896 QDomElement sortByElem;
897 for (
int q = 0; q < queryChildNodes.size(); q++ )
899 QDomElement queryChildElem = queryChildNodes.at( q ).toElement();
900 if ( queryChildElem.tagName() == QLatin1String(
"PropertyName" ) )
902 QString fieldName = queryChildElem.text().trimmed();
903 if ( fieldName.contains(
':' ) )
905 fieldName = fieldName.section(
':', 1, 1 );
907 if ( fieldName.contains(
'/' ) )
909 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
913 fieldName = fieldName.section(
'/', 1, 1 );
915 propertyList.append( fieldName );
917 else if ( queryChildElem.tagName() == QLatin1String(
"Filter" ) )
921 else if ( queryChildElem.tagName() == QLatin1String(
"SortBy" ) )
923 sortByElem = queryChildElem;
930 QString srsName = queryElem.attribute( QStringLiteral(
"srsName" ), QString() );
942 static QSet< QString > sParamFilter
944 QStringLiteral(
"REQUEST" ),
945 QStringLiteral(
"FORMAT" ),
946 QStringLiteral(
"OUTPUTFORMAT" ),
947 QStringLiteral(
"BBOX" ),
948 QStringLiteral(
"FEATUREID" ),
949 QStringLiteral(
"TYPENAME" ),
950 QStringLiteral(
"FILTER" ),
951 QStringLiteral(
"EXP_FILTER" ),
952 QStringLiteral(
"MAXFEATURES" ),
953 QStringLiteral(
"STARTINDEX" ),
954 QStringLiteral(
"PROPERTYNAME" ),
955 QStringLiteral(
"_DC" )
960 int numberOfFeatures,
const QStringList &typeNames )
962 QDateTime now = QDateTime::currentDateTime();
965 if ( format == QgsWfsParameters::Format::GeoJSON )
967 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
968 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
969 fcString += QStringLiteral(
" \"timeStamp\": \"%1\"\n" ).arg( now.toString( Qt::ISODate ) );
970 fcString += QStringLiteral(
" \"numberOfFeatures\": %1\n" ).arg( QString::number( numberOfFeatures ) );
971 fcString += QLatin1String(
"}" );
975 if ( format == QgsWfsParameters::Format::GML2 )
976 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
978 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
981 QString hrefString =
serviceUrl( request, project );
983 QUrl mapUrl( hrefString );
985 QUrlQuery query( mapUrl );
986 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
988 if ( mWfsParameters.version().isEmpty() )
991 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
993 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
995 for (
auto param : query.queryItems() )
997 if ( sParamFilter.contains( param.first.toUpper() ) )
998 query.removeAllQueryItems( param.first );
1001 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1002 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1005 if ( format == QgsWfsParameters::Format::GML2 )
1006 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1008 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1011 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1013 mapUrl.setQuery( query );
1015 hrefString = mapUrl.toString();
1018 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1022 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1023 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1025 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1026 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1027 fcString +=
"\n timeStamp=\"" + now.toString( Qt::ISODate ) +
"\"";
1028 fcString +=
"\n numberOfFeatures=\"" + QString::number( numberOfFeatures ) +
"\"";
1029 fcString += QLatin1String(
">\n" );
1030 fcString += QStringLiteral(
"</wfs:FeatureCollection>" );
1033 response.
write( fcString.toUtf8() );
1042 std::unique_ptr< QgsRectangle > transformedRect;
1044 if ( format == QgsWfsParameters::Format::GeoJSON )
1046 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1056 if ( exportGeom.
transform( transform ) == 0 )
1059 rect = transformedRect.get();
1070 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1072 fcString += QLatin1String(
" \"features\": [\n" );
1073 response.
write( fcString.toUtf8() );
1077 if ( format == QgsWfsParameters::Format::GML2 )
1078 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1080 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1083 QString hrefString =
serviceUrl( request, project );
1085 QUrl mapUrl( hrefString );
1087 QUrlQuery query( mapUrl );
1088 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1090 if ( mWfsParameters.version().isEmpty() )
1093 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1095 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1097 for (
auto param : query.queryItems() )
1099 if ( sParamFilter.contains( param.first.toUpper() ) )
1100 query.removeAllQueryItems( param.first );
1103 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1104 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1107 if ( format == QgsWfsParameters::Format::GML2 )
1108 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1110 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1113 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1115 mapUrl.setQuery( query );
1117 hrefString = mapUrl.toString();
1120 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1124 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1125 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1127 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1128 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1129 fcString += QLatin1String(
">\n" );
1131 response.
write( fcString.toUtf8() );
1135 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1136 if ( format == QgsWfsParameters::Format::GML3 )
1139 if ( !envElem.isNull() )
1143 envElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1145 bbElem.appendChild( envElem );
1146 doc.appendChild( bbElem );
1152 if ( !boxElem.isNull() )
1156 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1158 bbElem.appendChild( boxElem );
1159 doc.appendChild( bbElem );
1162 response.
write( doc.toByteArray() );
1168 const createFeatureParams ¶ms,
const QgsProject *project )
1173 if ( format == QgsWfsParameters::Format::GeoJSON )
1177 fcString += QLatin1String(
" " );
1179 fcString += QLatin1String(
" ," );
1180 mJsonExporter.setSourceCrs( params.crs );
1181 mJsonExporter.setIncludeGeometry(
false );
1182 mJsonExporter.setIncludeAttributes( !params.attributeIndexes.isEmpty() );
1183 mJsonExporter.setAttributes( params.attributeIndexes );
1184 fcString += createFeatureGeoJSON( feat, params );
1185 fcString += QLatin1String(
"\n" );
1187 response.
write( fcString.toUtf8() );
1191 QDomDocument gmlDoc;
1192 QDomElement featureElement;
1193 if ( format == QgsWfsParameters::Format::GML3 )
1195 featureElement = createFeatureGML3( feat, gmlDoc, params, project );
1196 gmlDoc.appendChild( featureElement );
1200 featureElement = createFeatureGML2( feat, gmlDoc, params, project );
1201 gmlDoc.appendChild( featureElement );
1203 response.
write( gmlDoc.toByteArray() );
1213 if ( format == QgsWfsParameters::Format::GeoJSON )
1215 fcString += QLatin1String(
" ]\n" );
1216 fcString += QLatin1String(
"}" );
1220 fcString = QStringLiteral(
"</wfs:FeatureCollection>\n" );
1222 response.
write( fcString.toUtf8() );
1226 QString createFeatureGeoJSON(
QgsFeature *feat,
const createFeatureParams ¶ms )
1228 QString
id = QStringLiteral(
"%1.%2" ).arg( params.typeName,
FID_TO_STRING( feat->
id() ) );
1236 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1238 mJsonExporter.setIncludeGeometry(
true );
1239 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1244 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1250 return mJsonExporter.exportFeature( f, QVariantMap(),
id );
1254 QDomElement createFeatureGML2(
QgsFeature *feat, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project )
1257 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1260 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1261 typeNameElement.setAttribute( QStringLiteral(
"fid" ), params.typeName +
"." + QString::number( feat->
id() ) );
1262 featureElement.appendChild( typeNameElement );
1266 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1268 int prec = params.precision;
1274 if ( transformed.
transform( mTransform ) == 0 )
1277 crs = params.outputCrs;
1278 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1279 prec = std::min( params.precision + 3, 6 );
1287 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1288 QDomElement gmlElem;
1289 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1294 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1304 gmlElem = abstractGeom->
asGml2( doc, prec,
"http://www.opengis.net/gml" );
1308 if ( !gmlElem.isNull() )
1311 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1316 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1317 gmlElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1320 bbElem.appendChild( boxElem );
1321 typeNameElement.appendChild( bbElem );
1323 geomElem.appendChild( gmlElem );
1324 typeNameElement.appendChild( geomElem );
1331 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1333 int idx = params.attributeIndexes[i];
1334 if ( idx >= fields.
count() )
1340 QString attributeName = field.
name();
1342 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1343 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1344 if ( featureAttributes[idx].isNull() )
1346 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1348 fieldElem.appendChild( fieldText );
1349 typeNameElement.appendChild( fieldElem );
1352 return featureElement;
1355 QDomElement createFeatureGML3(
QgsFeature *feat, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project )
1358 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1361 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1362 typeNameElement.setAttribute( QStringLiteral(
"gml:id" ), params.typeName +
"." + QString::number( feat->
id() ) );
1363 featureElement.appendChild( typeNameElement );
1367 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1369 int prec = params.precision;
1375 if ( transformed.
transform( mTransform ) == 0 )
1378 crs = params.outputCrs;
1379 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1380 prec = std::min( params.precision + 3, 6 );
1388 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1389 QDomElement gmlElem;
1390 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1395 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1405 gmlElem = abstractGeom->
asGml3( doc, prec,
"http://www.opengis.net/gml" );
1409 if ( !gmlElem.isNull() )
1412 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1417 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1418 gmlElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1421 bbElem.appendChild( boxElem );
1422 typeNameElement.appendChild( bbElem );
1424 geomElem.appendChild( gmlElem );
1425 typeNameElement.appendChild( geomElem );
1432 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1434 int idx = params.attributeIndexes[i];
1435 if ( idx >= fields.
count() )
1443 QString attributeName = field.
name();
1445 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1446 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1447 if ( featureAttributes[idx].isNull() )
1449 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1451 fieldElem.appendChild( fieldText );
1452 typeNameElement.appendChild( fieldElem );
1455 return featureElement;
1460 if ( value.isNull() )
1463 if ( setup.
type() == QStringLiteral(
"DateTime" ) )
1466 const QVariantMap config = setup.
config();
1467 const QString fieldFormat = config.value( QStringLiteral(
"field_format" ), fieldFormatter.
defaultFormat( value.type() ) ).toString();
1468 QDateTime date = value.toDateTime();
1470 if ( date.isValid() )
1472 return date.toString( fieldFormat );
1475 else if ( setup.
type() == QStringLiteral(
"Range" ) )
1477 const QVariantMap config = setup.
config();
1478 if ( config.contains( QStringLiteral(
"Precision" ) ) )
1482 int precision( config[ QStringLiteral(
"Precision" ) ].toInt( &ok ) );
1484 return QString::number( value.toDouble(),
'f',
precision );
1488 switch ( value.type() )
1491 case QVariant::UInt:
1492 case QVariant::LongLong:
1493 case QVariant::ULongLong:
1494 case QVariant::Double:
1495 return value.toString();
1497 case QVariant::Bool:
1498 return value.toBool() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" );
1500 case QVariant::StringList:
1501 case QVariant::List:
1507 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1508 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
1514 case QVariant::String:
1516 QString v = value.toString();
1519 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1520 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
QSet< QgsFeatureId > QgsFeatureIds
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.
QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
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...
QgsMapLayer::LayerType type() const
Returns the type of the layer.
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.
Reads and writes project states.
QString implementationVersion()
Returns the highest version supported by this implementation.
QgsAttributeList attributeList() const
Returns list of attribute indexes.
Format
Output format for the response.
virtual void flush()=0
Flushes the current output buffer to the network.
Encapsulate a field in an attribute table or data source.
Abstract base class for all geometries.
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.
#define FID_TO_STRING(fid)
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.
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
Query 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 null.
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
bool isValid() const
Returns whether this CRS is correctly initialized and usable.