30 #include <QStringList> 
   31 #include <QTextStream> 
   35 #include <netinet/in.h> 
   41 #define GML_NAMESPACE QStringLiteral( "http://www.opengis.net/gml" ) 
   42 #define GML32_NAMESPACE QStringLiteral( "http://www.opengis.net/gml/3.2" ) 
   43 #define OGC_NAMESPACE QStringLiteral( "http://www.opengis.net/ogc" ) 
   44 #define FES_NAMESPACE QStringLiteral( "http://www.opengis.net/fes/2.0" ) 
   50     const QString &srsName,
 
   51     bool honourAxisOrientation,
 
   52     bool invertAxisOrientation )
 
   55   , mGMLVersion( gmlVersion )
 
   56   , mFilterVersion( filterVersion )
 
   59   , mInvertAxisOrientation( invertAxisOrientation )
 
   60   , mFilterPrefix( ( filterVersion == 
QgsOgcUtils::FILTER_FES_2_0 ) ? 
"fes" : 
"ogc" )
 
   61   , mPropertyName( ( filterVersion == 
QgsOgcUtils::FILTER_FES_2_0 ) ? 
"ValueReference" : 
"PropertyName" )
 
   65   if ( !mSrsName.isEmpty() )
 
   71       mInvertAxisOrientation = !mInvertAxisOrientation;
 
   78   QDomElement geometryTypeElement = geometryNode.toElement();
 
   79   QString geomType = geometryTypeElement.tagName();
 
   82   if ( !( geomType == QLatin1String( 
"Point" ) || geomType == QLatin1String( 
"LineString" ) || geomType == QLatin1String( 
"Polygon" ) ||
 
   83           geomType == QLatin1String( 
"MultiPoint" ) || geomType == QLatin1String( 
"MultiLineString" ) || geomType == QLatin1String( 
"MultiPolygon" ) ||
 
   84           geomType == QLatin1String( 
"Box" ) || geomType == QLatin1String( 
"Envelope" ) ) )
 
   86     QDomNode geometryChild = geometryNode.firstChild();
 
   87     if ( geometryChild.isNull() )
 
   91     geometryTypeElement = geometryChild.toElement();
 
   92     geomType = geometryTypeElement.tagName();
 
   95   if ( !( geomType == QLatin1String( 
"Point" ) || geomType == QLatin1String( 
"LineString" ) || geomType == QLatin1String( 
"Polygon" ) ||
 
   96           geomType == QLatin1String( 
"MultiPoint" ) || geomType == QLatin1String( 
"MultiLineString" ) || geomType == QLatin1String( 
"MultiPolygon" ) ||
 
   97           geomType == QLatin1String( 
"Box" ) || geomType == QLatin1String( 
"Envelope" ) ) )
 
  100   if ( geomType == QLatin1String( 
"Point" ) )
 
  102     geometry = geometryFromGMLPoint( geometryTypeElement );
 
  104   else if ( geomType == QLatin1String( 
"LineString" ) )
 
  106     geometry = geometryFromGMLLineString( geometryTypeElement );
 
  108   else if ( geomType == QLatin1String( 
"Polygon" ) )
 
  110     geometry = geometryFromGMLPolygon( geometryTypeElement );
 
  112   else if ( geomType == QLatin1String( 
"MultiPoint" ) )
 
  114     geometry = geometryFromGMLMultiPoint( geometryTypeElement );
 
  116   else if ( geomType == QLatin1String( 
"MultiLineString" ) )
 
  118     geometry = geometryFromGMLMultiLineString( geometryTypeElement );
 
  120   else if ( geomType == QLatin1String( 
"MultiPolygon" ) )
 
  122     geometry = geometryFromGMLMultiPolygon( geometryTypeElement );
 
  124   else if ( geomType == QLatin1String( 
"Box" ) )
 
  128   else if ( geomType == QLatin1String( 
"Envelope" ) )
 
  142     if ( geometryTypeElement.hasAttribute( QStringLiteral( 
"srsName" ) ) )
 
  144       geomSrs.
createFromString( geometryTypeElement.attribute( QStringLiteral( 
"srsName" ) ) );
 
  151           if ( result != QgsGeometry::OperationResult::Success )
 
  153             QgsDebugMsgLevel( QStringLiteral( 
"Error transforming geometry: %1" ).arg( result ), 2 );
 
  170   QString xml = QStringLiteral( 
"<tmp xmlns=\"%1\" xmlns:gml=\"%1\">%2</tmp>" ).arg( 
GML_NAMESPACE, xmlString );
 
  172   if ( !doc.setContent( xml, 
true ) )
 
  175   return geometryFromGML( doc.documentElement().firstChildElement(), context );
 
  179 QgsGeometry QgsOgcUtils::geometryFromGMLPoint( 
const QDomElement &geometryElement )
 
  183   QDomNodeList coordList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  184   if ( !coordList.isEmpty() )
 
  186     QDomElement coordElement = coordList.at( 0 ).toElement();
 
  187     if ( readGMLCoordinates( pointCoordinate, coordElement ) != 0 )
 
  194     QDomNodeList posList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"pos" ) );
 
  195     if ( posList.size() < 1 )
 
  199     QDomElement posElement = posList.at( 0 ).toElement();
 
  200     if ( readGMLPositions( pointCoordinate, posElement ) != 0 )
 
  206   if ( pointCoordinate.empty() )
 
  211   QgsPolylineXY::const_iterator point_it = pointCoordinate.constBegin();
 
  212   char e = htonl( 1 ) != 1;
 
  213   double x = point_it->x();
 
  214   double y = point_it->y();
 
  215   int size = 1 + 
sizeof( int ) + 2 * 
sizeof( 
double );
 
  218   unsigned char *wkb = 
new unsigned char[size];
 
  221   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  223   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  224   wkbPosition += 
sizeof( int );
 
  225   memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  226   wkbPosition += 
sizeof( double );
 
  227   memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  234 QgsGeometry QgsOgcUtils::geometryFromGMLLineString( 
const QDomElement &geometryElement )
 
  238   QDomNodeList coordList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  239   if ( !coordList.isEmpty() )
 
  241     QDomElement coordElement = coordList.at( 0 ).toElement();
 
  242     if ( readGMLCoordinates( lineCoordinates, coordElement ) != 0 )
 
  249     QDomNodeList posList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"posList" ) );
 
  250     if ( posList.size() < 1 )
 
  254     QDomElement posElement = posList.at( 0 ).toElement();
 
  255     if ( readGMLPositions( lineCoordinates, posElement ) != 0 )
 
  261   char e = htonl( 1 ) != 1;
 
  262   int size = 1 + 2 * 
sizeof( int ) + lineCoordinates.size() * 2 * 
sizeof( double );
 
  265   unsigned char *wkb = 
new unsigned char[size];
 
  269   int nPoints = lineCoordinates.size();
 
  272   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  274   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  275   wkbPosition += 
sizeof( int );
 
  276   memcpy( &( wkb )[wkbPosition], &nPoints, 
sizeof( 
int ) );
 
  277   wkbPosition += 
sizeof( int );
 
  279   QgsPolylineXY::const_iterator iter;
 
  280   for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
 
  284     memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  285     wkbPosition += 
sizeof( double );
 
  286     memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  287     wkbPosition += 
sizeof( double );
 
  295 QgsGeometry QgsOgcUtils::geometryFromGMLPolygon( 
const QDomElement &geometryElement )
 
  302   QDomNodeList outerBoundaryList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"outerBoundaryIs" ) );
 
  303   if ( !outerBoundaryList.isEmpty() ) 
 
  305     QDomElement coordinatesElement = outerBoundaryList.at( 0 ).firstChild().firstChild().toElement();
 
  306     if ( coordinatesElement.isNull() )
 
  310     if ( readGMLCoordinates( exteriorPointList, coordinatesElement ) != 0 )
 
  314     ringCoordinates.push_back( exteriorPointList );
 
  317     QDomNodeList innerBoundaryList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"innerBoundaryIs" ) );
 
  318     for ( 
int i = 0; i < innerBoundaryList.size(); ++i )
 
  321       coordinatesElement = innerBoundaryList.at( i ).firstChild().firstChild().toElement();
 
  322       if ( coordinatesElement.isNull() )
 
  326       if ( readGMLCoordinates( interiorPointList, coordinatesElement ) != 0 )
 
  330       ringCoordinates.push_back( interiorPointList );
 
  336     QDomNodeList exteriorList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"exterior" ) );
 
  337     if ( exteriorList.size() < 1 ) 
 
  341     QDomElement posElement = exteriorList.at( 0 ).firstChild().firstChild().toElement();
 
  342     if ( posElement.isNull() )
 
  346     if ( readGMLPositions( exteriorPointList, posElement ) != 0 )
 
  350     ringCoordinates.push_back( exteriorPointList );
 
  353     QDomNodeList interiorList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"interior" ) );
 
  354     for ( 
int i = 0; i < interiorList.size(); ++i )
 
  357       QDomElement posElement = interiorList.at( i ).firstChild().firstChild().toElement();
 
  358       if ( posElement.isNull() )
 
  363       if ( readGMLPositions( interiorPointList, posElement ) )
 
  367       ringCoordinates.push_back( interiorPointList );
 
  372   int nrings = ringCoordinates.size();
 
  377   for ( QgsMultiPolylineXY::const_iterator it = ringCoordinates.constBegin(); it != ringCoordinates.constEnd(); ++it )
 
  379     npoints += it->size();
 
  381   int size = 1 + 2 * 
sizeof( int ) + nrings * 
sizeof( 
int ) + 2 * npoints * 
sizeof( double );
 
  384   unsigned char *wkb = 
new unsigned char[size];
 
  387   char e = htonl( 1 ) != 1;
 
  389   int nPointsInRing = 0;
 
  393   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  395   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  396   wkbPosition += 
sizeof( int );
 
  397   memcpy( &( wkb )[wkbPosition], &nrings, 
sizeof( 
int ) );
 
  398   wkbPosition += 
sizeof( int );
 
  399   for ( QgsMultiPolylineXY::const_iterator it = ringCoordinates.constBegin(); it != ringCoordinates.constEnd(); ++it )
 
  401     nPointsInRing = it->size();
 
  402     memcpy( &( wkb )[wkbPosition], &nPointsInRing, 
sizeof( 
int ) );
 
  403     wkbPosition += 
sizeof( int );
 
  405     QgsPolylineXY::const_iterator iter;
 
  406     for ( iter = it->begin(); iter != it->end(); ++iter )
 
  411       memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  412       wkbPosition += 
sizeof( double );
 
  413       memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  414       wkbPosition += 
