48     void addTransactionResult( QDomDocument &responseDoc, QDomElement &resultsElem,
 
   49                                const QString &locator, 
const QString &message );
 
   60     response.
setHeader( 
"Content-Type", 
"text/xml; charset=utf-8" );
 
   61     response.
write( doc.toByteArray() );
 
   70     transactionRequest aRequest;
 
   75     if ( doc.setContent( request.
data(), 
true, &errorMsg ) )
 
   77       QDomElement docElem = doc.documentElement();
 
   85     int actionCount = aRequest.inserts.size() + aRequest.updates.size() + aRequest.deletes.size();
 
   86     if ( actionCount == 0 )
 
   88       throw QgsRequestNotWellFormedException( QStringLiteral( 
"No actions found" ) );
 
   97     QDomElement respElem = resp.createElement( QStringLiteral( 
"TransactionResponse" ) );
 
   98     respElem.setAttribute( QStringLiteral( 
"xmlns" ), 
WFS_NAMESPACE );
 
   99     respElem.setAttribute( QStringLiteral( 
"xmlns:xsi" ), QStringLiteral( 
"http://www.w3.org/2001/XMLSchema-instance" ) );
 
  100     respElem.setAttribute( QStringLiteral( 
"xsi:schemaLocation" ), 
WFS_NAMESPACE + 
" http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" );
 
  101     respElem.setAttribute( QStringLiteral( 
"xmlns:ogc" ), 
OGC_NAMESPACE );
 
  102     respElem.setAttribute( QStringLiteral( 
"version" ), QStringLiteral( 
"1.1.0" ) );
 
  103     resp.appendChild( respElem );
 
  105     int totalInserted = 0;
 
  106     int totalUpdated = 0;
 
  107     int totalDeleted = 0;
 
  111     QDomElement trsElem = doc.createElement( QStringLiteral( 
"TransactionResults" ) );
 
  114     QDomElement irsElem = doc.createElement( QStringLiteral( 
"InsertResults" ) );
 
  115     QList<transactionInsert>::iterator tiIt = aRequest.inserts.begin();
 
  116     for ( ; tiIt != aRequest.inserts.end(); ++tiIt )
 
  118       transactionInsert &action = *tiIt;
 
  122         QString locator = action.handle;
 
  123         if ( locator.isEmpty() )
 
  125           locator = QStringLiteral( 
"Insert:%1" ).arg( action.typeName );
 
  127         addTransactionResult( resp, trsElem, locator, action.errorMsg );
 
  131         QStringList::const_iterator fidIt = action.insertFeatureIds.constBegin();
 
  132         for ( ; fidIt != action.insertFeatureIds.constEnd(); ++fidIt )
 
  134           QString fidStr = *fidIt;
 
  135           QDomElement irElem = doc.createElement( QStringLiteral( 
"Feature" ) );
 
  136           if ( !action.handle.isEmpty() )
 
  138             irElem.setAttribute( QStringLiteral( 
"handle" ), action.handle );
 
  140           QDomElement fiElem = doc.createElement( QStringLiteral( 
"ogc:FeatureId" ) );
 
  141           fiElem.setAttribute( QStringLiteral( 
"fid" ), fidStr );
 
  142           irElem.appendChild( fiElem );
 
  143           irsElem.appendChild( irElem );
 
  146       totalInserted += action.insertFeatureIds.count();
 
  149     QList<transactionUpdate>::iterator tuIt = aRequest.updates.begin();
 
  150     for ( ; tuIt != aRequest.updates.end(); ++tuIt )
 
  152       transactionUpdate &action = *tuIt;
 
  156         QString locator = action.handle;
 
  157         if ( locator.isEmpty() )
 
  159           locator = QStringLiteral( 
"Update:%1" ).arg( action.typeName );
 
  161         addTransactionResult( resp, trsElem, locator, action.errorMsg );
 
  163       totalUpdated += action.totalUpdated;
 
  166     QList<transactionDelete>::iterator tdIt = aRequest.deletes.begin();
 
  167     for ( ; tdIt != aRequest.deletes.end(); ++tdIt )
 
  169       transactionDelete &action = *tdIt;
 
  173         QString locator = action.handle;
 
  174         if ( locator.isEmpty() )
 
  176           locator = QStringLiteral( 
"Delete:%1" ).arg( action.typeName );
 
  178         addTransactionResult( resp, trsElem, locator, action.errorMsg );
 
  180       totalDeleted += action.totalDeleted;
 
  184     QDomElement summaryElem = doc.createElement( QStringLiteral( 
"TransactionSummary" ) );
 
  185     if ( aRequest.inserts.size() > 0 )
 
  187       QDomElement totalInsertedElem = doc.createElement( QStringLiteral( 
"totalInserted" ) );
 
  188       totalInsertedElem.appendChild( doc.createTextNode( QString::number( totalInserted ) ) );
 
  189       summaryElem.appendChild( totalInsertedElem );
 
  191     if ( aRequest.updates.size() > 0 )
 
  193       QDomElement totalUpdatedElem = doc.createElement( QStringLiteral( 
"totalUpdated" ) );
 
  194       totalUpdatedElem.appendChild( doc.createTextNode( QString::number( totalUpdated ) ) );
 
  195       summaryElem.appendChild( totalUpdatedElem );
 
  197     if ( aRequest.deletes.size() > 0 )
 
  199       QDomElement totalDeletedElem = doc.createElement( QStringLiteral( 
"totalDeleted" ) );
 
  200       totalDeletedElem.appendChild( doc.createTextNode( QString::number( totalDeleted ) ) );
 
  201       summaryElem.appendChild( totalDeletedElem );
 
  203     respElem.appendChild( summaryElem );
 
  206     if ( errorCount > 0 && trsElem.hasChildNodes() )
 
  208       respElem.appendChild( trsElem );
 
  212     if ( aRequest.inserts.size() > 0 && irsElem.hasChildNodes() )
 
  214       respElem.appendChild( irsElem );
 
  221 #ifndef HAVE_SERVER_PYTHON_PLUGINS 
  225     QStringList typeNameList;
 
  227     QList<transactionInsert>::iterator tiIt = aRequest.inserts.begin();
 
  228     for ( ; tiIt != aRequest.inserts.end(); ++tiIt )
 
  230       QString name = ( *tiIt ).typeName;
 
  231       if ( !typeNameList.contains( name ) )
 
  232         typeNameList << name;
 
  234     QList<transactionUpdate>::iterator tuIt = aRequest.updates.begin();
 
  235     for ( ; tuIt != aRequest.updates.end(); ++tuIt )
 
  237       QString name = ( *tuIt ).typeName;
 
  238       if ( !typeNameList.contains( name ) )
 
  239         typeNameList << name;
 
  241     QList<transactionDelete>::iterator tdIt = aRequest.deletes.begin();
 
  242     for ( ; tdIt != aRequest.deletes.end(); ++tdIt )
 
  244       QString name = ( *tdIt ).typeName;
 
  245       if ( !typeNameList.contains( name ) )
 
  246         typeNameList << name;
 
  249 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  263     QMap<QString, QgsVectorLayer *> mapLayerMap;
 
  278       if ( !typeNameList.contains( name ) )
 
  287         throw QgsRequestNotWellFormedException( QStringLiteral( 
"Layer error on '%1'" ).arg( name ) );
 
  294         throw QgsRequestNotWellFormedException( QStringLiteral( 
"Provider error on layer '%1'" ).arg( name ) );
 
  302         throw QgsRequestNotWellFormedException( QStringLiteral( 
"No capabilities to do WFS changes on layer '%1'" ).arg( name ) );
 
  309         throw QgsSecurityAccessException( QStringLiteral( 
"No permissions to do WFS changes on layer '%1'" ).arg( name ) );
 
  311 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  315         throw QgsSecurityAccessException( QStringLiteral( 
"No permissions to do WFS changes on layer '%1'" ).arg( name ) );
 
  324       mapLayerMap[name] = vlayer;
 
  328     tuIt = aRequest.updates.begin();
 
  329     for ( ; tuIt != aRequest.updates.end(); ++tuIt )
 
  331       transactionUpdate &action = *tuIt;
 
  334       if ( !mapLayerMap.keys().contains( 
typeName ) )
 
  337         action.errorMsg = QStringLiteral( 
"TypeName '%1' unknown" ).arg( 
typeName );
 
  348         action.errorMsg = QStringLiteral( 
"No permissions to do WFS updates on layer '%1'" ).arg( 
typeName );
 
  351 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  355         action.errorMsg = QStringLiteral( 
"No permissions to do WFS updates on layer '%1'" ).arg( 
typeName );
 
  367         action.errorMsg = QStringLiteral( 
"No capabilities to do WFS updates on layer '%1'" ).arg( 
typeName );
 
  384       if ( !action.serverFids.isEmpty() )
 
  390 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  399       int totalUpdated = 0;
 
  401       QMap<QString, QString> propertyMap = action.propertyMap;
 
  402       QDomElement geometryElem = action.geometryElement;
 
  405       const QMap<QString, int> fieldMap = provider->
