44 #include <QStringList> 51 struct createFeatureParams
70 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes );
74 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
76 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
91 QgsWfsParameters mWfsParameters;
104 mWfsParameters.dump();
110 if ( doc.setContent( mRequestParameters.value( QStringLiteral(
"REQUEST_BODY" ) ),
true, &errorMsg ) )
112 QDomElement docElem = doc.documentElement();
121 QStringList typeNameList;
124 bool onlyOneLayer = ( aRequest.
queries.size() == 1 );
127 int requestPrecision = 6;
131 QList<getFeatureQuery>::iterator qIt = aRequest.
queries.begin();
132 for ( ; qIt != aRequest.
queries.end(); ++qIt )
134 typeNameList << ( *qIt ).typeName;
140 QMap<QString, QgsMapLayer *> mapLayerMap;
141 for (
int i = 0; i < wfsLayerIds.size(); ++i )
148 if ( layer->
type() != QgsMapLayer::LayerType::VectorLayer )
155 if ( typeNameList.contains( name ) )
158 mapLayerMap[name] = layer;
162 requestRect = layer->
extent();
163 requestCrs = layer->
crs();
172 requestRect = transform.transform( layer->
extent() );
182 requestRect =
QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
188 #ifdef HAVE_SERVER_PYTHON_PLUGINS 198 long sentFeatures = 0;
199 long iteratedFeatures = 0;
202 qIt = aRequest.
queries.begin();
203 for ( ; qIt != aRequest.
queries.end(); ++qIt )
208 if ( !mapLayerMap.keys().contains( typeName ) )
214 #ifdef HAVE_SERVER_PYTHON_PLUGINS 234 #ifdef HAVE_SERVER_PYTHON_PLUGINS 242 QMap< int, QString > layerAliasInfo;
244 QgsStringMap::const_iterator aliasIt = aliasMap.constBegin();
245 for ( ; aliasIt != aliasMap.constEnd(); ++aliasIt )
248 if ( attrIndex != -1 )
250 layerAliasInfo.insert( attrIndex, aliasIt.value() );
261 if ( !propertyList.isEmpty() && propertyList.first() != QStringLiteral(
"*" ) )
264 QStringList::const_iterator plstIt;
267 QList<QString> propertynames;
268 QList<QString> fieldnames;
269 for (
int idx = 0; idx < fields.
count(); ++idx )
271 fieldnames.append( fields[idx].name() );
275 for ( plstIt = propertyList.begin(); plstIt != propertyList.end(); ++plstIt )
278 int fieldNameIdx = propertynames.indexOf( fieldName );
279 if ( fieldNameIdx == -1 )
281 fieldNameIdx = fieldnames.indexOf( fieldName );
283 if ( fieldNameIdx > -1 )
285 idxList.append( fieldNameIdx );
287 else if ( fieldName == QStringLiteral(
"geometry" ) )
292 if ( !idxList.isEmpty() )
294 attrIndexes = idxList;
300 if ( !attrIndexes.isEmpty() && !layerExcludedAttributes.isEmpty() )
302 foreach (
const QString &excludedAttribute, layerExcludedAttributes )
304 int fieldNameIdx = fields.
indexOf( excludedAttribute );
305 if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
307 attrIndexes.removeOne( fieldNameIdx );
337 #ifdef HAVE_SERVER_PYTHON_PLUGINS 342 QStringList attributes = QStringList();
343 for (
int idx : attrIndexes )
356 if ( !pkAttributes.isEmpty() )
359 for (
int idx : pkAttributes )
361 if ( !subsetOfAttrs.contains( idx ) )
363 subsetOfAttrs.prepend( idx );
390 geometryName = QLatin1String(
"NONE" );
394 if ( !query.
srsName.isEmpty() )
421 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
425 if ( iteratedFeatures >= aRequest.
startIndex )
434 const createFeatureParams cfp = { layerPrecision,
445 if ( iteratedFeatures == aRequest.
startIndex )
446 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
448 if ( iteratedFeatures >= aRequest.
startIndex )
458 #ifdef HAVE_SERVER_PYTHON_PLUGINS 460 filterRestorer.reset();
463 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
465 hitGetFeature( request, response, project, aRequest.
outputFormat, sentFeatures, typeNameList );
470 if ( iteratedFeatures <= aRequest.
startIndex )
471 startGetFeature( request, response, project, aRequest.
outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
480 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
481 request.
startIndex = mWfsParameters.startIndexAsInt();
485 QStringList fidList = mWfsParameters.featureIds();
486 bool paramContainsFeatureIds = !fidList.isEmpty();
487 QStringList filterList = mWfsParameters.filters();
488 bool paramContainsFilters = !filterList.isEmpty();
489 QString bbox = mWfsParameters.bbox();
490 bool paramContainsBbox = !bbox.isEmpty();
491 if ( ( paramContainsFeatureIds
492 && ( paramContainsFilters || paramContainsBbox ) )
493 || ( paramContainsFilters
494 && ( paramContainsFeatureIds || paramContainsBbox ) )
495 || ( paramContainsBbox
496 && ( paramContainsFeatureIds || paramContainsFilters ) )
503 QStringList propertyNameList = mWfsParameters.propertyNames();
506 request.
geometryName = mWfsParameters.geometryNameAsString().toUpper();
508 QStringList typeNameList;
510 if ( paramContainsFeatureIds )
513 if ( !propertyNameList.isEmpty() && propertyNameList.size() != fidList.size() )
517 if ( propertyNameList.isEmpty() )
519 for (
int i = 0; i < fidList.size(); ++i )
521 propertyNameList << QStringLiteral(
"*" );
525 QMap<QString, QStringList> fidsMap;
527 QStringList::const_iterator fidIt = fidList.constBegin();
528 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
529 for ( ; fidIt != fidList.constEnd(); ++fidIt )
532 QString fid = *fidIt;
535 QString propertyName;
536 if ( propertyNameIt != propertyNameList.constEnd() )
538 propertyName = *propertyNameIt;
541 if ( !fid.contains(
'.' ) )
546 QString
typeName = fid.section(
'.', 0, 0 );
547 fid = fid.section(
'.', 1, 1 );
548 if ( !typeNameList.contains( typeName ) )
554 QString key = QStringLiteral(
"%1(%2)" ).arg( typeName ).arg( propertyName );
556 if ( fidsMap.contains( key ) )
558 fids = fidsMap.value( key );
561 fidsMap.insert( key, fids );
563 if ( propertyNameIt != propertyNameList.constEnd() )
569 QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
570 while ( fidsMapIt != fidsMap.constEnd() )
572 QString key = fidsMapIt.key();
575 QRegExp rx(
"([^()]+)\\(([^()]+)\\)" );
576 if ( rx.indexIn( key, 0 ) == -1 )
581 QString propertyName = rx.cap( 2 );
585 query.
srsName = mWfsParameters.srsName();
588 if ( propertyName != QStringLiteral(
"*" ) )
590 QStringList propertyList;
592 QStringList attrList = propertyName.split(
',' );
593 QStringList::const_iterator alstIt;
594 for ( alstIt = attrList.begin(); alstIt != attrList.end(); ++alstIt )
596 QString fieldName = *alstIt;
597 fieldName = fieldName.trimmed();
598 if ( fieldName.contains(
':' ) )
600 fieldName = fieldName.section(
':', 1, 1 );
602 if ( fieldName.contains(
'/' ) )
604 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
608 fieldName = fieldName.section(
'/', 1, 1 );
610 propertyList.append( fieldName );
619 request.
queries.append( query );
625 if ( !mRequestParameters.contains( QStringLiteral(
"TYPENAME" ) ) )
630 typeNameList = mWfsParameters.typeNames();
632 if ( !propertyNameList.isEmpty() && typeNameList.size() != propertyNameList.size() )
636 if ( propertyNameList.isEmpty() )
638 for (
int i = 0; i < typeNameList.size(); ++i )
640 propertyNameList << QStringLiteral(
"*" );
645 QStringList::const_iterator typeNameIt = typeNameList.constBegin();
646 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
647 for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
650 typeName = typeName.trimmed();
652 QString propertyName;
653 if ( propertyNameIt != propertyNameList.constEnd() )
655 propertyName = *propertyNameIt;
660 query.
srsName = mWfsParameters.srsName();
663 if ( propertyName != QStringLiteral(
"*" ) )
665 QStringList propertyList;
667 QStringList attrList = propertyName.split(
',' );
668 QStringList::const_iterator alstIt;
669 for ( alstIt = attrList.begin(); alstIt != attrList.end(); ++alstIt )
671 QString fieldName = *alstIt;
672 fieldName = fieldName.trimmed();
673 if ( fieldName.contains(
':' ) )
675 fieldName = fieldName.section(
':', 1, 1 );
677 if ( fieldName.contains(
'/' ) )
679 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
683 fieldName = fieldName.section(
'/', 1, 1 );
685 propertyList.append( fieldName );
690 request.
queries.append( query );
692 if ( propertyNameIt != propertyNameList.constEnd() )
699 QStringList expFilterList = mWfsParameters.expFilters();
700 if ( !expFilterList.isEmpty() )
703 if ( request.
queries.size() == expFilterList.size() )
706 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
707 QStringList::const_iterator expFilterIt = expFilterList.constBegin();
708 for ( ; qIt != request.
queries.end(); ++qIt )
713 if ( expFilterIt != expFilterList.constEnd() )
715 expFilter = *expFilterIt;
717 std::shared_ptr<QgsExpression> filter(
new QgsExpression( expFilter ) );
720 if ( filter->hasParserError() )
724 if ( filter->needsGeometry() )
738 if ( paramContainsBbox )
745 if ( mWfsParameters.bbox().split(
',' ).size() == 5 && ! mWfsParameters.srsName().isEmpty() )
747 QString
crs( mWfsParameters.bbox().split(
',' )[4] );
748 if (
crs != mWfsParameters.srsName() )
752 if ( sourceCrs.
isValid() && destinationCrs.isValid( ) )
760 if ( extentGeom.
transform( transform ) == 0 )
774 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
775 for ( ; qIt != request.
queries.end(); ++qIt )
782 else if ( paramContainsFilters )
785 if ( request.
queries.size() != filterList.size() )
791 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
792 QStringList::const_iterator filterIt = filterList.constBegin();
793 for ( ; qIt != request.
queries.end(); ++qIt )
798 if ( filterIt != filterList.constEnd() )
801 if ( !filter.setContent( *filterIt,
true, &errorMsg ) )
807 QDomElement filterElem = filter.firstChildElement();
808 QStringList serverFids;
812 if ( filterIt != filterList.constEnd() )
820 QStringList sortByList = mWfsParameters.sortBy();
821 if ( !sortByList.isEmpty() && request.
queries.size() == sortByList.size() )
824 QList<getFeatureQuery>::iterator qIt = request.
queries.begin();
825 QStringList::const_iterator sortByIt = sortByList.constBegin();
826 for ( ; qIt != request.
queries.end(); ++qIt )
831 if ( sortByIt != sortByList.constEnd() )
835 for (
const QString &attribute : sortBy.split(
',' ) )
837 if ( attribute.endsWith( QLatin1String(
" D" ) ) || attribute.endsWith( QLatin1String(
"+D" ) ) )
841 else if ( attribute.endsWith( QLatin1String(
" DESC" ) ) || attribute.endsWith( QLatin1String(
"+DESC" ) ) )
845 else if ( attribute.endsWith( QLatin1String(
" A" ) ) || attribute.endsWith( QLatin1String(
"+A" ) ) )
849 else if ( attribute.endsWith( QLatin1String(
" ASC" ) ) || attribute.endsWith( QLatin1String(
"+ASC" ) ) )
867 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
868 request.
startIndex = mWfsParameters.startIndexAsInt();
871 QDomNodeList queryNodes = docElem.elementsByTagName( QStringLiteral(
"Query" ) );
872 QDomElement queryElem;
873 for (
int i = 0; i < queryNodes.size(); i++ )
875 queryElem = queryNodes.at( i ).toElement();
877 request.
queries.append( query );
884 QDomNodeList sortByNodes = sortByElem.childNodes();
885 if ( sortByNodes.size() )
887 for (
int i = 0; i < sortByNodes.size(); i++ )
889 QDomElement sortPropElem = sortByNodes.at( i ).toElement();
890 QDomNodeList sortPropChildNodes = sortPropElem.childNodes();
891 if ( sortPropChildNodes.size() )
894 bool ascending =
true;
895 for (
int j = 0; j < sortPropChildNodes.size(); j++ )
897 QDomElement sortPropChildElem = sortPropChildNodes.at( j ).toElement();
898 if ( sortPropChildElem.tagName() == QLatin1String(
"PropertyName" ) )
900 fieldName = sortPropChildElem.text().trimmed();
902 else if ( sortPropChildElem.tagName() == QLatin1String(
"SortOrder" ) )
904 QString sortOrder = sortPropChildElem.text().trimmed().toUpper();
905 if ( sortOrder == QLatin1String(
"DESC" ) || sortOrder == QLatin1String(
"D" ) )
910 if ( fieldName.contains(
':' ) )
912 fieldName = fieldName.section(
':', 1, 1 );
914 if ( fieldName.contains(
'/' ) )
916 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
920 fieldName = fieldName.section(
'/', 1, 1 );
923 if ( !fieldName.isEmpty() )
924 featureRequest.
addOrderBy( fieldName, ascending );
932 QString
typeName = queryElem.attribute( QStringLiteral(
"typeName" ), QString() );
933 if ( typeName.contains(
':' ) )
935 typeName = typeName.section(
':', 1, 1 );
939 QStringList serverFids;
940 QStringList propertyList;
941 QDomNodeList queryChildNodes = queryElem.childNodes();
942 if ( queryChildNodes.size() )
944 QDomElement sortByElem;
945 for (
int q = 0; q < queryChildNodes.size(); q++ )
947 QDomElement queryChildElem = queryChildNodes.at( q ).toElement();
948 if ( queryChildElem.tagName() == QLatin1String(
"PropertyName" ) )
950 QString fieldName = queryChildElem.text().trimmed();
951 if ( fieldName.contains(
':' ) )
953 fieldName = fieldName.section(
':', 1, 1 );
955 if ( fieldName.contains(
'/' ) )
957 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
961 fieldName = fieldName.section(
'/', 1, 1 );
963 propertyList.append( fieldName );
965 else if ( queryChildElem.tagName() == QLatin1String(
"Filter" ) )
969 else if ( queryChildElem.tagName() == QLatin1String(
"SortBy" ) )
971 sortByElem = queryChildElem;
978 QString srsName = queryElem.attribute( QStringLiteral(
"srsName" ), QString() );
991 static QSet< QString > sParamFilter
993 QStringLiteral(
"REQUEST" ),
994 QStringLiteral(
"FORMAT" ),
995 QStringLiteral(
"OUTPUTFORMAT" ),
996 QStringLiteral(
"BBOX" ),
997 QStringLiteral(
"FEATUREID" ),
998 QStringLiteral(
"TYPENAME" ),
999 QStringLiteral(
"FILTER" ),
1000 QStringLiteral(
"EXP_FILTER" ),
1001 QStringLiteral(
"MAXFEATURES" ),
1002 QStringLiteral(
"STARTINDEX" ),
1003 QStringLiteral(
"PROPERTYNAME" ),
1004 QStringLiteral(
"_DC" )
1009 int numberOfFeatures,
const QStringList &typeNames )
1011 QDateTime now = QDateTime::currentDateTime();
1014 if ( format == QgsWfsParameters::Format::GeoJSON )
1016 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1017 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1018 fcString += QStringLiteral(
" \"timeStamp\": \"%1\"\n" ).arg( now.toString( Qt::ISODate ) );
1019 fcString += QStringLiteral(
" \"numberOfFeatures\": %1\n" ).arg( QString::number( numberOfFeatures ) );
1020 fcString += QLatin1String(
"}" );
1024 if ( format == QgsWfsParameters::Format::GML2 )
1025 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1027 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1030 QString hrefString =
serviceUrl( request, project );
1032 QUrl mapUrl( hrefString );
1034 QUrlQuery query( mapUrl );
1035 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1037 if ( mWfsParameters.version().isEmpty() )
1040 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1042 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1044 for (
auto param : query.queryItems() )
1046 if ( sParamFilter.contains( param.first.toUpper() ) )
1047 query.removeAllQueryItems( param.first );
1050 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1051 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1054 if ( format == QgsWfsParameters::Format::GML2 )
1055 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1057 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1060 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1062 mapUrl.setQuery( query );
1064 hrefString = mapUrl.toString();
1067 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1071 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1072 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1074 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1075 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1076 fcString +=
"\n timeStamp=\"" + now.toString( Qt::ISODate ) +
"\"";
1077 fcString +=
"\n numberOfFeatures=\"" + QString::number( numberOfFeatures ) +
"\"";
1078 fcString += QLatin1String(
">\n" );
1079 fcString += QStringLiteral(
"</wfs:FeatureCollection>" );
1082 response.
write( fcString.toUtf8() );
1091 std::unique_ptr< QgsRectangle > transformedRect;
1093 if ( format == QgsWfsParameters::Format::GeoJSON )
1095 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1105 if ( exportGeom.
transform( transform ) == 0 )
1108 rect = transformedRect.get();
1119 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1121 fcString += QLatin1String(
" \"features\": [\n" );
1122 response.
write( fcString.toUtf8() );
1126 if ( format == QgsWfsParameters::Format::GML2 )
1127 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1129 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1132 QString hrefString =
serviceUrl( request, project );
1134 QUrl mapUrl( hrefString );
1136 QUrlQuery query( mapUrl );
1137 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1139 if ( mWfsParameters.version().isEmpty() )
1142 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1144 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1146 for (
auto param : query.queryItems() )
1148 if ( sParamFilter.contains( param.first.toUpper() ) )
1149 query.removeAllQueryItems( param.first );
1152 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1153 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1156 if ( format == QgsWfsParameters::Format::GML2 )
1157 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1159 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1162 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1164 mapUrl.setQuery( query );
1166 hrefString = mapUrl.toString();
1169 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1173 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1174 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1176 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1177 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1178 fcString += QLatin1String(
">\n" );
1180 response.
write( fcString.toUtf8() );
1184 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1185 if ( format == QgsWfsParameters::Format::GML3 )
1188 if ( !envElem.isNull() )
1192 envElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1194 bbElem.appendChild( envElem );
1195 doc.appendChild( bbElem );
1201 if ( !boxElem.isNull() )
1205 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1207 bbElem.appendChild( boxElem );
1208 doc.appendChild( bbElem );
1211 response.
write( doc.toByteArray() );
1222 if ( format == QgsWfsParameters::Format::GeoJSON )
1226 fcString += QLatin1String(
" " );
1228 fcString += QLatin1String(
" ," );
1229 mJsonExporter.setSourceCrs( params.crs );
1230 mJsonExporter.setIncludeGeometry(
false );
1231 mJsonExporter.setIncludeAttributes( !params.attributeIndexes.isEmpty() );
1232 mJsonExporter.setAttributes( params.attributeIndexes );
1233 fcString += createFeatureGeoJSON( feature, params, pkAttributes );
1234 fcString += QLatin1String(
"\n" );
1236 response.
write( fcString.toUtf8() );
1240 QDomDocument gmlDoc;
1241 QDomElement featureElement;
1242 if ( format == QgsWfsParameters::Format::GML3 )
1244 featureElement = createFeatureGML3( feature, gmlDoc, params, project, pkAttributes );
1245 gmlDoc.appendChild( featureElement );
1249 featureElement = createFeatureGML2( feature, gmlDoc, params, project, pkAttributes );
1250 gmlDoc.appendChild( featureElement );
1252 response.
write( gmlDoc.toByteArray() );
1262 if ( format == QgsWfsParameters::Format::GeoJSON )
1264 fcString += QLatin1String(
" ]\n" );
1265 fcString += QLatin1String(
"}" );
1269 fcString = QStringLiteral(
"</wfs:FeatureCollection>\n" );
1271 response.
write( fcString.toUtf8() );
1275 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes )
1285 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1287 mJsonExporter.setIncludeGeometry(
true );
1288 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1293 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1299 return mJsonExporter.exportFeature( f, QVariantMap(),
id );
1303 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1306 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1309 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1311 typeNameElement.setAttribute( QStringLiteral(
"fid" ),
id );
1312 featureElement.appendChild( typeNameElement );
1316 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1318 int prec = params.precision;
1324 if ( transformed.
transform( mTransform ) == 0 )
1327 crs = params.outputCrs;
1328 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1329 prec = std::min( params.precision + 3, 6 );
1337 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1338 QDomElement gmlElem;
1340 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1344 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1355 gmlElem = abstractGeom->
asGml2( doc, prec,
"http://www.opengis.net/gml" );
1358 if ( !gmlElem.isNull() )
1361 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1366 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1367 gmlElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1370 bbElem.appendChild( boxElem );
1371 typeNameElement.appendChild( bbElem );
1373 geomElem.appendChild( gmlElem );
1374 typeNameElement.appendChild( geomElem );
1381 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1383 int idx = params.attributeIndexes[i];
1384 if ( idx >= fields.
count() )
1390 QString attributeName = field.
name();
1392 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1393 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1394 if ( featureAttributes[idx].isNull() )
1396 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1398 fieldElem.appendChild( fieldText );
1399 typeNameElement.appendChild( fieldElem );
1402 return featureElement;
1405 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1408 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1411 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1413 typeNameElement.setAttribute( QStringLiteral(
"gml:id" ),
id );
1414 featureElement.appendChild( typeNameElement );
1418 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1420 int prec = params.precision;
1426 if ( transformed.
transform( mTransform ) == 0 )
1429 crs = params.outputCrs;
1430 if ( crs.
isGeographic() && !params.crs.isGeographic() )
1431 prec = std::min( params.precision + 3, 6 );
1439 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1440 QDomElement gmlElem;
1442 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1446 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1457 gmlElem = abstractGeom->
asGml3( doc, prec,
"http://www.opengis.net/gml" );
1460 if ( !gmlElem.isNull() )
1463 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1468 boxElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1469 gmlElem.setAttribute( QStringLiteral(
"srsName" ), crs.
authid() );
1472 bbElem.appendChild( boxElem );
1473 typeNameElement.appendChild( bbElem );
1475 geomElem.appendChild( gmlElem );
1476 typeNameElement.appendChild( geomElem );
1483 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1485 int idx = params.attributeIndexes[i];
1486 if ( idx >= fields.
count() )
1494 QString attributeName = field.
name();
1496 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1497 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1498 if ( featureAttributes[idx].isNull() )
1500 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1502 fieldElem.appendChild( fieldText );
1503 typeNameElement.appendChild( fieldElem );
1506 return featureElement;
1511 if ( value.isNull() )
1514 if ( setup.
type() == QStringLiteral(
"DateTime" ) )
1517 const QVariantMap config = setup.
config();
1518 const QString fieldFormat = config.value( QStringLiteral(
"field_format" ), fieldFormatter.
defaultFormat( value.type() ) ).toString();
1519 QDateTime date = value.toDateTime();
1521 if ( date.isValid() )
1523 return date.toString( fieldFormat );
1526 else if ( setup.
type() == QStringLiteral(
"Range" ) )
1528 const QVariantMap config = setup.
config();
1529 if ( config.contains( QStringLiteral(
"Precision" ) ) )
1533 int precision( config[ QStringLiteral(
"Precision" ) ].toInt( &ok ) );
1535 return QString::number( value.toDouble(),
'f',
precision );
1539 switch ( value.type() )
1542 case QVariant::UInt:
1543 case QVariant::LongLong:
1544 case QVariant::ULongLong:
1545 case QVariant::Double:
1546 return value.toString();
1548 case QVariant::Bool:
1549 return value.toBool() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" );
1551 case QVariant::StringList:
1552 case QVariant::List:
1558 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1559 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
1565 case QVariant::String:
1567 QString v = value.toString();
1570 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1571 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
void writeGetFeature(QgsServerInterface *serverIface, const QgsProject *project, const QString &version, const QgsServerRequest &request, QgsServerResponse &response)
Output WFS GetFeature response.
Class for parsing and evaluation of expressions (formerly called "search strings").
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
QgsAttributeList attributeList() const
Returns list of attribute indexes.
bool isEmpty() const
Returns true if the rectangle is empty.
const Flags & flags() const
QgsMapLayer::LayerType type() const
Returns the type of the layer.
QSet< QString > excludeAttributesWfs() const
A set of attributes that are not advertised in WFS requests with QGIS server.
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
bool isValid() const
Returns the validity of this feature.
getFeatureRequest parseGetFeatureRequestBody(QDomElement &docElem, const QgsProject *project)
Transform RequestBody root element to getFeatureRequest.
const QString QGS_NAMESPACE
virtual QgsAttributeList pkAttributeIndexes() const
Returns list of indexes of fields that make up the primary key.
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
const QgsRectangle & filterRect() const
Returns the rectangle from which features will be taken.
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.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
QgsAttributeList subsetOfAttributes() const
Returns the subset of attributes which at least need to be fetched.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
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.
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
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
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...
QMap< QString, QString > QgsStringMap
QString layerTypeName(const QgsMapLayer *layer)
Returns typename from vector layer.
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.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
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...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
static QString encodeValue(const QVariant &value)
Encodes a value to a JSON string representation, adding appropriate quotations and escaping where req...
double xMaximum() const
Returns the x maximum value (right side of rectangle).
const QString & geometryName
virtual QgsRectangle extent() const
Returns the extent of the layer.
getFeatureQuery parseQueryElement(QDomElement &queryElem, const QgsProject *project)
Transform Query element to getFeatureQuery.
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).
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.
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
Reads and writes project states.
QString implementationVersion()
Returns the highest version supported by this implementation.
int count() const
Returns number of items.
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.
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Abstract base class for all geometries.
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
QgsField field(int fieldIdx) const
Gets field at particular index (must be in range 0..N-1)
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.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
const QRegExp cleanTagNameRegExp("(?![\\w\\d\\.-]).")
const QString OGC_NAMESPACE
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...
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QgsServerInterface Class defining interfaces exposed by QGIS Server and made available to plugins...
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
QStringList layerAttributes(const QgsVectorLayer *layer, const QStringList &attributes) const
Returns the authorized layer attributes.
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
SERVER_EXPORT QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS.
This class represents a coordinate reference system (CRS).
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
QString authid() const
Returns the authority identifier for the CRS.
static QDomElement rectangleToGMLEnvelope(QgsRectangle *env, QDomDocument &doc, int precision=17)
Exports the rectangle to GML3 Envelope.
const QgsCoordinateReferenceSystem & outputCrs
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.
Exception thrown when data access violates access controls.
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.
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.
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
QgsServerRequest::Parameters parameters() const
Returns a map of query parameters with keys converted to uppercase.
bool isGeographic() const
Returns whether the CRS is a geographic CRS (using lat/lon coordinates)
double xMinimum() const
Returns the x minimum value (left side of rectangle).
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
Defines a QGIS exception class.
Provides an interface to retrieve and manipulate WFS parameters received from the client...
QgsStringMap attributeAliases() const
Returns a map of field name to attribute alias.
QgsCoordinateReferenceSystem crs
QgsGeometry centroid() const
Returns the center of mass of a geometry.
virtual QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const =0
Returns a GML3 representation of the geometry.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QMap< QString, QString > Parameters
bool layerReadPermission(const QgsMapLayer *layer) const
Returns the layer read right.