sizeof( double );
 
  423 QgsGeometry QgsOgcUtils::geometryFromGMLMultiPoint( 
const QDomElement &geometryElement )
 
  427   QDomNodeList pointMemberList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"pointMember" ) );
 
  428   if ( pointMemberList.size() < 1 )
 
  432   QDomNodeList pointNodeList;
 
  434   QDomNodeList coordinatesList;
 
  435   QDomNodeList posList;
 
  436   for ( 
int i = 0; i < pointMemberList.size(); ++i )
 
  439     pointNodeList = pointMemberList.at( i ).toElement().elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"Point" ) );
 
  440     if ( pointNodeList.size() < 1 )
 
  445     coordinatesList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  446     if ( !coordinatesList.isEmpty() )
 
  448       currentPoint.clear();
 
  449       if ( readGMLCoordinates( currentPoint, coordinatesList.at( 0 ).toElement() ) != 0 )
 
  453       if ( currentPoint.empty() )
 
  457       pointList.push_back( ( *currentPoint.begin() ) );
 
  463       posList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"pos" ) );
 
  464       if ( posList.size() < 1 )
 
  468       currentPoint.clear();
 
  469       if ( readGMLPositions( currentPoint, posList.at( 0 ).toElement() ) != 0 )
 
  473       if ( currentPoint.empty() )
 
  477       pointList.push_back( ( *currentPoint.begin() ) );
 
  481   int nPoints = pointList.size(); 
 
  486   int size = 1 + 2 * 
sizeof( int ) + pointList.size() * ( 2 * 
sizeof( double ) + 1 + 
sizeof( 
int ) );
 
  489   unsigned char *wkb = 
new unsigned char[size];
 
  492   char e = htonl( 1 ) != 1;
 
  495   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  497   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  498   wkbPosition += 
sizeof( int );
 
  499   memcpy( &( wkb )[wkbPosition], &nPoints, 
sizeof( 
int ) );
 
  500   wkbPosition += 
sizeof( int );
 
  502   for ( QgsPolylineXY::const_iterator it = pointList.constBegin(); it != pointList.constEnd(); ++it )
 
  504     memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  506     memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  507     wkbPosition += 
sizeof( int );
 
  509     memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  510     wkbPosition += 
sizeof( double );
 
  512     memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  513     wkbPosition += 
sizeof( double );
 
  521 QgsGeometry QgsOgcUtils::geometryFromGMLMultiLineString( 
const QDomElement &geometryElement )
 
  532   QList< QgsPolylineXY > lineCoordinates; 
 
  533   QDomElement currentLineStringElement;
 
  534   QDomNodeList currentCoordList;
 
  535   QDomNodeList currentPosList;
 
  537   QDomNodeList lineStringMemberList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"lineStringMember" ) );
 
  538   if ( !lineStringMemberList.isEmpty() ) 
 
  540     for ( 
int i = 0; i < lineStringMemberList.size(); ++i )
 
  542       QDomNodeList lineStringNodeList = lineStringMemberList.at( i ).toElement().elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LineString" ) );
 
  543       if ( lineStringNodeList.size() < 1 )
 
  547       currentLineStringElement = lineStringNodeList.at( 0 ).toElement();
 
  548       currentCoordList = currentLineStringElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  549       if ( !currentCoordList.isEmpty() )
 
  552         if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 )
 
  556         lineCoordinates.push_back( currentPointList );
 
  560         currentPosList = currentLineStringElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"posList" ) );
 
  561         if ( currentPosList.size() < 1 )
 
  566         if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 )
 
  570         lineCoordinates.push_back( currentPointList );
 
  576     QDomNodeList lineStringList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LineString" ) );
 
  577     if ( !lineStringList.isEmpty() ) 
 
  579       for ( 
int i = 0; i < lineStringList.size(); ++i )
 
  581         currentLineStringElement = lineStringList.at( i ).toElement();
 
  582         currentCoordList = currentLineStringElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  583         if ( !currentCoordList.isEmpty() )
 
  586           if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 )
 
  590           lineCoordinates.push_back( currentPointList );
 
  595           currentPosList = currentLineStringElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"posList" ) );
 
  596           if ( currentPosList.size() < 1 )
 
  601           if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 )
 
  605           lineCoordinates.push_back( currentPointList );
 
  615   int nLines = lineCoordinates.size();
 
  620   int size = ( lineCoordinates.size() + 1 ) * ( 1 + 2 * 
sizeof( 
int ) );
 
  621   for ( QList< QgsPolylineXY >::const_iterator it = lineCoordinates.constBegin(); it != lineCoordinates.constEnd(); ++it )
 
  623     size += it->size() * 2 * 
sizeof( double );
 
  627   unsigned char *wkb = 
new unsigned char[size];
 
  630   char e = htonl( 1 ) != 1;
 
  634   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  636   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  637   wkbPosition += 
sizeof( int );
 
  638   memcpy( &( wkb )[wkbPosition], &nLines, 
sizeof( 
int ) );
 
  639   wkbPosition += 
sizeof( int );
 
  641   for ( QList< QgsPolylineXY >::const_iterator it = lineCoordinates.constBegin(); it != lineCoordinates.constEnd(); ++it )
 
  643     memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  645     memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  646     wkbPosition += 
sizeof( int );
 
  647     nPoints = it->size();
 
  648     memcpy( &( wkb )[wkbPosition], &nPoints, 
sizeof( 
int ) );
 
  649     wkbPosition += 
sizeof( int );
 
  650     for ( QgsPolylineXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
 
  655       memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  656       wkbPosition += 
sizeof( double );
 
  657       memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  658       wkbPosition += 
sizeof( double );
 
  667 QgsGeometry QgsOgcUtils::geometryFromGMLMultiPolygon( 
const QDomElement &geometryElement )
 
  671   QDomElement currentPolygonMemberElement;
 
  672   QDomNodeList polygonList;
 
  673   QDomElement currentPolygonElement;
 
  675   QDomNodeList outerBoundaryList;
 
  676   QDomElement currentOuterBoundaryElement;
 
  677   QDomNodeList innerBoundaryList;
 
  678   QDomElement currentInnerBoundaryElement;
 
  680   QDomNodeList exteriorList;
 
  681   QDomElement currentExteriorElement;
 
  682   QDomElement currentInteriorElement;
 
  683   QDomNodeList interiorList;
 
  685   QDomNodeList linearRingNodeList;
 
  686   QDomElement currentLinearRingElement;
 
  688   QDomNodeList currentCoordinateList;
 
  689   QDomNodeList currentPosList;
 
  691   QDomNodeList polygonMemberList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"polygonMember" ) );
 
  693   for ( 
int i = 0; i < polygonMemberList.size(); ++i )
 
  695     currentPolygonList.resize( 0 ); 
 
  696     currentPolygonMemberElement = polygonMemberList.at( i ).toElement();
 
  697     polygonList = currentPolygonMemberElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"Polygon" ) );
 
  698     if ( polygonList.size() < 1 )
 
  702     currentPolygonElement = polygonList.at( 0 ).toElement();
 
  705     outerBoundaryList = currentPolygonElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"outerBoundaryIs" ) );
 
  706     if ( !outerBoundaryList.isEmpty() )
 
  708       currentOuterBoundaryElement = outerBoundaryList.at( 0 ).toElement();
 
  711       linearRingNodeList = currentOuterBoundaryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LinearRing" ) );
 
  712       if ( linearRingNodeList.size() < 1 )
 
  716       currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
 
  717       currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  718       if ( currentCoordinateList.size() < 1 )
 
  722       if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 )
 
  726       currentPolygonList.push_back( ringCoordinates );
 
  729       QDomNodeList innerBoundaryList = currentPolygonElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"innerBoundaryIs" ) );
 
  730       for ( 
int j = 0; j < innerBoundaryList.size(); ++j )
 
  733         currentInnerBoundaryElement = innerBoundaryList.at( j ).toElement();
 
  734         linearRingNodeList = currentInnerBoundaryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LinearRing" ) );
 
  735         if ( linearRingNodeList.size() < 1 )
 
  739         currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
 
  740         currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  741         if ( currentCoordinateList.size() < 1 )
 
  745         if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 )
 
  749         currentPolygonList.push_back( ringCoordinates );
 
  755       exteriorList = currentPolygonElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"exterior" ) );
 
  756       if ( exteriorList.size() < 1 )
 
  761       currentExteriorElement = exteriorList.at( 0 ).toElement();
 
  764       linearRingNodeList = currentExteriorElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LinearRing" ) );
 
  765       if ( linearRingNodeList.size() < 1 )
 
  769       currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
 
  770       currentPosList = currentLinearRingElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"posList" ) );
 
  771       if ( currentPosList.size() < 1 )
 
  775       if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 )
 
  779       currentPolygonList.push_back( ringPositions );
 
  782       QDomNodeList interiorList = currentPolygonElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"interior" ) );
 
  783       for ( 
int j = 0; j < interiorList.size(); ++j )
 
  786         currentInteriorElement = interiorList.at( j ).toElement();
 
  787         linearRingNodeList = currentInteriorElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LinearRing" ) );
 
  788         if ( linearRingNodeList.size() < 1 )
 
  792         currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
 
  793         currentPosList = currentLinearRingElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"posList" ) );
 
  794         if ( currentPosList.size() < 1 )
 
  798         if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 )
 
  802         currentPolygonList.push_back( ringPositions );
 
  805     multiPolygonPoints.push_back( currentPolygonList );
 
  808   int nPolygons = multiPolygonPoints.size();
 
  812   int size = 1 + 2 * 
sizeof( int );
 
  814   for ( QgsMultiPolygonXY::const_iterator it = multiPolygonPoints.constBegin(); it != multiPolygonPoints.constEnd(); ++it )
 
  816     size += 1 + 2 * 