fieldNameMap();
 
  406       QMap<QString, int>::const_iterator fieldMapIt;
 
  408       bool conversionSuccess;
 
  412 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  413         if ( accessControl && !accessControl->
allowToEdit( vlayer, feature ) )
 
  416           action.errorMsg = QStringLiteral( 
"Feature modify permission denied on layer '%1'" ).arg( 
typeName );
 
  421         QMap< QString, QString >::const_iterator it = propertyMap.constBegin();
 
  422         for ( ; it != propertyMap.constEnd(); ++it )
 
  424           fieldName = it.key();
 
  425           fieldMapIt = fieldMap.find( fieldName );
 
  426           if ( fieldMapIt == fieldMap.constEnd() )
 
  431           QVariant value = it.value();
 
  432           if ( value.isNull() )
 
  437               action.errorMsg = QStringLiteral( 
"NOT NULL constraint error on layer '%1', field '%2'" ).arg( 
typeName, 
field.
name() );
 
  444             if ( 
field.
type() == QVariant::Type::Int )
 
  446               value = it.value().toInt( &conversionSuccess );
 
  447               if ( !conversionSuccess )
 
  450                 action.errorMsg = QStringLiteral( 
"Property conversion error on layer '%1'" ).arg( 
typeName );
 
  455             else if ( 
field.
type() == QVariant::Type::Double )
 
  457               value = it.value().toDouble( &conversionSuccess );
 
  458               if ( !conversionSuccess )
 
  461                 action.errorMsg = QStringLiteral( 
"Property conversion error on layer '%1'" ).arg( 
typeName );
 
  466             else if ( 
field.
type() == QVariant::Type::LongLong )
 
  468               value = it.value().toLongLong( &conversionSuccess );
 
  469               if ( !conversionSuccess )
 
  472                 action.errorMsg = QStringLiteral( 
"Property conversion error on layer '%1'" ).arg( 
typeName );
 
  485         if ( !geometryElem.isNull() )
 
  491             action.errorMsg = QStringLiteral( 
"Geometry from GML error on layer '%1'" ).arg( 
typeName );
 
  498             action.errorMsg = QStringLiteral( 
"Error in change geometry on layer '%1'" ).arg( 
typeName );
 
  509 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  516           if ( accessControl && !accessControl->
allowToEdit( vlayer, feature ) )
 
  519             action.errorMsg = QStringLiteral( 
"Feature modify permission denied on layer '%1'" ).arg( 
typeName );
 
  535         action.errorMsg = QStringLiteral( 
"Error committing updates: %1" ).arg( vlayer->
commitErrors().join( QLatin1String( 
"; " ) ) );
 
  540       action.totalUpdated = totalUpdated;
 
  541       action.error = 
