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 )
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 );
180 #ifdef HAVE_SERVER_PYTHON_PLUGINS 190 long sentFeatures = 0;
191 long iteratedFeatures = 0;
194 qIt = aRequest.
queries.begin();
195 for ( ; qIt != aRequest.
queries.end(); ++qIt )
200 if ( !mapLayerMap.keys().contains( typeName ) )
206 #ifdef HAVE_SERVER_PYTHON_PLUGINS 224 #ifdef HAVE_SERVER_PYTHON_PLUGINS 231 QMap< int, QString > layerAliasInfo;
233 QgsStringMap::const_iterator aliasIt = aliasMap.constBegin();
234 for ( ; aliasIt != aliasMap.constEnd(); ++aliasIt )
237 if ( attrIndex != -1 )
239 layerAliasInfo.insert( attrIndex, aliasIt.value() );
250 if ( !propertyList.isEmpty() && propertyList.first() != QStringLiteral(
"*" ) )
253 QStringList::const_iterator plstIt;
256 QList<QString> propertynames;
257 QList<QString> fieldnames;
258 for (
int idx = 0; idx < fields.
count(); ++idx )
260 fieldnames.append( fields[idx].name() );
264 for ( plstIt = propertyList.constBegin(); plstIt != propertyList.constEnd(); ++plstIt )
267 int fieldNameIdx = propertynames.indexOf( fieldName );
268 if ( fieldNameIdx == -1 )
270 fieldNameIdx = fieldnames.indexOf( fieldName );
272 if ( fieldNameIdx > -1 )
274 idxList.append( fieldNameIdx );
276 else if ( fieldName == QStringLiteral(
"geometry" ) )
281 if ( !idxList.isEmpty() )
283 attrIndexes = idxList;
289 if ( !attrIndexes.isEmpty() && !layerExcludedAttributes.isEmpty() )
291 foreach (
const QString &excludedAttribute, layerExcludedAttributes )
293 int fieldNameIdx = fields.
indexOf( excludedAttribute );
294 if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
296 attrIndexes.removeOne( fieldNameIdx );
319 #ifdef HAVE_SERVER_PYTHON_PLUGINS 324 QStringList attributes = QStringList();
325 for (
int idx : attrIndexes )
352 geometryName = QLatin1String(
"NONE" );
356 if ( !query.
srsName.isEmpty() )
381 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
385 if ( iteratedFeatures >= aRequest.
startIndex )
394 const createFeatureParams cfp = { layerPrecision,
404 if ( iteratedFeatures == aRequest.
startIndex )
405 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
407 if ( iteratedFeatures >= aRequest.
startIndex )
409 setGetFeature( response, aRequest.
outputFormat, &feature, sentFeatures, cfp, project );
417 #ifdef HAVE_SERVER_PYTHON_PLUGINS 419 filterRestorer.reset();
422 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
424 hitGetFeature( request, response, project, aRequest.
outputFormat, sentFeatures, typeNameList );
429 if ( iteratedFeatures <= aRequest.
startIndex )
430 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
439 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
440 request.
startIndex = mWfsParameters.startIndexAsInt();
444 QStringList fidList = mWfsParameters.featureIds();
445 bool paramContainsFeatureIds = !fidList.isEmpty();
446 QStringList filterList = mWfsParameters.filters();
447 bool paramContainsFilters = !filterList.isEmpty();
448 QString bbox = mWfsParameters.bbox();
449 bool paramContainsBbox = !bbox.isEmpty();
450 if ( ( paramContainsFeatureIds
451 && ( paramContainsFilters || paramContainsBbox ) )
452 || ( paramContainsFilters
453 && ( paramContainsFeatureIds || paramContainsBbox ) )
454 || ( paramContainsBbox
455 && ( paramContainsFeatureIds || paramContainsFilters ) )
462 QStringList propertyNameList = mWfsParameters.propertyNames();
465 request.
geometryName = mWfsParameters.geometryNameAsString().toUpper();
467 QStringList typeNameList;
469 if ( paramContainsFeatureIds )
472 if ( !propertyNameList.isEmpty() && propertyNameList.size() != fidList.size() )
476 if ( propertyNameList.isEmpty() )
478 for (
int i = 0; i < fidList.size(); ++i )
480 propertyNameList << QStringLiteral(
"*" );
484 QMap<QString, QgsFeatureIds> fidsMap;
486 QStringList::const_iterator fidIt = fidList.constBegin();
487 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
488 for ( ; fidIt != fidList.constEnd(); ++fidIt )
491 QString fid = *fidIt;
494 QString propertyName;
495 if ( propertyNameIt != propertyNameList.constEnd() )
497 propertyName = *propertyNameIt;
500 if ( !fid.contains(
'.' ) )
505 QString
typeName = fid.section(
'.', 0, 0 );
506 fid = fid.section(
'.', 1, 1 );
507 if ( !typeNameList.contains( typeName ) )
513 QString key = QStringLiteral(
"%1(%2)" ).arg( typeName ).arg( propertyName );
515 if ( fidsMap.contains( key ) )
517 fids = fidsMap.value( key );
519 fids.insert( fid.toInt() );
520 fidsMap.insert( key, fids );
522 if ( propertyNameIt != propertyNameList.constEnd() )
528 QMap<QString, QgsFeatureIds>::const_iterator fidsMapIt = fidsMap.constBegin();
529 while ( fidsMapIt != fidsMap.constEnd() )
531 QString key = fidsMapIt.key();
534 QRegExp rx(
"([^()]+)\\(([^()]+)\\)" );
535 if ( rx.indexIn( key, 0 ) == -1 )
540 QString propertyName = rx.cap( 2 );
544 query.
srsName = mWfsParameters.srsName();
547 if ( propertyName != QStringLiteral(
"*" ) )
549 QStringList propertyList;
551 const QStringList attrList = propertyName.split(
',' );
552 QStringList::const_iterator alstIt;
553 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
555 QString fieldName = *alstIt;
556 fieldName = fieldName.trimmed();
557 if ( fieldName.contains(
':' ) )
559 fieldName = fieldName.section(
':', 1, 1 );
561 if ( fieldName.contains(
'/' ) )
563 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
567 fieldName = fieldName.section(
'/', 1, 1 );
569 propertyList.append( fieldName );
578 request.
queries.append( query );
584 if ( !mRequestParameters.contains( QStringLiteral(
"TYPENAME" ) ) )
589 typeNameList = mWfsParameters.typeNames();
591 if ( !propertyNameList.isEmpty() && typeNameList.size() != propertyNameList.size() )
595 if ( propertyNameList.isEmpty() )
597 for (
int i = 0; i < typeNameList.size(); ++i )
599 propertyNameList << QStringLiteral(
"*" );
604 QStringList::const_iterator typeNameIt = typeNameList.constBegin();
605 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
606 for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
609 typeName = typeName.trimmed();
611 QString propertyName;
612 if ( propertyNameIt != propertyNameList.constEnd() )
614 propertyName = *propertyNameIt;
619 query.
srsName = mWfsParameters.srsName();
622 if ( propertyName != QStringLiteral(
"*" ) )
624 QStringList propertyList;
626 const QStringList attrList = propertyName.split(
',' );
627 QStringList::const_iterator alstIt;
628 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
630 QString fieldName = *alstIt;
631 fieldName = fieldName.trimmed();
632 if ( fieldName.contains(
':' ) )
634 fieldName = fieldName.section(
':', 1, 1 );
636 if ( fieldName.contains(
'/' ) )
638 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
642 fieldName = fieldName.section(
'/', 1, 1 );
644 propertyList.append( fieldName );
649 request.
queries.append( query );
651 if ( propertyNameIt != propertyNameList.constEnd() )
658 QStringList expFilterList = mWfsParameters.expFilters();
659 if ( !expFilterList.isEmpty() )
662 if ( request.
queries.size() == expFilterList.size() )
665 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
666 QStringList::const_iterator expFilterIt = expFilterList.constBegin();
667 for ( ; qIt != request.
queries.end(); ++qIt )
672 if ( expFilterIt != expFilterList.constEnd() )
674 expFilter = *expFilterIt;
676 std::shared_ptr<QgsExpression> filter(
new QgsExpression( expFilter ) );
679 if ( filter->hasParserError() )
683 if ( filter->needsGeometry() )
697 if ( paramContainsBbox )
704 if ( mWfsParameters.bbox().split(
',' ).size() == 5 && ! mWfsParameters.srsName().isEmpty() )
706 QString
crs( mWfsParameters.bbox().split(
',' )[4] );
707 if (
crs != mWfsParameters.srsName() )
711 if ( sourceCrs.
isValid() && destinationCrs.isValid( ) )
719 if ( extentGeom.
transform( transform ) == 0 )
733 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
734 for ( ; qIt != request.
queries.end(); ++qIt )
741 else if ( paramContainsFilters )
744 if ( request.
queries.size() != filterList.size() )
750 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
751 QStringList::const_iterator filterIt = filterList.constBegin();
752 for ( ; qIt != request.
queries.end(); ++qIt )
757 if ( filterIt != filterList.constEnd() )
760 if ( !filter.setContent( *filterIt,
true, &errorMsg ) )
766 QDomElement filterElem = filter.firstChildElement();
769 if ( filterIt != filterList.constEnd() )
777 QStringList sortByList = mWfsParameters.sortBy();
778 if ( !sortByList.isEmpty() && request.
queries.size() == sortByList.size() )
781 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
782 QStringList::const_iterator sortByIt = sortByList.constBegin();
783 for ( ; qIt != request.
queries.end(); ++qIt )
788 if ( sortByIt != sortByList.constEnd() )
792 for (
const QString &attribute : sortBy.split(
',' ) )
794 if ( attribute.endsWith( QLatin1String(
" D" ) ) || attribute.endsWith( QLatin1String(
"+D" ) ) )
798 else if ( attribute.endsWith( QLatin1String(
" DESC" ) ) || attribute.endsWith( QLatin1String(
"+DESC" ) ) )
802 else if ( attribute.endsWith( QLatin1String(
" A" ) ) || attribute.endsWith( QLatin1String(
"+A" ) ) )
806 else if ( attribute.endsWith( QLatin1String(
" ASC" ) ) || attribute.endsWith( QLatin1String(
"+ASC" ) ) )
824 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
825 request.
startIndex = mWfsParameters.startIndexAsInt();
828 QDomNodeList queryNodes = docElem.elementsByTagName( QStringLiteral(
"Query" ) );
829 QDomElement queryElem;
830 for (
int i = 0; i < queryNodes.size(); i++ )
832 queryElem = queryNodes.at( i ).toElement();
834 request.
queries.append( query );
841 QDomNodeList sortByNodes = sortByElem.childNodes();
842 if ( sortByNodes.size() )
844 for (
int i = 0; i < sortByNodes.size(); i++ )
846 QDomElement sortPropElem = sortByNodes.at( i ).toElement();
847 QDomNodeList sortPropChildNodes = sortPropElem.childNodes();
848 if ( sortPropChildNodes.size() )
851 bool ascending =
true;
852 for (
int j = 0; j < sortPropChildNodes.size(); j++ )
854 QDomElement sortPropChildElem = sortPropChildNodes.at( j ).toElement();
855 if ( sortPropChildElem.tagName() == QLatin1String(
"PropertyName" ) )
857 fieldName = sortPropChildElem.text().trimmed();
859 else if ( sortPropChildElem.tagName() == QLatin1String(
"SortOrder" ) )
861 QString sortOrder = sortPropChildElem.text().trimmed().toUpper();
862 if ( sortOrder == QLatin1String(
"DESC" ) || sortOrder == QLatin1String(
"D" ) )
867 if ( fieldName.contains(
':' ) )
869 fieldName = fieldName.section(
':', 1, 1 );
871 if ( fieldName.contains(
'/' ) )
873 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
877 fieldName = fieldName.section(
'/', 1, 1 );
880 if ( !fieldName.isEmpty() )
881 featureRequest.
addOrderBy( fieldName, ascending );
889 QString
typeName = queryElem.attribute( QStringLiteral(
"typeName" ), QString() );
890 if ( typeName.contains(
':' ) )
892 typeName = typeName.section(
':', 1, 1 );
896 QStringList propertyList;
897 QDomNodeList queryChildNodes = queryElem.childNodes();
898 if ( queryChildNodes.size() )
900 QDomElement sortByElem;
901 for (
int q = 0; q < queryChildNodes.size(); q++ )
903 QDomElement queryChildElem = queryChildNodes.at( q ).toElement();
904 if ( queryChildElem.tagName() == QLatin1String(
"PropertyName" ) )
906 QString fieldName = queryChildElem.text().trimmed();
907 if ( fieldName.contains(
':' ) )
909 fieldName = fieldName.section(
':', 1, 1 );
911 if ( fieldName.contains(
'/' ) )
913 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
917 fieldName = fieldName.section(
'/', 1, 1 );
919 propertyList.append( fieldName );
921 else if ( queryChildElem.tagName() == QLatin1String(
"Filter" ) )
925 else if ( queryChildElem.tagName() == QLatin1String(
"SortBy" ) )
927 sortByElem = queryChildElem;
934 QString srsName = queryElem.attribute( QStringLiteral(
"srsName" ), QString() );
946 static QSet< QString > sParamFilter
948 QStringLiteral(
"REQUEST" ),
949 QStringLiteral(
"FORMAT" ),
950 QStringLiteral(
"OUTPUTFORMAT" ),
951 QStringLiteral(
"BBOX" ),
952 QStringLiteral(
"FEATUREID" ),
953 QStringLiteral(
"TYPENAME" ),
954 QStringLiteral(
"FILTER" ),
955 QStringLiteral(
"EXP_FILTER" ),
956 QStringLiteral(
"MAXFEATURES" ),
957 QStringLiteral(
"STARTINDEX" ),
958 QStringLiteral(
"PROPERTYNAME" ),
959 QStringLiteral(
"_DC" )
964 int numberOfFeatures,
const QStringList &typeNames )
966 QDateTime now = QDateTime::currentDateTime();
969 if ( format == QgsWfsParameters::Format::GeoJSON )
971 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
972 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
973 fcString += QStringLiteral(
" \"timeStamp\": \"%1\"\n" ).arg( now.toString( Qt::ISODate ) );
974 fcString += QStringLiteral(
" \"numberOfFeatures\": %1\n" ).arg( QString::number( numberOfFeatures ) );
975 fcString += QLatin1String(
"}" );
979 if ( format == QgsWfsParameters::Format::GML2 )
980 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
982 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
985 QString hrefString =
serviceUrl( request, project );
987 QUrl mapUrl( hrefString );
989 QUrlQuery query( mapUrl );
990 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
992 if ( mWfsParameters.version().isEmpty() )
995 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
997 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
999 for (
auto param : query.queryItems() )
1001 if ( sParamFilter.contains( param.first.toUpper() ) )
1002 query.removeAllQueryItems( param.first );
1005 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1006 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1009 if ( format == QgsWfsParameters::Format::GML2 )
1010 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1012 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1015 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1017 mapUrl.setQuery( query );
1019 hrefString = mapUrl.toString();
1022 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1026 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1027 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1029 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1030 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1031 fcString +=
"\n timeStamp=\"" + now.toString( Qt::ISODate ) +
"\"";
1032 fcString +=
"\n numberOfFeatures=\"" + QString::number( numberOfFeatures ) +
"\"";
1033 fcString += QLatin1String(
">\n" );
1034 fcString += QStringLiteral(
"</wfs:FeatureCollection>" );
1037 response.
write( fcString.toUtf8() );
1046 std::unique_ptr< QgsRectangle > transformedRect;
1048 if ( format == QgsWfsParameters::Format::GeoJSON )
1050 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1060 if ( exportGeom.
transform( transform ) == 0 )
1063 rect = transformedRect.get();
1074 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1076 fcString += QLatin1String(
" \"features\": [\n" );
1077 response.
write( fcString.toUtf8() );
1081 if ( format == QgsWfsParameters::Format::GML2 )
1082 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1084 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1087 QString hrefString =
serviceUrl( request, project );
1089 QUrl mapUrl( hrefString );
1091 QUrlQuery query( mapUrl );
1092 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1094 if ( mWfsParameters.version().isEmpty() )
1097 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1099 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1101 for (
auto param : query.queryItems() )
1103 if ( sParamFilter.contains( param.first.toUpper() ) )
1104 query.removeAllQueryItems( param.first );
1107 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1108 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1111 if ( format == QgsWfsParameters::Format::GML2 )
1112 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1114 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1117 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1119 mapUrl.setQuery( query );
1121 hrefString = mapUrl.toString();
1124 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1128 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1129 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1131 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1132 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1133 fcString += QLatin1String(
">\n" );
1135 response.
write( fcString.toUtf8() );
1139 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1140 if ( format == QgsWfsParameters::Format::GML3 )
1143 if ( !envElem.isNull() )
1147 envElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1149 bbElem.appendChild( envElem );
1150 doc.appendChild( bbElem );
1156 if ( !boxElem.isNull() )
1160 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1162 bbElem.appendChild( boxElem );
1163 doc.appendChild( bbElem );
1166 response.
write( doc.toByteArray() );
1172 const createFeatureParams ¶ms,
const QgsProject *project )
1177 if ( format == QgsWfsParameters::Format::GeoJSON )
1181 fcString += QLatin1String(
" " );
1183 fcString += QLatin1String(
" ," );
1184 mJsonExporter.setSourceCrs( params.crs );
1185 mJsonExporter.setIncludeGeometry(
false );
1186 mJsonExporter.setIncludeAttributes( !params.attributeIndexes.isEmpty() );
1187 mJsonExporter.setAttributes( params.attributeIndexes );
1188 fcString += createFeatureGeoJSON( feat, params );
1189 fcString += QLatin1String(
"\n" );
1191 response.
write( fcString.toUtf8() );
1195 QDomDocument gmlDoc;
1196 QDomElement featureElement;
1197 if ( format == QgsWfsParameters::Format::GML3 )
1199 featureElement = createFeatureGML3( feat, gmlDoc, params, project );
1200 gmlDoc.appendChild( featureElement );
1204 featureElement = createFeatureGML2( feat, gmlDoc, params, project );
1205 gmlDoc.appendChild( featureElement );
1207 response.
write( gmlDoc.toByteArray() );
1217 if ( format == QgsWfsParameters::Format::GeoJSON )
1219 fcString += QLatin1String(
" ]\n" );
1220 fcString += QLatin1String(
"}" );
1224 fcString = QStringLiteral(
"</wfs:FeatureCollection>\n" );
1226 response.
write( fcString.toUtf8() );
1230 QString createFeatureGeoJSON(
QgsFeature *feat,
const createFeatureParams ¶ms )
1232 QString
id = QStringLiteral(
"%1.%2" ).arg( params.typeName,
FID_TO_STRING( feat->
id() ) );
1240 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1242 mJsonExporter.setIncludeGeometry(
true );
1243 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1248 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1254 return mJsonExporter.exportFeature( f, QVariantMap(),
id );
1258 QDomElement createFeatureGML2(
QgsFeature *feat, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project )
1261 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1264 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1265 typeNameElement.setAttribute( QStringLiteral(
"fid" ), params.typeName +
"." + QString::number( feat->
id() ) );
1266 featureElement.appendChild( typeNameElement );
1270 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1272 int prec = params.precision;
1278 if ( transformed.
transform( mTransform ) == 0 )
1281 crs = params.outputCrs;
1282 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1283 prec = std::min( params.precision + 3, 6 );
1291 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1292 QDomElement gmlElem;
1293 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1298 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1308 gmlElem = abstractGeom->
asGml2( doc, prec,
"http://www.opengis.net/gml" );
1312 if ( !gmlElem.isNull() )
1315 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1320 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1321 gmlElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1324 bbElem.appendChild( boxElem );
1325 typeNameElement.appendChild( bbElem );
1327 geomElem.appendChild( gmlElem );
1328 typeNameElement.appendChild( geomElem );
1335 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1337 int idx = params.attributeIndexes[i];
1338 if ( idx >= fields.
count() )
1344 QString attributeName = field.
name();
1346 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1347 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1348 if ( featureAttributes[idx].isNull() )
1350 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1352 fieldElem.appendChild( fieldText );
1353 typeNameElement.appendChild( fieldElem );
1356 return featureElement;
1359 QDomElement createFeatureGML3(
QgsFeature *feat, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project )
1362 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1365 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1366 typeNameElement.setAttribute( QStringLiteral(
"gml:id" ), params.typeName +
"." + QString::number( feat->
id() ) );
1367 featureElement.appendChild( typeNameElement );
1371 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1373 int prec = params.precision;
1379 if ( transformed.
transform( mTransform ) == 0 )
1382 crs = params.outputCrs;
1383 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1384 prec = std::min( params.precision + 3, 6 );
1392 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1393 QDomElement gmlElem;
1394 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1399 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1409 gmlElem = abstractGeom->
asGml3( doc, prec,
"http://www.opengis.net/gml" );
1413 if ( !gmlElem.isNull() )
1416 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1421 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1422 gmlElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1425 bbElem.appendChild( boxElem );
1426 typeNameElement.appendChild( bbElem );
1428 geomElem.appendChild( gmlElem );
1429 typeNameElement.appendChild( geomElem );
1436 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1438 int idx = params.attributeIndexes[i];
1439 if ( idx >= fields.
count() )
1447 QString attributeName = field.
name();
1449 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1450 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1451 if ( featureAttributes[idx].isNull() )
1453 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1455 fieldElem.appendChild( fieldText );
1456 typeNameElement.appendChild( fieldElem );
1459 return featureElement;
1464 if ( value.isNull() )
1467 if ( setup.
type() == QStringLiteral(
"DateTime" ) )
1470 const QVariantMap config = setup.
config();
1471 const QString fieldFormat = config.value( QStringLiteral(
"field_format" ), fieldFormatter.
defaultFormat( value.type() ) ).toString();
1472 QDateTime date = value.toDateTime();
1474 if ( date.isValid() )
1476 return date.toString( fieldFormat );
1479 else if ( setup.
type() == QStringLiteral(
"Range" ) )
1481 const QVariantMap config = setup.
config();
1482 if ( config.contains( QStringLiteral(
"Precision" ) ) )
1486 int precision( config[ QStringLiteral(
"Precision" ) ].toInt( &ok ) );
1488 return QString::number( value.toDouble(),
'f',
precision );
1492 switch ( value.type() )
1495 case QVariant::UInt:
1496 case QVariant::LongLong:
1497 case QVariant::ULongLong:
1498 case QVariant::Double:
1499 return value.toString();
1501 case QVariant::Bool:
1502 return value.toBool() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" );
1504 case QVariant::StringList:
1505 case QVariant::List:
1511 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1512 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
1518 case QVariant::String:
1520 QString v = value.toString();
1523 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1524 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
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.
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...
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
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
bool isValid() const
Returns whether this CRS is correctly initialized and usable.