sizeof( int );
 
  817     for ( QgsPolygonXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
 
  819       size += 
sizeof( int ) + 2 * iter->size() * 
sizeof( double );
 
  824   unsigned char *wkb = 
new unsigned char[size];
 
  826   char e = htonl( 1 ) != 1;
 
  833   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  835   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  836   wkbPosition += 
sizeof( int );
 
  837   memcpy( &( wkb )[wkbPosition], &nPolygons, 
sizeof( 
int ) );
 
  838   wkbPosition += 
sizeof( int );
 
  842   for ( QgsMultiPolygonXY::const_iterator it = multiPolygonPoints.constBegin(); it != multiPolygonPoints.constEnd(); ++it )
 
  844     memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  846     memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  847     wkbPosition += 
sizeof( int );
 
  849     memcpy( &( wkb )[wkbPosition], &nRings, 
sizeof( 
int ) );
 
  850     wkbPosition += 
sizeof( int );
 
  851     for ( QgsPolygonXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
 
  853       nPointsInRing = iter->size();
 
  854       memcpy( &( wkb )[wkbPosition], &nPointsInRing, 
sizeof( 
int ) );
 
  855       wkbPosition += 
sizeof( int );
 
  856       for ( QgsPolylineXY::const_iterator iterator = iter->begin(); iterator != iter->end(); ++iterator )
 
  860         memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  861         wkbPosition += 
sizeof( double );
 
  862         memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  863         wkbPosition += 
sizeof( double );
 
  873 bool QgsOgcUtils::readGMLCoordinates( 
QgsPolylineXY &coords, 
const QDomElement &elem )
 
  875   QString coordSeparator = QStringLiteral( 
"," );
 
  876   QString tupelSeparator = QStringLiteral( 
" " );
 
  881   if ( elem.hasAttribute( QStringLiteral( 
"cs" ) ) )
 
  883     coordSeparator = elem.attribute( QStringLiteral( 
"cs" ) );
 
  885   if ( elem.hasAttribute( QStringLiteral( 
"ts" ) ) )
 
  887     tupelSeparator = elem.attribute( QStringLiteral( 
"ts" ) );
 
  890 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
  891   QStringList tupels = elem.text().split( tupelSeparator, QString::SkipEmptyParts );
 
  893   QStringList tupels = elem.text().split( tupelSeparator, Qt::SkipEmptyParts );
 
  895   QStringList tuple_coords;
 
  897   bool conversionSuccess;
 
  899   QStringList::const_iterator it;
 
  900   for ( it = tupels.constBegin(); it != tupels.constEnd(); ++it )
 
  902 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
  903     tuple_coords = ( *it ).split( coordSeparator, QString::SkipEmptyParts );
 
  905     tuple_coords = ( *it ).split( coordSeparator, Qt::SkipEmptyParts );
 
  907     if ( tuple_coords.size() < 2 )
 
  911     x = tuple_coords.at( 0 ).toDouble( &conversionSuccess );
 
  912     if ( !conversionSuccess )
 
  916     y = tuple_coords.at( 1 ).toDouble( &conversionSuccess );
 
  917     if ( !conversionSuccess )
 
  930   QDomElement boxElem = boxNode.toElement();
 
  931   if ( boxElem.tagName() != QLatin1String( 
"Box" ) )
 
  934   QDomElement bElem = boxElem.firstChild().toElement();
 
  935   QString coordSeparator = QStringLiteral( 
"," );
 
  936   QString tupelSeparator = QStringLiteral( 
" " );
 
  937   if ( bElem.hasAttribute( QStringLiteral( 
"cs" ) ) )
 
  939     coordSeparator = bElem.attribute( QStringLiteral( 
"cs" ) );
 
  941   if ( bElem.hasAttribute( QStringLiteral( 
"ts" ) ) )
 
  943     tupelSeparator = bElem.attribute( QStringLiteral( 
"ts" ) );
 
  946   QString bString = bElem.text();
 
  947   bool ok1, ok2, ok3, ok4;
 
  948   double xmin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 0, 0 ).toDouble( &ok1 );
 
  949   double ymin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 1, 1 ).toDouble( &ok2 );
 
  950   double xmax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 0, 0 ).toDouble( &ok3 );
 
  951   double ymax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 1, 1 ).toDouble( &ok4 );
 
  953   if ( ok1 && ok2 && ok3 && ok4 )
 
  962 bool QgsOgcUtils::readGMLPositions( 
QgsPolylineXY &coords, 
const QDomElement &elem )
 
  966 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
  967   QStringList pos = elem.text().split( 
' ', QString::SkipEmptyParts );
 
  969   QStringList pos = elem.text().split( 
' ', Qt::SkipEmptyParts );
 
  972   bool conversionSuccess;
 
  973   int posSize = pos.size();
 
  975   int srsDimension = 2;
 
  976   if ( elem.hasAttribute( QStringLiteral( 
"srsDimension" ) ) )
 
  978     srsDimension = elem.attribute( QStringLiteral( 
"srsDimension" ) ).toInt( &conversionSuccess );
 
  979     if ( !conversionSuccess )
 
  984   else if ( elem.hasAttribute( QStringLiteral( 
"dimension" ) ) )
 
  986     srsDimension = elem.attribute( QStringLiteral( 
"dimension" ) ).toInt( &conversionSuccess );
 
  987     if ( !conversionSuccess )
 
  993   for ( 
int i = 0; i < posSize / srsDimension; i++ )
 
  995     x = pos.at( i * srsDimension ).toDouble( &conversionSuccess );
 
  996     if ( !conversionSuccess )
 
 1000     y = pos.at( i * srsDimension + 1 ).toDouble( &conversionSuccess );
 
 1001     if ( !conversionSuccess )
 
 1015   QDomElement envelopeElem = envelopeNode.toElement();
 
 1016   if ( envelopeElem.tagName() != QLatin1String( 
"Envelope" ) )
 
 1019   QDomNodeList lowerCornerList = envelopeElem.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"lowerCorner" ) );
 
 1020   if ( lowerCornerList.size() < 1 )
 
 1023   QDomNodeList upperCornerList = envelopeElem.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"upperCorner" ) );
 
 1024   if ( upperCornerList.size() < 1 )
 
 1027   bool conversionSuccess;
 
 1028   int srsDimension = 2;
 
 1030   QDomElement elem = lowerCornerList.at( 0 ).toElement();
 
 1031   if ( elem.hasAttribute( QStringLiteral( 
"srsDimension" ) ) )
 
 1033     srsDimension = elem.attribute( QStringLiteral( 
"srsDimension" ) ).toInt( &conversionSuccess );
 
 1034     if ( !conversionSuccess )
 
 1039   else if ( elem.hasAttribute( QStringLiteral( 
"dimension" ) ) )
 
 1041     srsDimension = elem.attribute( QStringLiteral( 
"dimension" ) ).toInt( &conversionSuccess );
 
 1042     if ( !conversionSuccess )
 
 1047   QString bString = elem.text();
 
 1049   double xmin = bString.section( 
' ', 0, 0 ).toDouble( &conversionSuccess );
 
 1050   if ( !conversionSuccess )
 
 1052   double ymin = bString.section( 
' ', 1, 1 ).toDouble( &conversionSuccess );
 
 1053   if ( !conversionSuccess )
 
 1056   elem = upperCornerList.at( 0 ).toElement();
 
 1057   if ( elem.hasAttribute( QStringLiteral( 
"srsDimension" ) ) )
 
 1059     srsDimension = elem.attribute( QStringLiteral( 
"srsDimension" ) ).toInt( &conversionSuccess );
 
 1060     if ( !conversionSuccess )
 
 1065   else if ( elem.hasAttribute( QStringLiteral( 
"dimension" ) ) )
 
 1067     srsDimension = elem.attribute( QStringLiteral( 
"dimension" ) ).toInt( &conversionSuccess );
 
 1068     if ( !conversionSuccess )
 
 1074   Q_UNUSED( srsDimension )
 
 1076   bString = elem.text();
 
 1077   double xmax = bString.section( 
' ', 0, 0 ).toDouble( &conversionSuccess );
 
 1078   if ( !conversionSuccess )
 
 1080   double ymax = bString.section( 
' ', 1, 1 ).toDouble( &conversionSuccess );
 
 1081   if ( !conversionSuccess )
 
 1096     const QString &srsName,
 
 1097     bool invertAxisOrientation,
 
 1102     return QDomElement();
 
 1105   QDomElement boxElem = doc.createElement( QStringLiteral( 
"gml:Box" ) );
 
 1106   if ( !srsName.isEmpty() )
 
 1108     boxElem.setAttribute( QStringLiteral( 
"srsName" ), srsName );
 
 1110   QDomElement coordElem = doc.createElement( QStringLiteral( 
"gml:coordinates" ) );
 
 1111   coordElem.setAttribute( QStringLiteral( 
"cs" ), QStringLiteral( 
"," ) );
 
 1112   coordElem.setAttribute( QStringLiteral( 
"ts" ), QStringLiteral( 
" " ) );
 
 1114   QString coordString;
 
 1123   QDomText coordText = doc.createTextNode( coordString );
 
 1124   coordElem.appendChild( coordText );
 
 1125   boxElem.appendChild( coordElem );
 
 1136     const QString &srsName,
 
 1137     bool invertAxisOrientation,
 
 1142     return QDomElement();
 
 1145   QDomElement envElem = doc.createElement( QStringLiteral( 
"gml:Envelope" ) );
 
 1146   if ( !srsName.isEmpty() )
 
 1148     envElem.setAttribute( QStringLiteral( 
"srsName" ), srsName );
 
 1152   QDomElement lowerCornerElem = doc.createElement( QStringLiteral( 
"gml:lowerCorner" ) );
 
 1156   QDomText lowerCornerText = doc.createTextNode( posList );
 
 1157   lowerCornerElem.appendChild( lowerCornerText );
 
 1158   envElem.appendChild( lowerCornerElem );
 
 1160   QDomElement upperCornerElem = doc.createElement( QStringLiteral( 
"gml:upperCorner" ) );
 
 1164   QDomText upperCornerText = doc.createTextNode( posList );
 
 1165   upperCornerElem.appendChild( upperCornerText );
 
 1166   envElem.appendChild( upperCornerElem );
 
 1179                                         const QString &srsName,
 
 1180                                         bool invertAxisOrientation,
 
 1181                                         const QString &gmlIdBase,
 
 1185     return QDomElement();
 
 1188   QString cs = QStringLiteral( 
"," );
 
 1190   QString ts = QStringLiteral( 
" " );
 
 1192   QDomElement baseCoordElem;
 
 1194   bool hasZValue = 
false;
 
 1196   QByteArray wkb( geometry.
asWkb() );
 
 1206     return QDomElement();
 
 1217         baseCoordElem = doc.createElement( QStringLiteral( 
"gml:pos" ) );
 
 1220         baseCoordElem = doc.createElement( QStringLiteral( 
"gml:posList" ) );
 
 1223     baseCoordElem.setAttribute( QStringLiteral( 
"srsDimension" ), QStringLiteral( 
"2" ) );
 
 1228     baseCoordElem = doc.createElement( QStringLiteral( 
"gml:coordinates" ) );
 
 1229     baseCoordElem.setAttribute( QStringLiteral( 
"cs" ), cs );
 
 1230     baseCoordElem.setAttribute( QStringLiteral( 
"ts" ), ts );
 
 1240         QDomElement pointElem = doc.createElement( QStringLiteral( 
"gml:Point" ) );
 
 1241         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1242           pointElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1243         if ( !srsName.isEmpty() )
 
 1244           pointElem.setAttribute( QStringLiteral( 
"srsName" ), srsName );
 
 1245         QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1249         if ( invertAxisOrientation )
 
 1255         coordElem.appendChild( coordText );
 
 1256         pointElem.appendChild( coordElem );
 
 1265         QDomElement multiPointElem = doc.createElement( QStringLiteral( 
"gml:MultiPoint" ) );
 
 1266         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1267           multiPointElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1268         if ( !srsName.isEmpty() )
 
 1269           multiPointElem.setAttribute( QStringLiteral( 
"srsName" ), srsName );
 
 1274         for ( 
int idx = 0; idx < nPoints; ++idx )
 
 1276           QDomElement pointMemberElem = doc.createElement( QStringLiteral( 
"gml:pointMember" ) );
 
 1277           QDomElement pointElem = doc.createElement( QStringLiteral( 
"gml:Point" ) );
 
 1278           if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1279             pointElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase + QStringLiteral( 
".%1" ).arg( idx + 1 ) );
 
 1280           QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1285           if ( invertAxisOrientation )
 
 1291           coordElem.appendChild( coordText );
 
 1292           pointElem.appendChild( coordElem );
 
 1296             wkbPtr += 