false;
 
  546     tdIt = aRequest.deletes.begin();
 
  547     for ( ; tdIt != aRequest.deletes.end(); ++tdIt )
 
  549       transactionDelete &action = *tdIt;
 
  552       if ( !mapLayerMap.keys().contains( 
typeName ) )
 
  555         action.errorMsg = QStringLiteral( 
"TypeName '%1' unknown" ).arg( 
typeName );
 
  566         action.errorMsg = QStringLiteral( 
"No permissions to do WFS deletes on layer '%1'" ).arg( 
typeName );
 
  569 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  573         action.errorMsg = QStringLiteral( 
"No permissions to do WFS deletes on layer '%1'" ).arg( 
typeName );
 
  585         action.errorMsg = QStringLiteral( 
"No capabilities to do WFS deletes on layer '%1'" ).arg( 
typeName );
 
  602       if ( action.serverFids.isEmpty() )
 
  605         action.errorMsg = QStringLiteral( 
"No feature ids to do WFS deletes on layer '%1'" ).arg( 
typeName );
 
  612 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  626 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  627         if ( accessControl && !accessControl->
allowToEdit( vlayer, feature ) )
 
  630           action.errorMsg = QStringLiteral( 
"Feature modify permission denied" );
 
  635         fids << feature.
id();
 
  645         action.errorMsg = QStringLiteral( 
"Delete features failed on layer '%1'" ).arg( 
typeName );
 
  654         action.errorMsg = QStringLiteral( 
"Error committing deletes: %1" ).arg( vlayer->
commitErrors().join( QLatin1String( 
"; " ) ) );
 
  659       action.totalDeleted = fids.count();
 
  660       action.error = 
