47 struct createFeatureParams
66 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes );
70 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
72 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes );
87 QgsWfsParameters mWfsParameters;
99 mWfsParameters = QgsWfsParameters( QUrlQuery( request.
url() ) );
100 mWfsParameters.dump();
101 getFeatureRequest aRequest;
106 if ( doc.setContent( request.
data(),
true, &errorMsg ) )
108 QDomElement docElem = doc.documentElement();
117 QStringList typeNameList;
120 bool onlyOneLayer = ( aRequest.queries.size() == 1 );
123 int requestPrecision = 6;
127 QList<getFeatureQuery>::iterator qIt = aRequest.queries.begin();
128 for ( ; qIt != aRequest.queries.end(); ++qIt )
130 typeNameList << ( *qIt ).typeName;
136 QMap<QString, QgsMapLayer *> mapLayerMap;
151 if ( typeNameList.contains( name ) )
154 mapLayerMap[name] = layer;
158 requestRect = layer->
extent();
159 requestCrs = layer->
crs();
168 requestRect = transform.transform( layer->
extent() );
178 requestRect =
QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
184 #ifdef HAVE_SERVER_PYTHON_PLUGINS
194 long sentFeatures = 0;
195 long iteratedFeatures = 0;
198 qIt = aRequest.queries.begin();
199 for ( ; qIt != aRequest.queries.end(); ++qIt )
201 getFeatureQuery &query = *qIt;
204 if ( !mapLayerMap.keys().contains(
typeName ) )
206 throw QgsRequestNotWellFormedException( QStringLiteral(
"TypeName '%1' unknown" ).arg(
typeName ) );
210 #ifdef HAVE_SERVER_PYTHON_PLUGINS
213 throw QgsSecurityAccessException( QStringLiteral(
"Feature access permission denied" ) );
219 throw QgsRequestNotWellFormedException( QStringLiteral(
"TypeName '%1' layer error" ).arg(
typeName ) );
226 throw QgsRequestNotWellFormedException( QStringLiteral(
"TypeName '%1' layer's provider error" ).arg(
typeName ) );
228 #ifdef HAVE_SERVER_PYTHON_PLUGINS
235 QMap< int, QString > layerAliasInfo;
237 QgsStringMap::const_iterator aliasIt = aliasMap.constBegin();
238 for ( ; aliasIt != aliasMap.constEnd(); ++aliasIt )
241 if ( attrIndex != -1 )
243 layerAliasInfo.insert( attrIndex, aliasIt.value() );
248 const QStringList propertyList = query.propertyList;
254 if ( !propertyList.isEmpty() && propertyList.first() != QStringLiteral(
"*" ) )
257 QStringList::const_iterator plstIt;
260 QList<QString> propertynames;
261 QList<QString> fieldnames;
262 for (
int idx = 0; idx < fields.
count(); ++idx )
264 fieldnames.append( fields[idx].name() );
268 for ( plstIt = propertyList.constBegin(); plstIt != propertyList.constEnd(); ++plstIt )
271 int fieldNameIdx = propertynames.indexOf( fieldName );
272 if ( fieldNameIdx == -1 )
274 fieldNameIdx = fieldnames.indexOf( fieldName );
276 if ( fieldNameIdx > -1 )
278 idxList.append( fieldNameIdx );
280 else if ( fieldName == QStringLiteral(
"geometry" ) )
285 if ( !idxList.isEmpty() )
287 attrIndexes = idxList;
293 if ( !attrIndexes.isEmpty() && !layerExcludedAttributes.isEmpty() )
295 foreach (
const QString &excludedAttribute, layerExcludedAttributes )
297 int fieldNameIdx = fields.
indexOf( excludedAttribute );
298 if ( fieldNameIdx > -1 && attrIndexes.contains( fieldNameIdx ) )
300 attrIndexes.removeOne( fieldNameIdx );
316 if ( !query.serverFids.isEmpty() )
329 #ifdef HAVE_SERVER_PYTHON_PLUGINS
334 QStringList attributes = QStringList();
335 for (
int idx : attrIndexes )
348 if ( !pkAttributes.isEmpty() )
351 for (
int idx : pkAttributes )
353 if ( !subsetOfAttrs.contains( idx ) )
355 subsetOfAttrs.prepend( idx );
369 if ( aRequest.maxFeatures > 0 )
371 featureRequest.
setLimit( aRequest.maxFeatures + aRequest.startIndex - sentFeatures );
386 if ( !query.srsName.isEmpty() )
413 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
415 while ( fit.
nextFeature( feature ) && ( aRequest.maxFeatures == -1 || sentFeatures < aRequest.maxFeatures ) )
417 if ( iteratedFeatures >= aRequest.startIndex )
426 const createFeatureParams cfp = { layerPrecision,
435 while ( fit.
nextFeature( feature ) && ( aRequest.maxFeatures == -1 || sentFeatures < aRequest.maxFeatures ) )
437 if ( iteratedFeatures == aRequest.startIndex )
438 startGetFeature( request, response, project, aRequest.outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
440 if ( iteratedFeatures >= aRequest.startIndex )
442 setGetFeature( response, aRequest.outputFormat, feature, sentFeatures, cfp, project, provider->
pkAttributeIndexes() );
450 #ifdef HAVE_SERVER_PYTHON_PLUGINS
452 filterRestorer.reset();
455 if ( mWfsParameters.resultType() == QgsWfsParameters::ResultType::HITS )
457 hitGetFeature( request, response, project, aRequest.outputFormat, sentFeatures, typeNameList );
462 if ( iteratedFeatures <= aRequest.startIndex )
463 startGetFeature( request, response, project, aRequest.outputFormat, requestPrecision, requestCrs, &requestRect, typeNameList );
464 endGetFeature( response, aRequest.outputFormat );
471 getFeatureRequest request;
472 request.maxFeatures = mWfsParameters.maxFeaturesAsInt();;
473 request.startIndex = mWfsParameters.startIndexAsInt();
474 request.outputFormat = mWfsParameters.outputFormat();
477 QStringList fidList = mWfsParameters.featureIds();
478 bool paramContainsFeatureIds = !fidList.isEmpty();
479 QStringList filterList = mWfsParameters.filters();
480 bool paramContainsFilters = !filterList.isEmpty();
481 QString bbox = mWfsParameters.bbox();
482 bool paramContainsBbox = !bbox.isEmpty();
483 if ( ( paramContainsFeatureIds
484 && ( paramContainsFilters || paramContainsBbox ) )
485 || ( paramContainsFilters
486 && ( paramContainsFeatureIds || paramContainsBbox ) )
487 || ( paramContainsBbox
488 && ( paramContainsFeatureIds || paramContainsFilters ) )
495 QStringList propertyNameList = mWfsParameters.propertyNames();
498 request.geometryName = mWfsParameters.geometryNameAsString().toUpper();
500 QStringList typeNameList;
502 if ( paramContainsFeatureIds )
505 if ( !propertyNameList.isEmpty() && propertyNameList.size() != fidList.size() )
507 throw QgsRequestNotWellFormedException( QStringLiteral(
"There has to be a 1:1 mapping between each element in a FEATUREID and the PROPERTYNAME list" ) );
509 if ( propertyNameList.isEmpty() )
511 for (
int i = 0; i < fidList.size(); ++i )
513 propertyNameList << QStringLiteral(
"*" );
517 QMap<QString, QStringList> fidsMap;
519 QStringList::const_iterator fidIt = fidList.constBegin();
520 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
521 for ( ; fidIt != fidList.constEnd(); ++fidIt )
524 QString fid = *fidIt;
527 QString propertyName;
528 if ( propertyNameIt != propertyNameList.constEnd() )
530 propertyName = *propertyNameIt;
533 if ( !fid.contains(
'.' ) )
535 throw QgsRequestNotWellFormedException( QStringLiteral(
"FEATUREID has to have TYPENAME in the values" ) );
538 QString
typeName = fid.section(
'.', 0, 0 );
539 fid = fid.section(
'.', 1, 1 );
540 if ( !typeNameList.contains(
typeName ) )
546 QString key = QStringLiteral(
"%1(%2)" ).arg(
typeName ).arg( propertyName );
548 if ( fidsMap.contains( key ) )
550 fids = fidsMap.value( key );
553 fidsMap.insert( key, fids );
555 if ( propertyNameIt != propertyNameList.constEnd() )
561 QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
562 while ( fidsMapIt != fidsMap.constEnd() )
564 QString key = fidsMapIt.key();
567 QRegExp rx(
"([^()]+)\\(([^()]+)\\)" );
568 if ( rx.indexIn( key, 0 ) == -1 )
570 throw QgsRequestNotWellFormedException( QStringLiteral(
"Error getting properties for FEATUREID" ) );
573 QString propertyName = rx.cap( 2 );
575 getFeatureQuery query;
577 query.srsName = mWfsParameters.srsName();
580 if ( propertyName != QStringLiteral(
"*" ) )
582 QStringList propertyList;
584 const QStringList attrList = propertyName.split(
',' );
585 QStringList::const_iterator alstIt;
586 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
588 QString fieldName = *alstIt;
589 fieldName = fieldName.trimmed();
590 if ( fieldName.contains(
':' ) )
592 fieldName = fieldName.section(
':', 1, 1 );
594 if ( fieldName.contains(
'/' ) )
596 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
598 throw QgsRequestNotWellFormedException( QStringLiteral(
"PropertyName text '%1' has to contain TypeName '%2'" ).arg( fieldName ).arg(
typeName ) );
600 fieldName = fieldName.section(
'/', 1, 1 );
602 propertyList.append( fieldName );
604 query.propertyList = propertyList;
607 query.serverFids = fidsMapIt.value();
610 query.featureRequest = featureRequest;
611 request.queries.append( query );
617 if ( !mRequestParameters.contains( QStringLiteral(
"TYPENAME" ) ) )
619 throw QgsRequestNotWellFormedException( QStringLiteral(
"TYPENAME is mandatory except if FEATUREID is used" ) );
622 typeNameList = mWfsParameters.typeNames();
624 if ( !propertyNameList.isEmpty() && typeNameList.size() != propertyNameList.size() )
626 throw QgsRequestNotWellFormedException( QStringLiteral(
"There has to be a 1:1 mapping between each element in a TYPENAME and the PROPERTYNAME list" ) );
628 if ( propertyNameList.isEmpty() )
630 for (
int i = 0; i < typeNameList.size(); ++i )
632 propertyNameList << QStringLiteral(
"*" );
637 QStringList::const_iterator typeNameIt = typeNameList.constBegin();
638 QStringList::const_iterator propertyNameIt = propertyNameList.constBegin();
639 for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
644 QString propertyName;
645 if ( propertyNameIt != propertyNameList.constEnd() )
647 propertyName = *propertyNameIt;
650 getFeatureQuery query;
652 query.srsName = mWfsParameters.srsName();
655 if ( propertyName != QStringLiteral(
"*" ) )
657 QStringList propertyList;
659 const QStringList attrList = propertyName.split(
',' );
660 QStringList::const_iterator alstIt;
661 for ( alstIt = attrList.constBegin(); alstIt != attrList.constEnd(); ++alstIt )
663 QString fieldName = *alstIt;
664 fieldName = fieldName.trimmed();
665 if ( fieldName.contains(
':' ) )
667 fieldName = fieldName.section(
':', 1, 1 );
669 if ( fieldName.contains(
'/' ) )
671 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
673 throw QgsRequestNotWellFormedException( QStringLiteral(
"PropertyName text '%1' has to contain TypeName '%2'" ).arg( fieldName ).arg(
typeName ) );
675 fieldName = fieldName.section(
'/', 1, 1 );
677 propertyList.append( fieldName );
679 query.propertyList = propertyList;
682 request.queries.append( query );
684 if ( propertyNameIt != propertyNameList.constEnd() )
691 QStringList expFilterList = mWfsParameters.expFilters();
692 if ( !expFilterList.isEmpty() )
695 if ( request.queries.size() == expFilterList.size() )
698 QList<getFeatureQuery>::iterator qIt = request.queries.begin();
699 QStringList::const_iterator expFilterIt = expFilterList.constBegin();
700 for ( ; qIt != request.queries.end(); ++qIt )
702 getFeatureQuery &query = *qIt;
705 if ( expFilterIt != expFilterList.constEnd() )
707 expFilter = *expFilterIt;
709 std::shared_ptr<QgsExpression> filter(
new QgsExpression( expFilter ) );
712 if ( filter->hasParserError() )
714 throw QgsRequestNotWellFormedException( QStringLiteral(
"The EXP_FILTER expression has errors: %1" ).arg( filter->parserErrorString() ) );
716 if ( filter->needsGeometry() )
720 query.featureRequest.setFilterExpression( filter->expression() );
730 if ( paramContainsBbox )
737 if ( mWfsParameters.bbox().split(
',' ).size() == 5 && ! mWfsParameters.srsName().isEmpty() )
739 QString
crs( mWfsParameters.bbox().split(
',' )[4] );
740 if (
crs != mWfsParameters.srsName() )
744 if ( sourceCrs.isValid() && destinationCrs.isValid( ) )
752 if ( extentGeom.
transform( transform ) == 0 )
766 QList<getFeatureQuery>::iterator qIt = request.queries.begin();
767 for ( ; qIt != request.queries.end(); ++qIt )
769 getFeatureQuery &query = *qIt;
770 query.featureRequest.setFilterRect( extent );
774 else if ( paramContainsFilters )
777 if ( request.queries.size() != filterList.size() )
779 throw QgsRequestNotWellFormedException( QStringLiteral(
"There has to be a 1:1 mapping between each element in a TYPENAME and the FILTER list" ) );
783 QList<getFeatureQuery>::iterator qIt = request.queries.begin();
784 QStringList::const_iterator filterIt = filterList.constBegin();
785 for ( ; qIt != request.queries.end(); ++qIt )
787 getFeatureQuery &query = *qIt;
790 if ( filterIt != filterList.constEnd() )
793 if ( !filter.setContent( *filterIt,
true, &errorMsg ) )
795 throw QgsRequestNotWellFormedException( QStringLiteral(
"error message: %1. The XML string was: %2" ).arg( errorMsg, *filterIt ) );
799 QDomElement filterElem = filter.firstChildElement();
800 QStringList serverFids;
801 query.featureRequest =
parseFilterElement( query.typeName, filterElem, serverFids, project );
802 query.serverFids = serverFids;
804 if ( filterIt != filterList.constEnd() )
812 QStringList sortByList = mWfsParameters.sortBy();
813 if ( !sortByList.isEmpty() && request.queries.size() == sortByList.size() )
816 QList<getFeatureQuery>::iterator qIt = request.queries.begin();
817 QStringList::const_iterator sortByIt = sortByList.constBegin();
818 for ( ; qIt != request.queries.end(); ++qIt )
820 getFeatureQuery &query = *qIt;
823 if ( sortByIt != sortByList.constEnd() )
827 for (
const QString &attribute : sortBy.split(
',' ) )
829 if ( attribute.endsWith( QLatin1String(
" D" ) ) || attribute.endsWith( QLatin1String(
"+D" ) ) )
831 query.featureRequest.addOrderBy( attribute.left( attribute.size() - 2 ),
false );
833 else if ( attribute.endsWith( QLatin1String(
" DESC" ) ) || attribute.endsWith( QLatin1String(
"+DESC" ) ) )
835 query.featureRequest.addOrderBy( attribute.left( attribute.size() - 5 ),
false );
837 else if ( attribute.endsWith( QLatin1String(
" A" ) ) || attribute.endsWith( QLatin1String(
"+A" ) ) )
839 query.featureRequest.addOrderBy( attribute.left( attribute.size() - 2 ) );
841 else if ( attribute.endsWith( QLatin1String(
" ASC" ) ) || attribute.endsWith( QLatin1String(
"+ASC" ) ) )
843 query.featureRequest.addOrderBy( attribute.left( attribute.size() - 4 ) );
847 query.featureRequest.addOrderBy( attribute );
858 getFeatureRequest request;
859 request.
maxFeatures = mWfsParameters.maxFeaturesAsInt();;
860 request.startIndex = mWfsParameters.startIndexAsInt();
861 request.outputFormat = mWfsParameters.outputFormat();
863 QDomNodeList queryNodes = docElem.elementsByTagName( QStringLiteral(
"Query" ) );
864 QDomElement queryElem;
865 for (
int i = 0; i < queryNodes.size(); i++ )
867 queryElem = queryNodes.at( i ).toElement();
869 request.queries.append( query );
876 QDomNodeList sortByNodes = sortByElem.childNodes();
877 if ( sortByNodes.size() )
879 for (
int i = 0; i < sortByNodes.size(); i++ )
881 QDomElement sortPropElem = sortByNodes.at( i ).toElement();
882 QDomNodeList sortPropChildNodes = sortPropElem.childNodes();
883 if ( sortPropChildNodes.size() )
886 bool ascending =
true;
887 for (
int j = 0; j < sortPropChildNodes.size(); j++ )
889 QDomElement sortPropChildElem = sortPropChildNodes.at( j ).toElement();
890 if ( sortPropChildElem.tagName() == QLatin1String(
"PropertyName" ) )
892 fieldName = sortPropChildElem.text().trimmed();
894 else if ( sortPropChildElem.tagName() == QLatin1String(
"SortOrder" ) )
896 QString sortOrder = sortPropChildElem.text().trimmed().toUpper();
897 if ( sortOrder == QLatin1String(
"DESC" ) || sortOrder == QLatin1String(
"D" ) )
902 if ( fieldName.contains(
':' ) )
904 fieldName = fieldName.section(
':', 1, 1 );
906 if ( fieldName.contains(
'/' ) )
908 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
910 throw QgsRequestNotWellFormedException( QStringLiteral(
"PropertyName text '%1' has to contain TypeName '%2'" ).arg( fieldName ).arg(
typeName ) );
912 fieldName = fieldName.section(
'/', 1, 1 );
915 if ( !fieldName.isEmpty() )
916 featureRequest.
addOrderBy( fieldName, ascending );
924 QString
typeName = queryElem.attribute( QStringLiteral(
"typeName" ), QString() );
931 QStringList serverFids;
932 QStringList propertyList;
933 QDomNodeList queryChildNodes = queryElem.childNodes();
934 if ( queryChildNodes.size() )
936 QDomElement sortByElem;
937 for (
int q = 0; q < queryChildNodes.size(); q++ )
939 QDomElement queryChildElem = queryChildNodes.at( q ).toElement();
940 if ( queryChildElem.tagName() == QLatin1String(
"PropertyName" ) )
942 QString fieldName = queryChildElem.text().trimmed();
943 if ( fieldName.contains(
':' ) )
945 fieldName = fieldName.section(
':', 1, 1 );
947 if ( fieldName.contains(
'/' ) )
949 if ( fieldName.section(
'/', 0, 0 ) !=
typeName )
953 fieldName = fieldName.section(
'/', 1, 1 );
955 propertyList.append( fieldName );
957 else if ( queryChildElem.tagName() == QLatin1String(
"Filter" ) )
961 else if ( queryChildElem.tagName() == QLatin1String(
"SortBy" ) )
963 sortByElem = queryChildElem;
970 QString srsName = queryElem.attribute( QStringLiteral(
"srsName" ), QString() );
972 getFeatureQuery query;
974 query.srsName = srsName;
975 query.featureRequest = featureRequest;
976 query.serverFids = serverFids;
977 query.propertyList = propertyList;
983 static QSet< QString > sParamFilter
985 QStringLiteral(
"REQUEST" ),
986 QStringLiteral(
"FORMAT" ),
987 QStringLiteral(
"OUTPUTFORMAT" ),
988 QStringLiteral(
"BBOX" ),
989 QStringLiteral(
"FEATUREID" ),
990 QStringLiteral(
"TYPENAME" ),
991 QStringLiteral(
"FILTER" ),
992 QStringLiteral(
"EXP_FILTER" ),
993 QStringLiteral(
"MAXFEATURES" ),
994 QStringLiteral(
"STARTINDEX" ),
995 QStringLiteral(
"PROPERTYNAME" ),
996 QStringLiteral(
"_DC" )
1001 int numberOfFeatures,
const QStringList &typeNames )
1003 QDateTime now = QDateTime::currentDateTime();
1006 if ( format == QgsWfsParameters::Format::GeoJSON )
1008 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1009 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1010 fcString += QStringLiteral(
" \"timeStamp\": \"%1\"\n" ).arg( now.toString( Qt::ISODate ) );
1011 fcString += QStringLiteral(
" \"numberOfFeatures\": %1\n" ).arg( QString::number( numberOfFeatures ) );
1012 fcString += QLatin1String(
"}" );
1016 if ( format == QgsWfsParameters::Format::GML2 )
1017 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1019 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1022 QString hrefString =
serviceUrl( request, project );
1024 QUrl mapUrl( hrefString );
1026 QUrlQuery query( mapUrl );
1027 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1029 if ( mWfsParameters.version().isEmpty() )
1032 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1034 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1036 for (
auto param : query.queryItems() )
1038 if ( sParamFilter.contains( param.first.toUpper() ) )
1039 query.removeAllQueryItems( param.first );
1042 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1043 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1046 if ( format == QgsWfsParameters::Format::GML2 )
1047 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1049 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1052 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1054 mapUrl.setQuery( query );
1056 hrefString = mapUrl.toString();
1059 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1063 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1064 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1066 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1067 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1068 fcString +=
"\n timeStamp=\"" + now.toString( Qt::ISODate ) +
"\"";
1069 fcString +=
"\n numberOfFeatures=\"" + QString::number( numberOfFeatures ) +
"\"";
1070 fcString += QLatin1String(
">\n" );
1071 fcString += QStringLiteral(
"</wfs:FeatureCollection>" );
1074 response.
write( fcString.toUtf8() );
1083 std::unique_ptr< QgsRectangle > transformedRect;
1085 if ( format == QgsWfsParameters::Format::GeoJSON )
1087 response.
setHeader(
"Content-Type",
"application/vnd.geo+json; charset=utf-8" );
1097 if ( exportGeom.
transform( transform ) == 0 )
1100 rect = transformedRect.get();
1111 fcString = QStringLiteral(
"{\"type\": \"FeatureCollection\",\n" );
1113 fcString += QLatin1String(
" \"features\": [\n" );
1114 response.
write( fcString.toUtf8() );
1118 if ( format == QgsWfsParameters::Format::GML2 )
1119 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/2.1.2; charset=utf-8" );
1121 response.
setHeader(
"Content-Type",
"text/xml; subtype=gml/3.1.1; charset=utf-8" );
1124 QString hrefString =
serviceUrl( request, project );
1126 QUrl mapUrl( hrefString );
1128 QUrlQuery query( mapUrl );
1129 query.addQueryItem( QStringLiteral(
"SERVICE" ), QStringLiteral(
"WFS" ) );
1131 if ( mWfsParameters.version().isEmpty() )
1134 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.1.0" ) );
1136 query.addQueryItem( QStringLiteral(
"VERSION" ), QStringLiteral(
"1.0.0" ) );
1138 for (
auto param : query.queryItems() )
1140 if ( sParamFilter.contains( param.first.toUpper() ) )
1141 query.removeAllQueryItems( param.first );
1144 query.addQueryItem( QStringLiteral(
"REQUEST" ), QStringLiteral(
"DescribeFeatureType" ) );
1145 query.addQueryItem( QStringLiteral(
"TYPENAME" ), typeNames.join(
',' ) );
1148 if ( format == QgsWfsParameters::Format::GML2 )
1149 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/2.1.2" ) );
1151 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"text/xml; subtype=gml/3.1.1" ) );
1154 query.addQueryItem( QStringLiteral(
"OUTPUTFORMAT" ), QStringLiteral(
"XMLSCHEMA" ) );
1156 mapUrl.setQuery( query );
1158 hrefString = mapUrl.toString();
1161 fcString = QStringLiteral(
"<wfs:FeatureCollection" );
1165 fcString += QLatin1String(
" xmlns:ows=\"http://www.opengis.net/ows\"" );
1166 fcString += QLatin1String(
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" );
1168 fcString += QLatin1String(
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" );
1169 fcString +=
" xsi:schemaLocation=\"" +
WFS_NAMESPACE +
" http://schemas.opengis.net/wfs/1.0.0/wfs.xsd " +
QGS_NAMESPACE +
" " + hrefString.replace( QLatin1String(
"&" ), QLatin1String(
"&" ) ) +
"\"";
1170 fcString += QLatin1String(
">\n" );
1172 response.
write( fcString.toUtf8() );
1176 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1177 if ( format == QgsWfsParameters::Format::GML3 )
1180 if ( !envElem.isNull() )
1184 envElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1186 bbElem.appendChild( envElem );
1187 doc.appendChild( bbElem );
1193 if ( !boxElem.isNull() )
1197 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1199 bbElem.appendChild( boxElem );
1200 doc.appendChild( bbElem );
1203 response.
write( doc.toByteArray() );
1214 if ( format == QgsWfsParameters::Format::GeoJSON )
1218 fcString += QLatin1String(
" " );
1220 fcString += QLatin1String(
" ," );
1221 mJsonExporter.setSourceCrs( params.crs );
1222 mJsonExporter.setIncludeGeometry(
false );
1223 mJsonExporter.setIncludeAttributes( !params.attributeIndexes.isEmpty() );
1224 mJsonExporter.setAttributes( params.attributeIndexes );
1225 fcString += createFeatureGeoJSON( feature, params, pkAttributes );
1226 fcString += QLatin1String(
"\n" );
1228 response.
write( fcString.toUtf8() );
1232 QDomDocument gmlDoc;
1233 QDomElement featureElement;
1234 if ( format == QgsWfsParameters::Format::GML3 )
1236 featureElement = createFeatureGML3( feature, gmlDoc, params, project, pkAttributes );
1237 gmlDoc.appendChild( featureElement );
1241 featureElement = createFeatureGML2( feature, gmlDoc, params, project, pkAttributes );
1242 gmlDoc.appendChild( featureElement );
1244 response.
write( gmlDoc.toByteArray() );
1254 if ( format == QgsWfsParameters::Format::GeoJSON )
1256 fcString += QLatin1String(
" ]\n" );
1257 fcString += QLatin1String(
"}" );
1261 fcString = QStringLiteral(
"</wfs:FeatureCollection>\n" );
1263 response.
write( fcString.toUtf8() );
1267 QString createFeatureGeoJSON(
const QgsFeature &feature,
const createFeatureParams ¶ms,
const QgsAttributeList &pkAttributes )
1277 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1279 mJsonExporter.setIncludeGeometry(
true );
1280 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1285 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1291 return mJsonExporter.exportFeature( f, QVariantMap(),
id );
1295 QDomElement createFeatureGML2(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1298 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1301 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1303 typeNameElement.setAttribute( QStringLiteral(
"fid" ),
id );
1304 featureElement.appendChild( typeNameElement );
1308 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1310 int prec = params.precision;
1316 if ( transformed.
transform( mTransform ) == 0 )
1319 crs = params.outputCrs;
1321 prec = std::min( params.precision + 3, 6 );
1329 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1330 QDomElement gmlElem;
1332 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1336 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1347 gmlElem = abstractGeom->
asGml2( doc, prec,
"http://www.opengis.net/gml" );
1350 if ( !gmlElem.isNull() )
1353 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1358 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1359 gmlElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1362 bbElem.appendChild( boxElem );
1363 typeNameElement.appendChild( bbElem );
1365 geomElem.appendChild( gmlElem );
1366 typeNameElement.appendChild( geomElem );
1373 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1375 int idx = params.attributeIndexes[i];
1376 if ( idx >= fields.
count() )
1382 QString attributeName = field.
name();
1384 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1385 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1386 if ( featureAttributes[idx].isNull() )
1388 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1390 fieldElem.appendChild( fieldText );
1391 typeNameElement.appendChild( fieldElem );
1394 return featureElement;
1397 QDomElement createFeatureGML3(
const QgsFeature &feature, QDomDocument &doc,
const createFeatureParams ¶ms,
const QgsProject *project,
const QgsAttributeList &pkAttributes )
1400 QDomElement featureElement = doc.createElement( QStringLiteral(
"gml:featureMember" ) );
1403 QDomElement typeNameElement = doc.createElement(
"qgs:" + params.typeName );
1405 typeNameElement.setAttribute( QStringLiteral(
"gml:id" ),
id );
1406 featureElement.appendChild( typeNameElement );
1410 if ( !geom.
isNull() && params.withGeom && params.geometryName != QLatin1String(
"NONE" ) )
1412 int prec = params.precision;
1418 if ( transformed.
transform( mTransform ) == 0 )
1421 crs = params.outputCrs;
1423 prec = std::min( params.precision + 3, 6 );
1431 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
1432 QDomElement gmlElem;
1434 if ( params.geometryName == QLatin1String(
"EXTENT" ) )
1438 else if ( params.geometryName == QLatin1String(
"CENTROID" ) )
1449 gmlElem = abstractGeom->
asGml3( doc, prec,
"http://www.opengis.net/gml" );
1452 if ( !gmlElem.isNull() )
1455 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
1460 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1461 gmlElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1464 bbElem.appendChild( boxElem );
1465 typeNameElement.appendChild( bbElem );
1467 geomElem.appendChild( gmlElem );
1468 typeNameElement.appendChild( geomElem );
1475 for (
int i = 0; i < params.attributeIndexes.count(); ++i )
1477 int idx = params.attributeIndexes[i];
1478 if ( idx >= fields.
count() )
1486 QString attributeName = field.
name();
1488 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ).replace(
cleanTagNameRegExp, QString() ) );
1489 QDomText fieldText = doc.createTextNode( encodeValueToText( featureAttributes[idx], setup ) );
1490 if ( featureAttributes[idx].isNull() )
1492 fieldElem.setAttribute( QStringLiteral(
"xsi:nil" ), QStringLiteral(
"true" ) );
1494 fieldElem.appendChild( fieldText );
1495 typeNameElement.appendChild( fieldElem );
1498 return featureElement;
1503 if ( value.isNull() )
1506 if ( setup.
type() == QStringLiteral(
"DateTime" ) )
1509 const QVariantMap config = setup.
config();
1510 const QString fieldFormat = config.value( QStringLiteral(
"field_format" ), fieldFormatter.
defaultFormat( value.type() ) ).toString();
1511 QDateTime date = value.toDateTime();
1513 if ( date.isValid() )
1515 return date.toString( fieldFormat );
1518 else if ( setup.
type() == QStringLiteral(
"Range" ) )
1520 const QVariantMap config = setup.
config();
1521 if ( config.contains( QStringLiteral(
"Precision" ) ) )
1525 int precision( config[ QStringLiteral(
"Precision" ) ].toInt( &ok ) );
1527 return QString::number( value.toDouble(),
'f',
precision );
1531 switch ( value.type() )
1534 case QVariant::UInt:
1535 case QVariant::LongLong:
1536 case QVariant::ULongLong:
1537 case QVariant::Double:
1538 return value.toString();
1540 case QVariant::Bool:
1541 return value.toBool() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" );
1543 case QVariant::StringList:
1544 case QVariant::List:
1550 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1551 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );
1557 case QVariant::String:
1559 QString v = value.toString();
1562 if ( v.indexOf(
'<' ) != -1 || v.indexOf(
'&' ) != -1 )
1563 v.prepend( QStringLiteral(
"<![CDATA[" ) ).append( QStringLiteral(
"]]>" ) );