sizeof( double );
 
 1298           pointMemberElem.appendChild( pointElem );
 
 1299           multiPointElem.appendChild( pointMemberElem );
 
 1301         return multiPointElem;
 
 1309         QDomElement lineStringElem = doc.createElement( QStringLiteral( 
"gml:LineString" ) );
 
 1310         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1311           lineStringElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1312         if ( !srsName.isEmpty() )
 
 1313           lineStringElem.setAttribute( QStringLiteral( 
"srsName" ), srsName );
 
 1319         QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1320         QString coordString;
 
 1321         for ( 
int idx = 0; idx < nPoints; ++idx )
 
 1329           if ( invertAxisOrientation )
 
 1337             wkbPtr += 
sizeof( double );
 
 1340         QDomText coordText = doc.createTextNode( coordString );
 
 1341         coordElem.appendChild( coordText );
 
 1342         lineStringElem.appendChild( coordElem );
 
 1343         return lineStringElem;
 
 1351         QDomElement multiLineStringElem = doc.createElement( QStringLiteral( 
"gml:MultiLineString" ) );
 
 1352         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1353           multiLineStringElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1354         if ( !srsName.isEmpty() )
 
 1355           multiLineStringElem.setAttribute( QStringLiteral( 
"srsName" ), srsName );
 
 1360         for ( 
int jdx = 0; jdx < nLines; jdx++ )
 
 1362           QDomElement lineStringMemberElem = doc.createElement( QStringLiteral( 
"gml:lineStringMember" ) );
 
 1363           QDomElement lineStringElem = doc.createElement( QStringLiteral( 
"gml:LineString" ) );
 
 1364           if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1365             lineStringElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase + QStringLiteral( 
".%1" ).arg( jdx + 1 ) );
 
 1372           QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1373           QString coordString;
 
 1374           for ( 
int idx = 0; idx < nPoints; idx++ )
 
 1382             if ( invertAxisOrientation )
 
 1391               wkbPtr += 
sizeof( double );
 
 1394           QDomText coordText = doc.createTextNode( coordString );
 
 1395           coordElem.appendChild( coordText );
 
 1396           lineStringElem.appendChild( coordElem );
 
 1397           lineStringMemberElem.appendChild( lineStringElem );
 
 1398           multiLineStringElem.appendChild( lineStringMemberElem );
 
 1400         return multiLineStringElem;
 
 1408         QDomElement polygonElem = doc.createElement( QStringLiteral( 
"gml:Polygon" ) );
 
 1409         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1410           polygonElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1411         if ( !srsName.isEmpty() )
 
 1412           polygonElem.setAttribute( QStringLiteral( 
"srsName" ), srsName );
 
 1418         if ( numRings == 0 ) 
 
 1419           return QDomElement();
 
 1421         int *ringNumPoints = 
new int[numRings]; 
 
 1423         for ( 
int idx = 0; idx < numRings; idx++ )
 
 1425           QString boundaryName = ( gmlVersion == 
GML_2_1_2 ) ? 
"gml:outerBoundaryIs" : 
"gml:exterior";
 
 1428             boundaryName = ( gmlVersion == 
GML_2_1_2 ) ? 
"gml:innerBoundaryIs" : 
"gml:interior";
 
 1430           QDomElement boundaryElem = doc.createElement( boundaryName );
 
 1431           QDomElement ringElem = doc.createElement( QStringLiteral( 
"gml:LinearRing" ) );
 
 1435           ringNumPoints[idx] = nPoints;
 
 1437           QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1438           QString coordString;
 
 1439           for ( 
int jdx = 0; jdx < nPoints; jdx++ )
 
 1447             if ( invertAxisOrientation )
 
 1455               wkbPtr += 
sizeof( double );
 
 1458           QDomText coordText = doc.createTextNode( coordString );
 
 1459           coordElem.appendChild( coordText );
 
 1460           ringElem.appendChild( coordElem );
 
 1461           boundaryElem.appendChild( ringElem );
 
 1462           polygonElem.appendChild( boundaryElem );
 
 1464         delete [] ringNumPoints;
 
 1473         QDomElement multiPolygonElem = doc.createElement( QStringLiteral( 
"gml:MultiPolygon" ) );
 
 1474         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1475           multiPolygonElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1476         if ( !srsName.isEmpty() )
 
 1477           multiPolygonElem.setAttribute( QStringLiteral( 
"srsName" ), srsName );
 
 1480         wkbPtr >> numPolygons;
 
 1482         for ( 
int kdx = 0; kdx < numPolygons; kdx++ )
 
 1484           QDomElement polygonMemberElem = doc.createElement( QStringLiteral( 
"gml:polygonMember" ) );
 
 1485           QDomElement polygonElem = doc.createElement( QStringLiteral( 
"gml:Polygon" ) );
 
 1486           if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1487             polygonElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase + QStringLiteral( 
".%1" ).arg( kdx + 1 ) );
 
 1494           for ( 
int idx = 0; idx < numRings; idx++ )
 
 1496             QString boundaryName = ( gmlVersion == 
GML_2_1_2 ) ? 
"gml:outerBoundaryIs" : 
"gml:exterior";
 
 1499               boundaryName = ( gmlVersion == 
GML_2_1_2 ) ? 
"gml:innerBoundaryIs" : 
"gml:interior";
 
 1501             QDomElement boundaryElem = doc.createElement( boundaryName );
 
 1502             QDomElement ringElem = doc.createElement( QStringLiteral( 
"gml:LinearRing" ) );
 
 1507             QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1508             QString coordString;
 
 1509             for ( 
int jdx = 0; jdx < nPoints; jdx++ )
 
 1517               if ( invertAxisOrientation )
 
 1526                 wkbPtr += 
sizeof( double );
 
 1529             QDomText coordText = doc.createTextNode( coordString );
 
 1530             coordElem.appendChild( coordText );
 
 1531             ringElem.appendChild( coordElem );
 
 1532             boundaryElem.appendChild( ringElem );
 
 1533             polygonElem.appendChild( boundaryElem );
 
 1534             polygonMemberElem.appendChild( polygonElem );
 
 1535             multiPolygonElem.appendChild( polygonMemberElem );
 
 1538         return multiPolygonElem;
 
 1541         return QDomElement();
 
 1547     return QDomElement();
 
 1556 QDomElement QgsOgcUtils::createGMLCoordinates( 
const QgsPolylineXY &points, QDomDocument &doc )
 
 1558   QDomElement coordElem = doc.createElement( QStringLiteral( 
"gml:coordinates" ) );
 
 1559   coordElem.setAttribute( QStringLiteral( 
"cs" ), QStringLiteral( 
"," ) );
 
 1560   coordElem.setAttribute( QStringLiteral( 
"ts" ), QStringLiteral( 
" " ) );
 
 1562   QString coordString;
 
 1563   QVector<QgsPointXY>::const_iterator pointIt = points.constBegin();
 
 1564   for ( ; pointIt != points.constEnd(); ++pointIt )
 
 1566     if ( pointIt != points.constBegin() )
 
 1575   QDomText coordText = doc.createTextNode( coordString );
 
 1576   coordElem.appendChild( coordText );
 
 1580 QDomElement QgsOgcUtils::createGMLPositions( 
const QgsPolylineXY &points, QDomDocument &doc )
 
 1582   QDomElement posElem = doc.createElement( QStringLiteral( 
"gml:pos" ) );
 
 1583   if ( points.size() > 1 )
 
 1584     posElem = doc.createElement( QStringLiteral( 
"gml:posList" ) );
 
 1585   posElem.setAttribute( QStringLiteral( 
"srsDimension" ), QStringLiteral( 
"2" ) );
 
 1587   QString coordString;
 
 1588   QVector<QgsPointXY>::const_iterator pointIt = points.constBegin();
 
 1589   for ( ; pointIt != points.constEnd(); ++pointIt )
 
 1591     if ( pointIt != points.constBegin() )
 
 1600   QDomText coordText = doc.createTextNode( coordString );
 
 1601   posElem.appendChild( coordText );
 
 1611   if ( fillElement.isNull() || !fillElement.hasChildNodes() )
 
 1619   QDomElement cssElem = fillElement.firstChildElement( QStringLiteral( 
"CssParameter" ) );
 
 1620   while ( !cssElem.isNull() )
 
 1622     cssName = cssElem.attribute( QStringLiteral( 
"name" ), QStringLiteral( 
"not_found" ) );
 
 1623     if ( cssName != QLatin1String( 
"not_found" ) )
 
 1625       elemText = cssElem.text();
 
 1626       if ( cssName == QLatin1String( 
"fill" ) )
 
 1628         color.setNamedColor( elemText );
 
 1630       else if ( cssName == QLatin1String( 
"fill-opacity" ) )
 
 1633         double opacity = elemText.toDouble( &ok );
 
 1636           color.setAlphaF( opacity );
 
 1641     cssElem = cssElem.nextSiblingElement( QStringLiteral( 
"CssParameter" ) );
 
 1655   if ( element.isNull() || !element.hasChildNodes() )
 
 1662   if ( element.firstChild().nodeType() == QDomNode::TextNode )
 
 1672   QDomElement childElem = element.firstChildElement();
 
 1673   while ( !childElem.isNull() )
 
 1685     if ( !expr->d->mRootNode )
 
 1687       expr->d->mRootNode = node;
 
 1694     childElem = childElem.nextSiblingElement();
 
 1698   expr->d->mExp = expr->
dump();
 
 1724 static 