false;
 
  664     tiIt = aRequest.inserts.begin();
 
  665     for ( ; tiIt != aRequest.inserts.end(); ++tiIt )
 
  667       transactionInsert &action = *tiIt;
 
  670       if ( !mapLayerMap.keys().contains( 
typeName ) )
 
  673         action.errorMsg = QStringLiteral( 
"TypeName '%1' unknown" ).arg( 
typeName );
 
  684         action.errorMsg = QStringLiteral( 
"No permissions to do WFS inserts on layer '%1'" ).arg( 
typeName );
 
  687 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  691         action.errorMsg = QStringLiteral( 
"No permissions to do WFS inserts on layer '%1'" ).arg( 
typeName );
 
  703         action.errorMsg = QStringLiteral( 
"No capabilities to do WFS inserts on layer '%1'" ).arg( 
typeName );
 
  719         action.errorMsg = QStringLiteral( 
"%1 '%2'" ).arg( ex.
message(), 
typeName );
 
  723       if ( featureList.empty() )
 
  726         action.errorMsg = QStringLiteral( 
"No features to insert in layer '%1'" ).arg( 
typeName );
 
  730 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  734         QgsFeatureList::iterator featureIt = featureList.begin();
 
  735         while ( featureIt != featureList.end() )
 
  737           if ( !accessControl->
allowToEdit( vlayer, *featureIt ) )
 
  740             action.errorMsg = QStringLiteral( 
"Feature modify permission denied on layer '%1'" ).arg( 
typeName );
 
  757         action.errorMsg = QStringLiteral( 
"Insert features failed on layer '%1'" ).arg( 
typeName );
 
  758         if ( provider ->hasErrors() )
 
  770         action.errorMsg = QStringLiteral( 
"Error committing inserts: %1" ).arg( vlayer->
commitErrors().join( QLatin1String( 
"; " ) ) );
 
  775       action.error = 
false;
 
  779       for ( 
const QgsFeature &feat : std::as_const( featureList ) )
 
  786     filterRestorer.reset();
 
  798     const QMap<QString, int> fieldMap = provider->
