@@ -67,6 +67,10 @@ namespace QgsWfs
67
67
QDomElement docElem = doc.documentElement ();
68
68
aRequest = parseTransactionRequestBody ( docElem );
69
69
}
70
+ else
71
+ {
72
+ aRequest = parseTransactionParameters ( parameters );
73
+ }
70
74
71
75
int actionCount = aRequest.inserts .size () + aRequest.updates .size () + aRequest.deletes .size ();
72
76
if ( actionCount == 0 )
@@ -741,6 +745,257 @@ namespace QgsWfs
741
745
return featList;
742
746
}
743
747
748
+ transactionRequest parseTransactionParameters ( QgsServerRequest::Parameters parameters )
749
+ {
750
+ if ( !parameters.contains ( QStringLiteral ( " OPERATION" ) ) )
751
+ {
752
+ throw QgsRequestNotWellFormedException ( QStringLiteral ( " OPERATION parameter is mandatory" ) );
753
+ }
754
+ if ( parameters.value ( QStringLiteral ( " OPERATION" ) ).toUpper () != QStringLiteral ( " DELETE" ) )
755
+ {
756
+ throw QgsRequestNotWellFormedException ( QStringLiteral ( " Only DELETE value is defined for OPERATION parameter" ) );
757
+ }
758
+
759
+ // Verifying parameters mutually exclusive
760
+ if ( ( parameters.contains ( QStringLiteral ( " FEATUREID" ) )
761
+ && ( parameters.contains ( QStringLiteral ( " FILTER" ) ) || parameters.contains ( QStringLiteral ( " BBOX" ) ) ) )
762
+ || ( parameters.contains ( QStringLiteral ( " FILTER" ) )
763
+ && ( parameters.contains ( QStringLiteral ( " FEATUREID" ) ) || parameters.contains ( QStringLiteral ( " BBOX" ) ) ) )
764
+ || ( parameters.contains ( QStringLiteral ( " BBOX" ) )
765
+ && ( parameters.contains ( QStringLiteral ( " FEATUREID" ) ) || parameters.contains ( QStringLiteral ( " FILTER" ) ) ) )
766
+ )
767
+ {
768
+ throw QgsRequestNotWellFormedException ( QStringLiteral ( " FEATUREID FILTER and BBOX parameters are mutually exclusive" ) );
769
+ }
770
+
771
+ transactionRequest request;
772
+
773
+ QStringList typeNameList;
774
+ // parse FEATUREID
775
+ if ( parameters.contains ( QStringLiteral ( " FEATUREID" ) ) )
776
+ {
777
+ QStringList fidList = parameters.value ( QStringLiteral ( " FEATUREID" ) ).split ( QStringLiteral ( " ," ) );
778
+
779
+ QMap<QString, QgsFeatureIds> fidsMap;
780
+
781
+ QStringList::const_iterator fidIt = fidList.constBegin ();
782
+ for ( ; fidIt != fidList.constEnd (); ++fidIt )
783
+ {
784
+ // Get FeatureID
785
+ QString fid = *fidIt;
786
+ fid = fid.trimmed ();
787
+ // testing typename in the WFS featureID
788
+ if ( !fid.contains ( QLatin1String ( " ." ) ) )
789
+ {
790
+ throw QgsRequestNotWellFormedException ( QStringLiteral ( " FEATUREID has to have TYPENAME in the values" ) );
791
+ }
792
+
793
+ QString typeName = fid.section ( QStringLiteral ( " ." ), 0 , 0 );
794
+ fid = fid.section ( QStringLiteral ( " ." ), 1 , 1 );
795
+ if ( !typeNameList.contains ( typeName ) )
796
+ {
797
+ typeNameList << typeName;
798
+ }
799
+
800
+ QgsFeatureIds fids;
801
+ if ( fidsMap.contains ( typeName ) )
802
+ {
803
+ fids = fidsMap.value ( typeName );
804
+ }
805
+ fids.insert ( fid.toInt () );
806
+ fidsMap.insert ( typeName, fids );
807
+ }
808
+
809
+ QMap<QString, QgsFeatureIds>::const_iterator fidsMapIt = fidsMap.constBegin ();
810
+ while ( fidsMapIt != fidsMap.constEnd () )
811
+ {
812
+ transactionDelete action;
813
+ action.typeName = fidsMapIt.key ();
814
+
815
+ QgsFeatureIds fids = fidsMapIt.value ();
816
+ action.featureRequest = QgsFeatureRequest ( fids );
817
+
818
+ request.deletes .append ( action );
819
+ }
820
+ return request;
821
+ }
822
+
823
+ if ( !parameters.contains ( QStringLiteral ( " TYPENAME" ) ) )
824
+ {
825
+ throw QgsRequestNotWellFormedException ( QStringLiteral ( " TYPENAME is mandatory except if FEATUREID is used" ) );
826
+ }
827
+
828
+ typeNameList = parameters.value ( QStringLiteral ( " TYPENAME" ) ).split ( QStringLiteral ( " ," ) );
829
+
830
+ // Create actions based on TypeName
831
+ QStringList::const_iterator typeNameIt = typeNameList.constBegin ();
832
+ for ( ; typeNameIt != typeNameList.constEnd (); ++typeNameIt )
833
+ {
834
+ QString typeName = *typeNameIt;
835
+ typeName = typeName.trimmed ();
836
+
837
+ transactionDelete action;
838
+ action.typeName = typeName;
839
+
840
+ request.deletes .append ( action );
841
+ }
842
+
843
+ // Manage extra parameter exp_filter
844
+ if ( parameters.contains ( QStringLiteral ( " EXP_FILTER" ) ) )
845
+ {
846
+ QString expFilterName = parameters.value ( QStringLiteral ( " EXP_FILTER" ) );
847
+ QStringList expFilterList;
848
+ QRegExp rx ( " \\ (([^()]+)\\ )" );
849
+ if ( rx.indexIn ( expFilterName, 0 ) == -1 )
850
+ {
851
+ expFilterList << expFilterName;
852
+ }
853
+ else
854
+ {
855
+ int pos = 0 ;
856
+ while ( ( pos = rx.indexIn ( expFilterName, pos ) ) != -1 )
857
+ {
858
+ expFilterList << rx.cap ( 1 );
859
+ pos += rx.matchedLength ();
860
+ }
861
+ }
862
+
863
+ // Verifying the 1:1 mapping between TYPENAME and EXP_FILTER but without exception
864
+ if ( request.deletes .size () == expFilterList.size () )
865
+ {
866
+ // set feature request filter expression based on filter element
867
+ QList<transactionDelete>::iterator dIt = request.deletes .begin ();
868
+ QStringList::const_iterator expFilterIt = expFilterList.constBegin ();
869
+ for ( ; dIt != request.deletes .end (); ++dIt )
870
+ {
871
+ transactionDelete &action = *dIt;
872
+ // Get Filter for this typeName
873
+ QString expFilter;
874
+ if ( expFilterIt != expFilterList.constEnd () )
875
+ {
876
+ expFilter = *expFilterIt;
877
+ }
878
+ std::shared_ptr<QgsExpression> filter ( new QgsExpression ( expFilter ) );
879
+ if ( filter )
880
+ {
881
+ if ( filter->hasParserError () )
882
+ {
883
+ QgsMessageLog::logMessage ( filter->parserErrorString () );
884
+ }
885
+ else
886
+ {
887
+ if ( filter->needsGeometry () )
888
+ {
889
+ action.featureRequest .setFlags ( QgsFeatureRequest::NoFlags );
890
+ }
891
+ action.featureRequest .setFilterExpression ( filter->expression () );
892
+ }
893
+ }
894
+ }
895
+ }
896
+ else
897
+ {
898
+ QgsMessageLog::logMessage ( " There has to be a 1:1 mapping between each element in a TYPENAME and the EXP_FILTER list" );
899
+ }
900
+ }
901
+
902
+ if ( parameters.contains ( QStringLiteral ( " BBOX" ) ) )
903
+ {
904
+ // get bbox value
905
+ QString bbox = parameters.value ( QStringLiteral ( " BBOX" ) );
906
+ if ( bbox.isEmpty () )
907
+ {
908
+ throw QgsRequestNotWellFormedException ( QStringLiteral ( " BBOX parameter is empty" ) );
909
+ }
910
+
911
+ // get bbox corners
912
+ QStringList corners = bbox.split ( " ," );
913
+ if ( corners.size () != 4 )
914
+ {
915
+ throw QgsRequestNotWellFormedException ( QStringLiteral ( " BBOX has to be composed of 4 elements: '%1'" ).arg ( bbox ) );
916
+ }
917
+
918
+ // convert corners to double
919
+ double d[4 ];
920
+ bool ok;
921
+ for ( int i = 0 ; i < 4 ; i++ )
922
+ {
923
+ corners[i].replace ( QLatin1String ( " " ), QLatin1String ( " +" ) );
924
+ d[i] = corners[i].toDouble ( &ok );
925
+ if ( !ok )
926
+ {
927
+ throw QgsRequestNotWellFormedException ( QStringLiteral ( " BBOX has to be composed of 4 double: '%1'" ).arg ( bbox ) );
928
+ }
929
+ }
930
+ // create extent
931
+ QgsRectangle extent ( d[0 ], d[1 ], d[2 ], d[3 ] );
932
+
933
+ // set feature request filter rectangle
934
+ QList<transactionDelete>::iterator dIt = request.deletes .begin ();
935
+ for ( ; dIt != request.deletes .end (); ++dIt )
936
+ {
937
+ transactionDelete &action = *dIt;
938
+ action.featureRequest .setFilterRect ( extent );
939
+ }
940
+ return request;
941
+ }
942
+ else if ( parameters.contains ( QStringLiteral ( " FILTER" ) ) )
943
+ {
944
+ QString filterName = parameters.value ( QStringLiteral ( " FILTER" ) );
945
+ QStringList filterList;
946
+ QRegExp rx ( " \\ (([^()]+)\\ )" );
947
+ if ( rx.indexIn ( filterName, 0 ) == -1 )
948
+ {
949
+ filterList << filterName;
950
+ }
951
+ else
952
+ {
953
+ int pos = 0 ;
954
+ while ( ( pos = rx.indexIn ( filterName, pos ) ) != -1 )
955
+ {
956
+ filterList << rx.cap ( 1 );
957
+ pos += rx.matchedLength ();
958
+ }
959
+ }
960
+
961
+ // Verifying the 1:1 mapping between TYPENAME and FILTER
962
+ if ( request.deletes .size () != filterList.size () )
963
+ {
964
+ throw QgsRequestNotWellFormedException ( QStringLiteral ( " There has to be a 1:1 mapping between each element in a TYPENAME and the FILTER list" ) );
965
+ }
966
+
967
+ // set feature request filter expression based on filter element
968
+ QList<transactionDelete>::iterator dIt = request.deletes .begin ();
969
+ QStringList::const_iterator filterIt = filterList.constBegin ();
970
+ for ( ; dIt != request.deletes .end (); ++dIt )
971
+ {
972
+ transactionDelete &action = *dIt;
973
+
974
+ // Get Filter for this typeName
975
+ QDomDocument filter;
976
+ if ( filterIt != filterList.constEnd () )
977
+ {
978
+ QString errorMsg;
979
+ if ( !filter.setContent ( *filterIt, true , &errorMsg ) )
980
+ {
981
+ throw QgsRequestNotWellFormedException ( QStringLiteral ( " error message: %1. The XML string was: %2" ).arg ( errorMsg, *filterIt ) );
982
+ }
983
+ }
984
+
985
+ QDomElement filterElem = filter.firstChildElement ();
986
+ action.featureRequest = parseFilterElement ( action.typeName , filterElem );
987
+
988
+ if ( filterIt != filterList.constEnd () )
989
+ {
990
+ ++filterIt;
991
+ }
992
+ }
993
+ return request;
994
+ }
995
+
996
+ return request;
997
+ }
998
+
744
999
transactionRequest parseTransactionRequestBody ( QDomElement &docElem )
745
1000
{
746
1001
transactionRequest request;
0 commit comments