int binaryOperatorFromTagName( const QString &tagName )
 
 1727   return BINARY_OPERATORS_TAG_NAMES_MAP()->value( tagName, -1 );
 
 1734     return QStringLiteral( 
"PropertyIsLike" );
 
 1736   return BINARY_OPERATORS_TAG_NAMES_MAP()->key( op, QString() );
 
 1739 static bool isBinaryOperator( 
const QString &tagName )
 
 1741   return binaryOperatorFromTagName( tagName ) >= 0;
 
 1745 static bool isSpatialOperator( 
const QString &tagName )
 
 1747   static QStringList spatialOps;
 
 1748   if ( spatialOps.isEmpty() )
 
 1750     spatialOps << QStringLiteral( 
"BBOX" ) << QStringLiteral( 
"Intersects" ) << QStringLiteral( 
"Contains" ) << QStringLiteral( 
"Crosses" ) << QStringLiteral( 
"Equals" )
 
 1751                << QStringLiteral( 
"Disjoint" ) << QStringLiteral( 
"Overlaps" ) << QStringLiteral( 
"Touches" ) << QStringLiteral( 
"Within" );
 
 1754   return spatialOps.contains( tagName );
 
 1761   errorMessage = utils.errorMessage();
 
 1769   errorMessage = utils.errorMessage();
 
 1777   errorMessage = utils.errorMessage();
 
 1785   errorMessage = utils.errorMessage();
 
 1793   errorMessage = utils.errorMessage();
 
 1801   errorMessage = utils.errorMessage();
 
 1809   errorMessage = utils.errorMessage();
 
 1813 QgsExpressionNode *QgsOgcUtils::nodeIsBetweenFromOgcFilter( QDomElement &element, QString &errorMessage )
 
 1817   errorMessage = utils.errorMessage();
 
 1825   errorMessage = utils.errorMessage();
 
 1836                                 QStringLiteral( 
"geometry" ), QString(), 
false, 
false, errorMessage );
 
 1842                                     QStringLiteral( 
"geometry" ), QString(), 
false, 
false, errorMessage );
 
 1850     const QString &srsName,
 
 1851     bool honourAxisOrientation,
 
 1852     bool invertAxisOrientation,
 
 1853     QString *errorMessage )
 
 1856     return QDomElement();
 
 1866   if ( exprRootElem.isNull() )
 
 1867     return QDomElement();
 
 1869   QDomElement filterElem =
 
 1871     doc.createElementNS( 
FES_NAMESPACE, QStringLiteral( 
"fes:Filter" ) ) :
 
 1872     doc.createElementNS( 
OGC_NAMESPACE, QStringLiteral( 
"ogc:Filter" ) );
 
 1875     QDomAttr attr = doc.createAttribute( QStringLiteral( 
"xmlns:gml" ) );
 
 1880     filterElem.setAttributeNode( attr );
 
 1882   filterElem.appendChild( exprRootElem );
 
 1891     const QString &srsName,
 
 1892     bool honourAxisOrientation,
 
 1893     bool invertAxisOrientation,
 
 1894     QString *errorMessage )
 
 1903     return QDomElement();
 
 1917       if ( !exprRootElem.isNull() )
 
 1919         return exprRootElem;
 
 1926         *errorMessage = QObject::tr( 
"Node type not supported in expression translation: %1" ).arg( node->
nodeType() );
 
 1930   return QDomElement();
 
 1937     const QList<LayerProperties> &layerProperties,
 
 1938     bool honourAxisOrientation,
 
 1939     bool invertAxisOrientation,
 
 1940     const QMap< QString, QString> &mapUnprefixedTypenameToPrefixedTypename,
 
 1941     QString *errorMessage )
 
 1944     return QDomElement();
 
 1947                                          layerProperties, honourAxisOrientation, invertAxisOrientation,
 
 1948                                          mapUnprefixedTypenameToPrefixedTypename );
 
 1952   if ( exprRootElem.isNull() )
 
 1953     return QDomElement();
 
 1955   QDomElement filterElem =
 
 1957     doc.createElementNS( 
FES_NAMESPACE, QStringLiteral( 
"fes:Filter" ) ) :
 
 1958     doc.createElementNS( 
OGC_NAMESPACE, QStringLiteral( 
"ogc:Filter" ) );
 
 1961     QDomAttr attr = doc.createAttribute( QStringLiteral( 
"xmlns:gml" ) );
 
 1966     filterElem.setAttributeNode( attr );
 
 1968   filterElem.appendChild( exprRootElem );
 
 1993       mErrorMessage = QObject::tr( 
"Node type not supported: %1" ).arg( node->
nodeType() );
 
 1994       return QDomElement();
 
 2001   if ( !mErrorMessage.isEmpty() )
 
 2002     return QDomElement();
 
 2005   switch ( node->
op() )
 
 2008       uoElem = mDoc.createElement( mFilterPrefix + 
":Literal" );
 
 2013         uoElem.appendChild( mDoc.createTextNode( 
"-" + operandElem.text() ) );
 
 2014         mDoc.removeChild( operandElem );
 
 2018         mErrorMessage = QObject::tr( 
"This use of unary operator not implemented yet" );
 
 2019         return QDomElement();
 
 2023       uoElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2024       uoElem.appendChild( operandElem );
 
 2028       mErrorMessage = QObject::tr( 
"Unary operator '%1' not implemented yet" ).arg( node->
text() );
 
 2029       return QDomElement();
 
 2039   if ( !mErrorMessage.isEmpty() )
 
 2040     return QDomElement();
 
 2050       if ( rightLit->
value().isNull() )
 
 2053         QDomElement elem = mDoc.createElement( mFilterPrefix + 
":PropertyIsNull" );
 
 2054         elem.appendChild( leftElem );
 
 2058           QDomElement notElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2059           notElem.appendChild( elem );
 
 2073   if ( !mErrorMessage.isEmpty() )
 
 2074     return QDomElement();
 
 2077   QString opText = binaryOperatorToTagName( op );
 
 2078   if ( opText.isEmpty() )
 
 2082     mErrorMessage = QObject::tr( 
"Binary operator %1 not implemented yet" ).arg( node->
text() );
 
 2083     return QDomElement();
 
 2086   QDomElement boElem = mDoc.createElement( mFilterPrefix + 
":" + opText );
 
 2091       boElem.setAttribute( QStringLiteral( 
"matchCase" ), QStringLiteral( 
"false" ) );
 
 2094     boElem.setAttribute( QStringLiteral( 
"wildCard" ), QStringLiteral( 
"%" ) );
 
 2095     boElem.setAttribute( QStringLiteral( 
"singleChar" ), QStringLiteral( 
"_" ) );
 
 2097       boElem.setAttribute( QStringLiteral( 
"escape" ), QStringLiteral( 
"\\" ) );
 
 2099       boElem.setAttribute( QStringLiteral( 
"escapeChar" ), QStringLiteral( 
"\\" ) );
 
 2102   boElem.appendChild( leftElem );
 
 2103   boElem.appendChild( rightElem );
 
 2110   Q_UNUSED( expression )
 
 2113   switch ( node->
value().type() )
 
 2116       value = QString::number( node->
value().toInt() );
 
 2118     case QVariant::Double:
 
 2121     case QVariant::String:
 
 2122       value = node->
value().toString();
 
 2124     case QVariant::Date:
 
 2125       value = node->
value().toDate().toString( Qt::ISODate );
 
 2127     case QVariant::DateTime:
 
 2128       value = node->
value().toDateTime().toString( Qt::ISODate );
 
 2132       mErrorMessage = QObject::tr( 
"Literal type not supported: %1" ).arg( node->
value().type() );
 
 2133       return QDomElement();
 
 2136   QDomElement litElem = mDoc.createElement( mFilterPrefix + 
":Literal" );
 
 2137   litElem.appendChild( mDoc.createTextNode( value ) );
 
 2144   Q_UNUSED( expression )
 
 2146   QDomElement propElem = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 2147   propElem.appendChild( mDoc.createTextNode( node->
name() ) );
 
 2155   if ( node->
list()->
list().size() == 1 )
 
 2158   QDomElement orElem = mDoc.createElement( mFilterPrefix + 
":Or" );
 
 2161   const auto constList = node->
list()->
list();
 
 2165     if ( !mErrorMessage.isEmpty() )
 
 2166       return QDomElement();
 
 2168     QDomElement eqElem = mDoc.createElement( mFilterPrefix + 
":PropertyIsEqualTo" );
 
 2169     eqElem.appendChild( leftNode.cloneNode() );
 
 2170     eqElem.appendChild( listNode );
 
 2172     orElem.appendChild( eqElem );
 
 2177     QDomElement notElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2178     notElem.appendChild( orElem );
 
 2187   { QLatin1String( 
"disjoint" ),   QLatin1String( 
"Disjoint" ) },
 
 2188   { QLatin1String( 
"intersects" ), QLatin1String( 
"Intersects" )},
 
 2189   { QLatin1String( 
"touches" ),    QLatin1String( 
"Touches" ) },
 
 2190   { QLatin1String( 
"crosses" ),    QLatin1String( 
"Crosses" ) },
 
 2191   { QLatin1String( 
"contains" ),   QLatin1String( 
"Contains" ) },
 
 2192   { QLatin1String( 
"overlaps" ),   QLatin1String( 
"Overlaps" ) },
 
 2193   { QLatin1String( 
"within" ),     QLatin1String( 
"Within" ) }
 
 2196 static 
bool isBinarySpatialOperator( const QString &fnName )
 
 2198   return BINARY_SPATIAL_OPS_MAP()->contains( fnName );
 
 2201 static QString tagNameForSpatialOperator( 
const QString &fnName )
 
 2203   return BINARY_SPATIAL_OPS_MAP()->value( fnName );
 
 2213   return fd->
name() == QLatin1String( 
"$geometry" );
 
 2225     if ( fnDef->
name() == QLatin1String( 
"geom_from_wkt" ) )
 
 2227       const QList<QgsExpressionNode *> &args = fnNode->
args()->
list();
 
 2243   if ( fd->
name() == QLatin1String( 
"intersects_bbox" ) )
 
 2245     QList<QgsExpressionNode *> argNodes = node->
args()->
list();
 
 2246     Q_ASSERT( argNodes.count() == 2 ); 
 
 2248     QgsGeometry geom = geometryFromConstExpr( argNodes[1] );
 
 2249     if ( !geom.
isNull() && isGeometryColumn( argNodes[0] ) )
 
 2259       QDomElement geomProperty = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 2260       geomProperty.appendChild( mDoc.createTextNode( mGeometryName ) );
 
 2262       QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":BBOX" );
 
 2263       funcElem.appendChild( geomProperty );
 
 2264       funcElem.appendChild( elemBox );
 
 2269       mErrorMessage = QObject::tr( 
"<BBOX> is currently supported only in form: bbox($geometry, geomFromWKT('…'))" );
 
 2270       return QDomElement();
 
 2274   if ( isBinarySpatialOperator( fd->
name() ) )
 
 2276     QList<QgsExpressionNode *> argNodes = node->