fieldNameMap();
 
  799     QMap<QString, int>::const_iterator fieldMapIt;
 
  801     for ( 
int i = 0; i < featureNodeList.count(); i++ )
 
  805       QDomElement featureElem = featureNodeList.at( i ).toElement();
 
  806       QDomNode currentAttributeChild = featureElem.firstChild();
 
  807       bool conversionSuccess = 
true;
 
  809       while ( !currentAttributeChild.isNull() )
 
  811         QDomElement currentAttributeElement = currentAttributeChild.toElement();
 
  812         QString attrName = currentAttributeElement.localName();
 
  814         if ( attrName != QLatin1String( 
"boundedBy" ) )
 
  816           if ( attrName != QLatin1String( 
"geometry" ) ) 
 
  818             fieldMapIt = fieldMap.find( attrName );
 
  819             if ( fieldMapIt == fieldMap.constEnd() )
 
  825             QString attrValue = currentAttributeElement.text();
 
  828             QgsMessageLog::logMessage( QStringLiteral( 
"attr: name=%1 idx=%2 value=%3" ).arg( attrName ).arg( fieldMapIt.value() ).arg( attrValue ) );
 
  830             if ( attrType == QVariant::Int )
 
  831               feat.setAttribute( fieldMapIt.value(), attrValue.toInt( &conversionSuccess ) );
 
  832             else if ( attrType == QVariant::Double )
 
  833               feat.setAttribute( fieldMapIt.value(), attrValue.toDouble( &conversionSuccess ) );
 
  835               feat.setAttribute( fieldMapIt.value(), attrValue );
 
  837             if ( !conversionSuccess )
 
  850             feat.setGeometry( g );
 
  853         currentAttributeChild = currentAttributeChild.nextSibling();
 
  863     if ( !parameters.contains( QStringLiteral( 
"OPERATION" ) ) )
 
  865       throw QgsRequestNotWellFormedException( QStringLiteral( 
"OPERATION parameter is mandatory" ) );
 
  867     if ( parameters.value( QStringLiteral( 
"OPERATION" ) ).toUpper() != QLatin1String( 
"DELETE" ) )
 
  869       throw QgsRequestNotWellFormedException( QStringLiteral( 
"Only DELETE value is defined for OPERATION parameter" ) );
 
  873     if ( ( parameters.contains( QStringLiteral( 
"FEATUREID" ) )
 
  874            && ( parameters.contains( QStringLiteral( 
"FILTER" ) ) || parameters.contains( QStringLiteral( 
"BBOX" ) ) ) )
 
  875          || ( parameters.contains( QStringLiteral( 
"FILTER" ) )
 
  876               && ( parameters.contains( QStringLiteral( 
"FEATUREID" ) ) || parameters.contains( QStringLiteral( 
"BBOX" ) ) ) )
 
  877          || ( parameters.contains( QStringLiteral( 
"BBOX" ) )
 
  878               && ( parameters.contains( QStringLiteral( 
"FEATUREID" ) ) || parameters.contains( QStringLiteral( 
"FILTER" ) ) ) )
 
  884     transactionRequest request;
 
  886     QStringList typeNameList;
 
  888     if ( parameters.contains( QStringLiteral( 
"FEATUREID" ) ) )
 
  890       QStringList fidList = parameters.value( QStringLiteral( 
"FEATUREID" ) ).split( 
',' );
 
  892       QMap<QString, QStringList> fidsMap;
 
  894       QStringList::const_iterator fidIt = fidList.constBegin();
 
  895       for ( ; fidIt != fidList.constEnd(); ++fidIt )
 
  898         QString fid = *fidIt;
 
  901         if ( !fid.contains( 
'.' ) )
 
  903           throw QgsRequestNotWellFormedException( QStringLiteral( 
"FEATUREID has to have TYPENAME in the values" ) );
 
  906         QString 
typeName = fid.section( 
'.', 0, 0 );
 
  907         fid = fid.section( 
'.', 1, 1 );
 
  908         if ( !typeNameList.contains( 
typeName ) )
 
  922       QMap<QString, QStringList>::const_iterator fidsMapIt = fidsMap.constBegin();
 
  923       while ( fidsMapIt != fidsMap.constEnd() )
 
  925         transactionDelete action;
 
  926         action.typeName = fidsMapIt.key();
 
  928         action.serverFids = fidsMapIt.value();
 
  931         request.deletes.append( action );
 
  936     if ( !parameters.contains( QStringLiteral( 
"TYPENAME" ) ) )
 
  938       throw QgsRequestNotWellFormedException( QStringLiteral( 
"TYPENAME is mandatory except if FEATUREID is used" ) );
 
  941     typeNameList = parameters.value( QStringLiteral( 
"TYPENAME" ) ).split( 
',' );
 
  944     QStringList::const_iterator typeNameIt = typeNameList.constBegin();
 
  945     for ( ; typeNameIt != typeNameList.constEnd(); ++typeNameIt )
 
  950       transactionDelete action;
 
  953       request.deletes.append( action );
 
  957     if ( parameters.contains( QStringLiteral( 
"EXP_FILTER" ) ) )
 
  959       QString expFilterName = parameters.value( QStringLiteral( 
"EXP_FILTER" ) );
 
  960       QStringList expFilterList;
 
  961       QRegExp rx( 
"\\(([^()]+)\\)" );
 
  962       if ( rx.indexIn( expFilterName, 0 ) == -1 )
 
  964         expFilterList << expFilterName;
 
  969         while ( ( pos = rx.indexIn( expFilterName, pos ) ) != -1 )
 
  971           expFilterList << rx.cap( 1 );
 
  972           pos += rx.matchedLength();
 
  977       if ( request.deletes.size() == expFilterList.size() )
 
  980         QList<transactionDelete>::iterator dIt = request.deletes.begin();
 
  981         QStringList::const_iterator expFilterIt = expFilterList.constBegin();
 
  982         for ( ; dIt != request.deletes.end(); ++dIt )
 
  984           transactionDelete &action = *dIt;
 
  987           if ( expFilterIt != expFilterList.constEnd() )
 
  989             expFilter = *expFilterIt;
 
  991           std::shared_ptr<QgsExpression> filter( 
new QgsExpression( expFilter ) );
 
  994             if ( filter->hasParserError() )
 
 1000               if ( filter->needsGeometry() )
 
 1004               action.featureRequest.setFilterExpression( filter->expression() );
 
 1011         QgsMessageLog::logMessage( 
"There has to be a 1:1 mapping between each element in a TYPENAME and the EXP_FILTER list" );
 
 1015     if ( parameters.contains( QStringLiteral( 
"BBOX" ) ) )
 
 1018       QString bbox = parameters.value( QStringLiteral( 
"BBOX" ) );
 
 1019       if ( bbox.isEmpty() )
 
 1021         throw QgsRequestNotWellFormedException( QStringLiteral( 
"BBOX parameter is empty" ) );
 
 1025       QStringList corners = bbox.split( 
',' );
 
 1026       if ( corners.size() != 4 )
 
 1028         throw QgsRequestNotWellFormedException( QStringLiteral( 
"BBOX has to be composed of 4 elements: '%1'" ).arg( bbox ) );
 
 1034       for ( 
int i = 0; i < 4; i++ )
 
 1036         corners[i].replace( 
' ', 
'+' );
 
 1037         d[i] = corners[i].toDouble( &ok );
 
 1040           throw QgsRequestNotWellFormedException( QStringLiteral( 
"BBOX has to be composed of 4 double: '%1'" ).arg( bbox ) );
 
 1047       QList<transactionDelete>::iterator dIt = request.deletes.begin();
 
 1048       for ( ; dIt != request.deletes.end(); ++dIt )
 
 1050         transactionDelete &action = *dIt;
 
 1051         action.featureRequest.setFilterRect( extent );
 
 1055     else if ( parameters.contains( QStringLiteral( 
"FILTER" ) ) )
 
 1057       QString filterName = parameters.value( QStringLiteral( 
"FILTER" ) );
 
 1058       QStringList filterList;
 
 1059       QRegExp rx( 
"\\(([^()]+)\\)" );
 
 1060       if ( rx.indexIn( filterName, 0 ) == -1 )
 
 1062         filterList << filterName;
 
 1067         while ( ( pos = rx.indexIn( filterName, pos ) ) != -1 )
 
 1069           filterList << rx.cap( 1 );
 
 1070           pos += rx.matchedLength();
 
 1075       if ( request.deletes.size() != filterList.size() )
 
 1077         throw QgsRequestNotWellFormedException( QStringLiteral( 
"There has to be a 1:1 mapping between each element in a TYPENAME and the FILTER list" ) );
 
 1081       QList<transactionDelete>::iterator dIt = request.deletes.begin();
 
 1082       QStringList::const_iterator filterIt = filterList.constBegin();
 
 1083       for ( ; dIt != request.deletes.end(); ++dIt )
 
 1085         transactionDelete &action = *dIt;
 
 1088         QDomDocument filter;
 
 1089         if ( filterIt != filterList.constEnd() )
 
 1092           if ( !filter.setContent( *filterIt, 
true, &errorMsg ) )
 
 1094             throw QgsRequestNotWellFormedException( QStringLiteral( 
"error message: %1. The XML string was: %2" ).arg( errorMsg, *filterIt ) );
 
 1098         QDomElement filterElem = filter.firstChildElement();
 
 1099         QStringList serverFids;
 
 1100         action.featureRequest = 
parseFilterElement( action.typeName, filterElem, serverFids, project );
 
 1101         action.serverFids = serverFids;
 
 1103         if ( filterIt != filterList.constEnd() )
 
 1116     transactionRequest request;
 
 1118     QDomNodeList docChildNodes = docElem.childNodes();
 
 1120     QDomElement actionElem;
 
 1123     for ( 
int i = docChildNodes.count(); 0 < i; --i )
 
 1125       actionElem = docChildNodes.at( i - 1 ).toElement();
 
 1126       actionName = actionElem.localName();
 
 1128       if ( actionName == QLatin1String( 
"Insert" ) )
 
 1131         request.inserts.append( action );
 
 1133       else if ( actionName == QLatin1String( 
"Update" ) )
 
 1136         request.updates.append( action );
 
 1138       else if ( actionName == QLatin1String( 
"Delete" ) )
 
 1141         request.deletes.append( action );
 
 1150     QString 
typeName = actionElem.attribute( QStringLiteral( 
"typeName" ) );
 
 1154     QDomElement filterElem = actionElem.firstChild().toElement();
 
 1155     if ( filterElem.tagName() != QLatin1String( 
"Filter" ) )
 
 1157       throw QgsRequestNotWellFormedException( QStringLiteral( 
"Delete action element first child is not Filter" ) );
 
 1160     QStringList serverFids;
 
 1163     transactionDelete action;
 
 1165     action.featureRequest = featureRequest;
 
 1166     action.serverFids = serverFids;
 
 1167     action.error = 
false;
 
 1169     if ( actionElem.hasAttribute( QStringLiteral( 
"handle" ) ) )
 
 1171       action.handle = actionElem.attribute( QStringLiteral( 
"handle" ) );
 
 1179     QgsMessageLog::logMessage( QStringLiteral( 
"parseUpdateActionElement" ), QStringLiteral( 
"Server" ), Qgis::MessageLevel::Info );
 
 1180     QString 
typeName = actionElem.attribute( QStringLiteral( 
"typeName" ) );
 
 1184     QDomNodeList propertyNodeList = actionElem.elementsByTagName( QStringLiteral( 
"Property" ) );
 
 1185     if ( propertyNodeList.isEmpty() )
 
 1187       throw QgsRequestNotWellFormedException( QStringLiteral( 
"Update action element must have one or more Property element" ) );
 
 1190     QMap<QString, QString> propertyMap;
 
 1191     QDomElement propertyElem;
 
 1192     QDomElement nameElem;
 
 1193     QDomElement valueElem;
 
 1194     QDomElement geometryElem;
 
 1196     for ( 
int l = 0; l < propertyNodeList.count(); ++l )
 
 1198       propertyElem = propertyNodeList.at( l ).toElement();
 
 1199       nameElem = propertyElem.elementsByTagName( QStringLiteral( 
"Name" ) ).at( 0 ).toElement();
 
 1200       valueElem = propertyElem.elementsByTagName( QStringLiteral( 
"Value" ) ).at( 0 ).toElement();
 
 1201       if ( nameElem.text() != QLatin1String( 
"geometry" ) )
 
 1203         propertyMap.insert( nameElem.text(), valueElem.text() );
 
 1207         geometryElem = valueElem;
 
 1211     QDomNodeList filterNodeList = actionElem.elementsByTagName( QStringLiteral( 
"Filter" ) );
 
 1213     QStringList serverFids;
 
 1214     if ( filterNodeList.size() != 0 )
 
 1216       QDomElement filterElem = filterNodeList.at( 0 ).toElement();
 
 1219     QgsMessageLog::logMessage( QStringLiteral( 
"parseUpdateActionElement: serverFids length %1" ).arg( serverFids.count() ), QStringLiteral( 
"Server" ), Qgis::MessageLevel::Info );
 
 1221     transactionUpdate action;
 
 1223     action.propertyMap = propertyMap;
 
 1224     action.geometryElement = geometryElem;
 
 1225     action.featureRequest = featureRequest;
 
 1226     action.serverFids = serverFids;
 
 1227     action.error = 
false;
 
 1229     if ( actionElem.hasAttribute( QStringLiteral( 
"handle" ) ) )
 
 1231       action.handle = actionElem.attribute( QStringLiteral( 
"handle" ) );
 
 1239     QDomNodeList featureNodeList = actionElem.childNodes();
 
 1240     if ( featureNodeList.size() != 1 )
 
 1242       throw QgsRequestNotWellFormedException( QStringLiteral( 
"Insert action element must have one or more child node" ) );
 
 1246     for ( 
int i = 0; i < featureNodeList.count(); ++i )
 
 1248       QString tempTypeName = featureNodeList.at( i ).toElement().localName();
 
 1249       if ( tempTypeName.contains( 
':' ) )
 
 1250         tempTypeName = tempTypeName.section( 
':', 1, 1 );
 
 1256       else if ( tempTypeName != 
typeName )
 
 1258         throw QgsRequestNotWellFormedException( QStringLiteral( 
"Insert action element must have one typename features" ) );
 
 1262     transactionInsert action;
 
 1264     action.featureNodeList = featureNodeList;
 
 1265     action.error = 
false;
 
 1267     if ( actionElem.hasAttribute( QStringLiteral( 
"handle" ) ) )
 
 1269       action.handle = actionElem.attribute( QStringLiteral( 
"handle" ) );
 
 1278     void addTransactionResult( QDomDocument &responseDoc, QDomElement &resultsElem,
 
 1279                                const QString &locator, 
const QString &message )
 
 1281       QDomElement trElem = responseDoc.createElement( QStringLiteral( 
"Action" ) );
 
 1282       resultsElem.appendChild( trElem );
 
 1284       if ( !locator.isEmpty() )
 
 1286         trElem.setAttribute( QStringLiteral( 
"locator" ), locator );
 
 1289       if ( !message.isEmpty() )
 
 1291         QDomElement mesElem = responseDoc.createElement( QStringLiteral( 
"Message" ) );
 
 1292         mesElem.appendChild( responseDoc.createTextNode( message ) );
 
 1293         trElem.appendChild( mesElem );