args()->
list();
 
 2277     Q_ASSERT( argNodes.count() == 2 ); 
 
 2280     if ( isGeometryColumn( argNodes[0] ) )
 
 2281       otherNode = argNodes[1];
 
 2282     else if ( isGeometryColumn( argNodes[1] ) )
 
 2283       otherNode = argNodes[0];
 
 2286       mErrorMessage = QObject::tr( 
"Unable to translate spatial operator: at least one must refer to geometry." );
 
 2287       return QDomElement();
 
 2290     QDomElement otherGeomElem;
 
 2295       mErrorMessage = QObject::tr( 
"spatial operator: the other operator must be a geometry constructor function" );
 
 2296       return QDomElement();
 
 2301     if ( otherFnDef->
name() == QLatin1String( 
"geom_from_wkt" ) )
 
 2306         mErrorMessage = QObject::tr( 
"geom_from_wkt: argument must be string literal" );
 
 2307         return QDomElement();
 
 2312                       QStringLiteral( 
"qgis_id_geom_%1" ).arg( mGeomId ) );
 
 2315     else if ( otherFnDef->
name() == QLatin1String( 
"geom_from_gml" ) )
 
 2320         mErrorMessage = QObject::tr( 
"geom_from_gml: argument must be string literal" );
 
 2321         return QDomElement();
 
 2324       QDomDocument geomDoc;
 
 2326       if ( !geomDoc.setContent( gml, 
true ) )
 
 2328         mErrorMessage = QObject::tr( 
"geom_from_gml: unable to parse XML" );
 
 2329         return QDomElement();
 
 2332       QDomNode geomNode = mDoc.importNode( geomDoc.documentElement(), 
true );
 
 2333       otherGeomElem = geomNode.toElement();
 
 2337       mErrorMessage = QObject::tr( 
"spatial operator: unknown geometry constructor function" );
 
 2338       return QDomElement();
 
 2343     QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":" + tagNameForSpatialOperator( fd->
name() ) );
 
 2344     QDomElement geomProperty = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 2345     geomProperty.appendChild( mDoc.createTextNode( mGeometryName ) );
 
 2346     funcElem.appendChild( geomProperty );
 
 2347     funcElem.appendChild( otherGeomElem );
 
 2351   if ( fd->
isStatic( node, expression, context ) )
 
 2353     QVariant result = fd->
run( node->
args(), context, expression, node );
 
 2355     return expressionLiteralToOgcFilter( &literal, expression, context );
 
 2360     mErrorMessage = QObject::tr( 
"Special columns/constants are not supported." );
 
 2361     return QDomElement();
 
 2365   QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":Function" );
 
 2366   funcElem.setAttribute( QStringLiteral( 
"name" ), fd->
name() );
 
 2367   const auto constList = node->
args()->
list();
 
 2371     if ( !mErrorMessage.isEmpty() )
 
 2372       return QDomElement();
 
 2374     funcElem.appendChild( childElem );
 
 2385     const QList<QgsOgcUtils::LayerProperties> &layerProperties,
 
 2386     bool honourAxisOrientation,
 
 2387     bool invertAxisOrientation,
 
 2388     const QMap< QString, QString> &mapUnprefixedTypenameToPrefixedTypename )
 
 2391   , mGMLVersion( gmlVersion )
 
 2392   , mFilterVersion( filterVersion )
 
 2393   , mLayerProperties( layerProperties )
 
 2394   , mHonourAxisOrientation( honourAxisOrientation )
 
 2395   , mInvertAxisOrientation( invertAxisOrientation )
 
 2396   , mFilterPrefix( ( filterVersion == 
QgsOgcUtils::FILTER_FES_2_0 ) ? 
"fes" : 
"ogc" )
 
 2397   , mPropertyName( ( filterVersion == 
QgsOgcUtils::FILTER_FES_2_0 ) ? 
"ValueReference" : 
"PropertyName" )
 
 2399   , mMapUnprefixedTypenameToPrefixedTypename( mapUnprefixedTypenameToPrefixedTypename )
 
 2425       mErrorMessage = QObject::tr( 
"Node type not supported: %1" ).arg( node->
nodeType() );
 
 2426       return QDomElement();
 
 2435   if ( !mErrorMessage.isEmpty() )
 
 2436     return QDomElement();
 
 2439   switch ( node->
op() )
 
 2442       uoElem = mDoc.createElement( mFilterPrefix + 
":Literal" );
 
 2447         uoElem.appendChild( mDoc.createTextNode( 
"-" + operandElem.text() ) );
 
 2448         mDoc.removeChild( operandElem );
 
 2452         mErrorMessage = QObject::tr( 
"This use of unary operator not implemented yet" );
 
 2453         return QDomElement();
 
 2457       uoElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2458       uoElem.appendChild( operandElem );
 
 2463       return QDomElement();
 
 2473   if ( !mErrorMessage.isEmpty() )
 
 2474     return QDomElement();
 
 2484       if ( rightLit->
value().isNull() )
 
 2487         QDomElement elem = mDoc.createElement( mFilterPrefix + 
":PropertyIsNull" );
 
 2488         elem.appendChild( leftElem );
 
 2492           QDomElement notElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2493           notElem.appendChild( elem );
 
 2507   if ( !mErrorMessage.isEmpty() )
 
 2508     return QDomElement();
 
 2513     opText = QStringLiteral( 
"Or" );
 
 2515     opText = QStringLiteral( 
"And" );
 
 2517     opText = QStringLiteral( 
"PropertyIsEqualTo" );
 
 2519     opText = QStringLiteral( 
"PropertyIsNotEqualTo" );
 
 2521     opText = QStringLiteral( 
"PropertyIsLessThanOrEqualTo" );
 
 2523     opText = QStringLiteral( 
"PropertyIsGreaterThanOrEqualTo" );
 
 2525     opText = QStringLiteral( 
"PropertyIsLessThan" );
 
 2527     opText = QStringLiteral( 
"PropertyIsGreaterThan" );
 
 2529     opText = QStringLiteral( 
"PropertyIsLike" );
 
 2531     opText = QStringLiteral( 
"PropertyIsLike" );
 
 2533   if ( opText.isEmpty() )
 
 2537     return QDomElement();
 
 2540   QDomElement boElem = mDoc.createElement( mFilterPrefix + 
":" + opText );
 
 2545       boElem.setAttribute( QStringLiteral( 
"matchCase" ), QStringLiteral( 
"false" ) );
 
 2548     boElem.setAttribute( QStringLiteral( 
"wildCard" ), QStringLiteral( 
"%" ) );
 
 2549     boElem.setAttribute( QStringLiteral( 
"singleChar" ), QStringLiteral( 
"_" ) );
 
 2551       boElem.setAttribute( QStringLiteral( 
"escape" ), QStringLiteral( 
"\\" ) );
 
 2553       boElem.setAttribute( QStringLiteral( 
"escapeChar" ), QStringLiteral( 
"\\" ) );
 
 2556   boElem.appendChild( leftElem );
 
 2557   boElem.appendChild( rightElem );
 
 2565   switch ( node->
value().type() )
 
 2568       value = QString::number( node->
value().toInt() );
 
 2570     case QVariant::LongLong:
 
 2571       value = QString::number( node->
value().toLongLong() );
 
 2573     case QVariant::Double:
 
 2576     case QVariant::String:
 
 2577       value = node->
value().toString();
 
 2581       mErrorMessage = QObject::tr( 
"Literal type not supported: %1" ).arg( node->
value().type() );
 
 2582       return QDomElement();
 
 2585   QDomElement litElem = mDoc.createElement( mFilterPrefix + 
":Literal" );
 
 2586   litElem.appendChild( mDoc.createTextNode( value ) );
 
 2593   QDomElement propElem = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 2594   if ( node->
tableName().isEmpty() || mLayerProperties.size() == 1 )
 
 2595     propElem.appendChild( mDoc.createTextNode( node->
name() ) );
 
 2598     QString tableName( mMapTableAliasToNames[node->
tableName()] );
 
 2599     if ( mMapUnprefixedTypenameToPrefixedTypename.contains( tableName ) )
 
 2600       tableName = mMapUnprefixedTypenameToPrefixedTypename[tableName];
 
 2601     propElem.appendChild( mDoc.createTextNode( tableName + 
"/" + node->
name() ) );
 
 2608   if ( node->
list()->
list().size() == 1 )
 
 2611   QDomElement orElem = mDoc.createElement( mFilterPrefix + 
":Or" );
 
 2614   const auto constList = node->
list()->
list();
 
 2618     if ( !mErrorMessage.isEmpty() )
 
 2619       return QDomElement();
 
 2621     QDomElement eqElem = mDoc.createElement( mFilterPrefix + 
":PropertyIsEqualTo" );
 
 2622     eqElem.appendChild( leftNode.cloneNode() );
 
 2623     eqElem.appendChild( listNode );
 
 2625     orElem.appendChild( eqElem );
 
 2630     QDomElement notElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2631     notElem.appendChild( orElem );
 
 2640   QDomElement elem = mDoc.createElement( mFilterPrefix + 
":PropertyIsBetween" );
 
 2642   QDomElement lowerBoundary = mDoc.createElement( mFilterPrefix + 
":LowerBoundary" );
 
 2644   elem.appendChild( lowerBoundary );
 
 2645   QDomElement upperBoundary = mDoc.createElement( mFilterPrefix + 
":UpperBoundary" );
 
 2647   elem.appendChild( upperBoundary );
 
 2651     QDomElement notElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2652     notElem.appendChild( elem );
 
 2659 static QString mapBinarySpatialToOgc( 
const QString &name )
 
 2661   QString nameCompare( name );
 
 2662   if ( name.size() > 3 && name.midRef( 0, 3 ).compare( QLatin1String( 
"ST_" ), Qt::CaseInsensitive ) == 0 )
 
 2663     nameCompare = name.mid( 3 );
 
 2664   QStringList spatialOps;
 
 2665   spatialOps << QStringLiteral( 
"BBOX" ) << QStringLiteral( 
"Intersects" ) << QStringLiteral( 
"Contains" ) << QStringLiteral( 
"Crosses" ) << QStringLiteral( 
"Equals" )
 
 2666              << QStringLiteral( 
"Disjoint" ) << QStringLiteral( 
"Overlaps" ) << QStringLiteral( 
"Touches" ) << QStringLiteral( 
"Within" );
 
 2667   const auto constSpatialOps = spatialOps;
 
 2668   for ( QString op : constSpatialOps )
 
 2670     if ( nameCompare.compare( op, Qt::CaseInsensitive ) == 0 )
 
 2676 static QString mapTernarySpatialToOgc( 
const QString &name )
 
 2678   QString nameCompare( name );
 
 2679   if ( name.size() > 3 && name.midRef( 0, 3 ).compare( QLatin1String( 
"ST_" ), Qt::CaseInsensitive ) == 0 )
 
 2680     nameCompare = name.mid( 3 );
 
 2681   if ( nameCompare.compare( QLatin1String( 
"DWithin" ), Qt::CaseInsensitive ) == 0 )
 
 2682     return QStringLiteral( 
"DWithin" );
 
 2683   if ( nameCompare.compare( QLatin1String( 
"Beyond" ), Qt::CaseInsensitive ) == 0 )
 
 2684     return QStringLiteral( 
"Beyond" );
 
 2688 QString QgsOgcUtilsSQLStatementToFilter::getGeometryColumnSRSName( 
const QgsSQLStatement::Node *node )
 
 2696     const auto constMLayerProperties = mLayerProperties;
 
 2699       if ( prop.mName.compare( mMapTableAliasToNames[col->
tableName()], Qt::CaseInsensitive ) == 0 &&
 
 2700            prop.mGeometryAttribute.compare( col->
name(), Qt::CaseInsensitive ) == 0 )
 
 2702         return prop.mSRSName;
 
 2706   if ( !mLayerProperties.empty() &&
 
 2707        mLayerProperties.at( 0 ).mGeometryAttribute.compare( col->
name(), Qt::CaseInsensitive ) == 0 )
 
 2709     return  mLayerProperties.at( 0 ).mSRSName;
 
 2715     QList<QgsSQLStatement::Node *> args,
 
 2716     bool lastArgIsSRSName,
 
 2718     bool &axisInversion )
 
 2720   srsName = mCurrentSRSName;
 
 2721   axisInversion = mInvertAxisOrientation;
 
 2723   if ( lastArgIsSRSName )
 
 2728       mErrorMessage = QObject::tr( 
"%1: Last argument must be string or integer literal" ).arg( mainNode->
name() );
 
 2732     if ( lit->
value().type() == QVariant::Int )
 
 2736         srsName = 
"EPSG:" + QString::number( lit->
value().toInt() );
 
 2740         srsName = 
"urn:ogc:def:crs:EPSG::" + QString::number( lit->
value().toInt() );
 
 2745       srsName = lit->
value().toString();
 
 2746       if ( srsName.startsWith( QLatin1String( 
"EPSG:" ), Qt::CaseInsensitive ) )
 
 2752   if ( !srsName.isEmpty() )
 
 2758       axisInversion = !axisInversion;
 
 2768   if ( node->
name().compare( QLatin1String( 
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 )
 
 2770     QList<QgsSQLStatement::Node *> args = node->
args()->
list();
 
 2771     if ( args.size() != 1 && args.size() != 2 )
 
 2773       mErrorMessage = QObject::tr( 
"Function %1 should have 1 or 2 arguments" ).arg( node->
name() );
 
 2774       return QDomElement();
 
 2780       mErrorMessage = QObject::tr( 
"%1: First argument must be string literal" ).arg( node->
name() );
 
 2781       return QDomElement();
 
 2786     if ( ! processSRSName( node, args, args.size() == 2, srsName, axisInversion ) )
 
 2788       return QDomElement();
 
 2794                            QStringLiteral( 
"qgis_id_geom_%1" ).arg( mGeomId ) );
 
 2796     if ( geomElem.isNull() )
 
 2798       mErrorMessage = QObject::tr( 
"%1: invalid WKT" ).arg( node->
name() );
 
 2799       return QDomElement();
 
 2806   if ( node->
name().compare( QLatin1String( 
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 )
 
 2808     QList<QgsSQLStatement::Node *> args = node->
args()->
list();
 
 2809     if ( args.size() != 4 && args.size() != 5 )
 
 2811       mErrorMessage = QObject::tr( 
"Function %1 should have 4 or 5 arguments" ).arg( node->
name() );
 
 2812       return QDomElement();
 
 2817     for ( 
int i = 0; i < 4; i++ )
 
 2822         mErrorMessage = QObject::tr( 
"%1: Argument %2 must be numeric literal" ).arg( node->
name() ).arg( i + 1 );
 
 2823         return QDomElement();
 
 2827       if ( lit->
value().type() == QVariant::Int )
 
 2828         val = lit->
value().toInt();
 
 2829       else if ( lit->
value().type() == QVariant::LongLong )
 
 2830         val = lit->
value().toLongLong();
 
 2831       else if ( lit->
value().type() == QVariant::Double )
 
 2832         val = lit->
value().toDouble();
 
 2835         mErrorMessage = QObject::tr( 
"%1 Argument %2 must be numeric literal" ).arg( node->
name() ).arg( i + 1 );
 
 2836         return QDomElement();
 
 2850     if ( ! processSRSName( node, args, args.size() == 5, srsName, axisInversion ) )
 
 2852       return QDomElement();
 
 2859            QgsOgcUtils::rectangleToGMLEnvelope( &rect, mDoc, srsName, axisInversion, 15 );
 
 2863   if ( node->
name().compare( QLatin1String( 
"ST_GeomFromGML" ), Qt::CaseInsensitive ) == 0 )
 
 2865     QList<QgsSQLStatement::Node *> args = node->
args()->
list();
 
 2866     if ( args.size() != 1 )
 
 2868       mErrorMessage = QObject::tr( 
"Function %1 should have 1 argument" ).arg( node->
name() );
 
 2869       return QDomElement();
 
 2875       mErrorMessage = QObject::tr( 
"%1: Argument must be string literal" ).arg( node->
name() );
 
 2876       return QDomElement();
 
 2879     QDomDocument geomDoc;
 
 2881     if ( !geomDoc.setContent( gml, 
true ) )
 
 2883       mErrorMessage = QObject::tr( 
"ST_GeomFromGML: unable to parse XML" );
 
 2884       return QDomElement();
 
 2887     QDomNode geomNode = mDoc.importNode( geomDoc.documentElement(), 
true );
 
 2889     return geomNode.toElement();
 
 2893   QString ogcName( mapBinarySpatialToOgc( node->
name() ) );
 
 2894   if ( !ogcName.isEmpty() )
 
 2896     QList<QgsSQLStatement::Node *> args = node->
args()->
list();
 
 2897     if ( args.size() != 2 )
 
 2899       mErrorMessage = QObject::tr( 
"Function %1 should have 2 arguments" ).arg( node->
name() );
 
 2900       return QDomElement();
 
 2903     for ( 
int i = 0; i < 2; i ++ )
 
 2906            ( 
static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String( 
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 ||
 
 2907              static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String( 
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 ) )
 
 2909         mCurrentSRSName = getGeometryColumnSRSName( args[1 - i] );
 
 2916     QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":" + ogcName );
 
 2917     const auto constArgs = args;
 
 2921       if ( !mErrorMessage.isEmpty() )
 
 2923         mCurrentSRSName.clear();
 
 2924         return QDomElement();
 
 2927       funcElem.appendChild( childElem );
 
 2930     mCurrentSRSName.clear();
 
 2934   ogcName = mapTernarySpatialToOgc( node->
name() );
 
 2935   if ( !ogcName.isEmpty() )
 
 2937     QList<QgsSQLStatement::Node *> args = node->
args()->
list();
 
 2938     if ( args.size() != 3 )
 
 2940       mErrorMessage = QObject::tr( 
"Function %1 should have 3 arguments" ).arg( node->
name() );
 
 2941       return QDomElement();
 
 2944     for ( 
int i = 0; i < 2; i ++ )
 
 2947            ( 
static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String( 
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 ||
 
 2948              static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String( 
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 ) )
 
 2950         mCurrentSRSName = getGeometryColumnSRSName( args[1 - i] );
 
 2955     QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":" + node->
name().mid( 3 ) );
 
 2956     for ( 
int i = 0; i < 2; i++ )
 
 2959       if ( !mErrorMessage.isEmpty() )
 
 2961         mCurrentSRSName.clear();
 
 2962         return QDomElement();
 
 2965       funcElem.appendChild( childElem );
 
 2967     mCurrentSRSName.clear();
 
 2972       mErrorMessage = QObject::tr( 
"Function %1 3rd argument should be a numeric value or a string made of a numeric value followed by a string" ).arg( node->
name() );
 
 2973       return QDomElement();
 
 2976     if ( lit->
value().isNull() )
 
 2978       mErrorMessage = QObject::tr( 
"Function %1 3rd argument should be a numeric value or a string made of a numeric value followed by a string" ).arg( node->
name() );
 
 2979       return QDomElement();
 
 2982     QString unit( QStringLiteral( 
"m" ) );
 
 2983     switch ( lit->
value().type() )
 
 2986         distance = QString::number( lit->
value().toInt() );
 
 2988       case QVariant::LongLong:
 
 2989         distance = QString::number( lit->
value().toLongLong() );
 
 2991       case QVariant::Double:
 
 2994       case QVariant::String:
 
 2996         distance = lit->
value().toString();
 
 2997         for ( 
int i = 0; i < distance.size(); i++ )
 
 2999           if ( !( ( distance[i] >= 
'0' && distance[i] <= 
'9' ) || distance[i] == 
'-' || distance[i] == 
'.' || distance[i] == 
'e' || distance[i] == 
'E' ) )
 
 3001             unit = distance.mid( i ).trimmed();
 
 3002             distance = distance.mid( 0, i );
 
 3010         mErrorMessage = QObject::tr( 
"Literal type not supported: %1" ).arg( lit->
value().type() );
 
 3011         return QDomElement();
 
 3014     QDomElement distanceElem = mDoc.createElement( mFilterPrefix + 
":Distance" );
 
 3016       distanceElem.setAttribute( QStringLiteral( 
"uom" ), unit );
 
 3018       distanceElem.setAttribute( QStringLiteral( 
"unit" ), unit );
 
 3019     distanceElem.appendChild( mDoc.createTextNode( distance ) );
 
 3020     funcElem.appendChild( distanceElem );
 
 3025   QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":Function" );
 
 3026   funcElem.setAttribute( QStringLiteral( 
"name" ), node->
name() );
 
 3027   const auto constList = node->
args()->
list();
 
 3031     if ( !mErrorMessage.isEmpty() )
 
 3032       return QDomElement();
 
 3034     funcElem.appendChild( childElem );
 
 3040     const QString &leftTable )
 
 3048   QList<QDomElement> listElem;
 
 3050   for ( 
const QString &columnName : constUsingColumns )
 
 3052     QDomElement eqElem = mDoc.createElement( mFilterPrefix + 
":PropertyIsEqualTo" );
 
 3053     QDomElement propElem1 = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 3054     propElem1.appendChild( mDoc.createTextNode( leftTable + 
"/" + columnName ) );
 
 3055     eqElem.appendChild( propElem1 );
 
 3056     QDomElement propElem2 = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 3057     propElem2.appendChild( mDoc.createTextNode( node->
tableDef()->
name() + 
"/" + columnName ) );
 
 3058     eqElem.appendChild( propElem2 );
 
 3059     listElem.append( eqElem );
 
 3062   if ( listElem.size() == 1 )
 
 3066   else if ( listElem.size() > 1 )
 
 3068     QDomElement andElem = mDoc.createElement( mFilterPrefix + 
":And" );
 
 3069     const auto constListElem = listElem;
 
 3070     for ( 
const QDomElement &elem : constListElem )
 
 3072       andElem.appendChild( elem );
 
 3077   return QDomElement();
 
 3082   if ( node->
alias().isEmpty() )
 
 3084     mMapTableAliasToNames[ node->
name()] = node->
name();
 
 3088     mMapTableAliasToNames[ node->
alias()] = node->
name();
 
 3094   QList<QDomElement> listElem;
 
 3097        ( node->
tables().size() != 1 || !node->
joins().empty() ) )
 
 3099     mErrorMessage = QObject::tr( 
"Joins are only supported with WFS 2.0" );
 
 3100     return QDomElement();
 
 3104   const auto constTables = node->
tables();
 
 3109   const auto constJoins = node->
joins();
 
 3112     visit( join->tableDef() );
 
 3116   QList< QgsSQLStatement::NodeTableDef *> nodeTables = node->
tables();
 
 3117   QString leftTable = nodeTables.at( nodeTables.length() - 1 )->name();
 
 3120     QDomElement joinElem = 
toOgcFilter( join, leftTable );
 
 3121     if ( !mErrorMessage.isEmpty() )
 
 3122       return QDomElement();
 
 3123     listElem.append( joinElem );
 
 3124     leftTable = join->tableDef()->name();
 
 3128   if ( node->
where() )
 
 3131     if ( !mErrorMessage.isEmpty() )
 
 3132       return QDomElement();
 
 3133     listElem.append( whereElem );
 
 3137   if ( listElem.size() == 1 )
 
 3141   else if ( listElem.size() > 1 )
 
 3143     QDomElement andElem = mDoc.createElement( mFilterPrefix + 
":And" );
 
 3144     const auto constListElem = listElem;
 
 3145     for ( 
const QDomElement &elem : constListElem )
 
 3147       andElem.appendChild( elem );
 
 3152   return QDomElement();
 
 3158   mPropertyName = QStringLiteral( 
"PropertyName" );
 
 3159   mPrefix = QStringLiteral( 
"ogc" );
 
 3163     mPropertyName = QStringLiteral( 
"ValueReference" );
 
 3164     mPrefix = QStringLiteral( 
"fes" );
 
 3170   if ( element.isNull() )
 
 3174   if ( isBinaryOperator( element.tagName() ) )
 
 3180   if ( isSpatialOperator( element.tagName() ) )
 
 3186   if ( element.tagName() == QLatin1String( 
"Not" ) )
 
 3190   else if ( element.tagName() == QLatin1String( 
"PropertyIsNull" ) )
 
 3194   else if ( element.tagName() == QLatin1String( 
"Literal" ) )
 
 3198   else if ( element.tagName() == QLatin1String( 
"Function" ) )
 
 3202   else if ( element.tagName() == mPropertyName )
 
 3206   else if ( element.tagName() == QLatin1String( 
"PropertyIsBetween" ) )
 
 3211   mErrorMessage += QObject::tr( 
"unable to convert '%1' element to a valid expression: it is not supported yet or it has invalid arguments" ).arg( element.tagName() );
 
 3217   if ( element.isNull() )
 
 3220   int op = binaryOperatorFromTagName( element.tagName() );
 
 3223     mErrorMessage = QObject::tr( 
"'%1' binary operator not supported." ).arg( element.tagName() );
 
 3227   if ( op == 
QgsExpressionNodeBinaryOperator::boLike && element.hasAttribute( QStringLiteral( 
"matchCase" ) ) && element.attribute( QStringLiteral( 
"matchCase" ) ) == QLatin1String( 
"false" ) )
 
 3232   QDomElement operandElem = element.firstChildElement();
 
 3237     mErrorMessage = QObject::tr( 
"invalid left operand for '%1' binary operator" ).arg( element.tagName() );
 
 3241   std::unique_ptr<QgsExpressionNode> leftOp( expr->clone() );
 
 3242   for ( operandElem = operandElem.nextSiblingElement(); !operandElem.isNull(); operandElem = operandElem.nextSiblingElement() )
 
 3247       mErrorMessage = QObject::tr( 
"invalid right operand for '%1' binary operator" ).arg( element.tagName() );
 
 3254       if ( element.hasAttribute( QStringLiteral( 
"wildCard" ) ) )
 
 3256         wildCard = element.attribute( QStringLiteral( 
"wildCard" ) );
 
 3259       if ( element.hasAttribute( QStringLiteral( 
"singleChar" ) ) )
 
 3261         singleChar = element.attribute( QStringLiteral( 
"singleChar" ) );
 
 3263       QString escape = QStringLiteral( 
"\\" );
 
 3264       if ( element.hasAttribute( QStringLiteral( 
"escape" ) ) )
 
 3266         escape = element.attribute( QStringLiteral( 
"escape" ) );
 
 3268       if ( element.hasAttribute( QStringLiteral( 
"escapeChar" ) ) )
 
 3270         escape = element.attribute( QStringLiteral( 
"escapeChar" ) );
 
 3274       if ( !wildCard.isEmpty() && wildCard != QLatin1String( 
"%" ) )
 
 3276         oprValue.replace( 
'%', QLatin1String( 
"\\%" ) );
 
 3277         if ( oprValue.startsWith( wildCard ) )
 
 3279           oprValue.replace( 0, 1, QStringLiteral( 
"%" ) );
 
 3281         QRegExp rx( 
"[^" + QRegExp::escape( escape ) + 
"](" + QRegExp::escape( wildCard ) + 
")" );
 
 3283         while ( ( pos = rx.indexIn( oprValue, pos ) ) != -1 )
 
 3285           oprValue.replace( pos + 1, 1, QStringLiteral( 
"%" ) );
 
 3288         oprValue.replace( escape + wildCard, wildCard );
 
 3290       if ( !singleChar.isEmpty() && singleChar != QLatin1String( 
"_" ) )
 
 3292         oprValue.replace( 
'_', QLatin1String( 
"\\_" ) );
 
 3293         if ( oprValue.startsWith( singleChar ) )
 
 3295           oprValue.replace( 0, 1, QStringLiteral( 
"_" ) );
 
 3297         QRegExp rx( 
"[^" + QRegExp::escape( escape ) + 
"](" + QRegExp::escape( singleChar ) + 
")" );
 
 3299         while ( ( pos = rx.indexIn( oprValue, pos ) ) != -1 )
 
 3301           oprValue.replace( pos + 1, 1, QStringLiteral( 
"_" ) );
 
 3304         oprValue.replace( escape + singleChar, singleChar );
 
 3306       if ( !escape.isEmpty() && escape != QLatin1String( 
"\\" ) )
 
 3308         oprValue.replace( escape + escape, escape );
 
 3316   if ( expr == leftOp )
 
 3318     mErrorMessage = QObject::tr( 
"only one operand for '%1' binary operator" ).arg( element.tagName() );
 
 3332   QDomElement childElem = element.firstChildElement();
 
 3334   while ( !childElem.isNull() && gml2Str.isEmpty() )
 
 3336     if ( childElem.tagName() != mPropertyName )
 
 3338       QTextStream gml2Stream( &gml2Str );
 
 3339       childElem.save( gml2Stream, 0 );
 
 3341     childElem = childElem.nextSiblingElement();
 
 3343   if ( !gml2Str.isEmpty() )
 
 3349     mErrorMessage = QObject::tr( 
"No OGC Geometry found" );
 
 3362   if ( element.isNull() || element.tagName() != mPropertyName )
 
 3364     mErrorMessage = QObject::tr( 
"%1:PropertyName expected, got %2" ).arg( mPrefix, element.tagName() );
 
 3373   if ( element.isNull() || element.tagName() != QLatin1String( 
"Literal" ) )
 
 3375     mErrorMessage = QObject::tr( 
"%1:Literal expected, got %2" ).arg( mPrefix, element.tagName() );
 
 3379   std::unique_ptr<QgsExpressionNode> root;
 
 3382   QDomNode childNode = element.firstChild();
 
 3383   while ( !childNode.isNull() )
 
 3385     std::unique_ptr<QgsExpressionNode> operand;
 
 3387     if ( childNode.nodeType() == QDomNode::ElementNode )
 
 3390       const QDomElement operandElem = childNode.toElement();
 
 3394         mErrorMessage = QObject::tr( 
"'%1' is an invalid or not supported content for %2:Literal" ).arg( operandElem.tagName(), mPrefix );
 
 3401       QVariant value = childNode.nodeValue();
 
 3403       bool converted = 
false;
 
 3408         QDomElement propertyNameElement = element.previousSiblingElement( mPropertyName );
 
 3409         if ( propertyNameElement.isNull() || propertyNameElement.tagName() != mPropertyName )
 
 3411           propertyNameElement = element.nextSiblingElement( mPropertyName );
 
 3413         if ( !propertyNameElement.isNull() || propertyNameElement.tagName() == mPropertyName )
 
 3415           const int fieldIndex = mLayer->
fields().
indexOf( propertyNameElement.firstChild().nodeValue() );
 
 3416           if ( fieldIndex != -1 )
 
 3429         const double d = value.toDouble( &ok );
 
 3442       root = std::move( operand );
 
 3449     childNode = childNode.nextSibling();
 
 3453     return root.release();
 
 3460   if ( element.tagName() != QLatin1String( 
"Not" ) )
 
 3463   const QDomElement operandElem = element.firstChildElement();
 
 3467     mErrorMessage = QObject::tr( 
"invalid operand for '%1' unary operator" ).arg( element.tagName() );
 
 3477   if ( element.tagName() != QLatin1String( 
"PropertyIsNull" ) )
 
 3482   const QDomElement operandElem = element.firstChildElement();
 
 3493   if ( element.isNull() || element.tagName() != QLatin1String( 
"Function" ) )
 
 3495     mErrorMessage = QObject::tr( 
"%1:Function expected, got %2" ).arg( mPrefix, element.tagName() );
 
 3503     if ( element.attribute( QStringLiteral( 
"name" ) ) != funcDef->
name() )
 
 3508     QDomElement operandElem = element.firstChildElement();
 
 3509     while ( !operandElem.isNull() )
 
 3516       args->append( op.release() );
 
 3518       operandElem = operandElem.nextSiblingElement();
 
 3530   std::unique_ptr<QgsExpressionNode> operand;
 
 3531   std::unique_ptr<QgsExpressionNode> lowerBound;
 
 3532   std::unique_ptr<QgsExpressionNode> upperBound;
 
 3534   QDomElement operandElem = element.firstChildElement();
 
 3535   while ( !operandElem.isNull() )
 
 3537     if ( operandElem.tagName() == QLatin1String( 
"LowerBoundary" ) )
 
 3539       QDomElement lowerBoundElem = operandElem.firstChildElement();
 
 3542     else if ( operandElem.tagName() == QLatin1String( 
"UpperBoundary" ) )
 
 3544       QDomElement upperBoundElem = operandElem.firstChildElement();
 
 3553     if ( operand && lowerBound && upperBound )
 
 3556     operandElem = operandElem.nextSiblingElement();
 
 3559   if ( !operand || !lowerBound || !upperBound )
 
 3561     mErrorMessage = QObject::tr( 
"missing some required sub-elements in %1:PropertyIsBetween" ).arg( mPrefix );
 
 3572   return mErrorMessage;