31 #include <QStringList> 
   32 #include <QTextStream> 
   34 #include <QRegularExpression> 
   37 #include <netinet/in.h> 
   43 #define GML_NAMESPACE QStringLiteral( "http://www.opengis.net/gml" )
 
   44 #define GML32_NAMESPACE QStringLiteral( "http://www.opengis.net/gml/3.2" )
 
   45 #define OGC_NAMESPACE QStringLiteral( "http://www.opengis.net/ogc" )
 
   46 #define FES_NAMESPACE QStringLiteral( "http://www.opengis.net/fes/2.0" )
 
   53     bool honourAxisOrientation,
 
   54     bool invertAxisOrientation )
 
   57   , mGMLVersion( gmlVersion )
 
   58   , mFilterVersion( filterVersion )
 
   61   , mInvertAxisOrientation( invertAxisOrientation )
 
   62   , mFilterPrefix( ( filterVersion == 
QgsOgcUtils::FILTER_FES_2_0 ) ? 
"fes" : 
"ogc" )
 
   63   , mPropertyName( ( filterVersion == 
QgsOgcUtils::FILTER_FES_2_0 ) ? 
"ValueReference" : 
"PropertyName" )
 
   67   if ( !mSrsName.isEmpty() )
 
   73       mInvertAxisOrientation = !mInvertAxisOrientation;
 
   80   QDomElement geometryTypeElement = geometryNode.toElement();
 
   81   QString geomType = geometryTypeElement.tagName();
 
   84   if ( !( geomType == QLatin1String( 
"Point" ) || geomType == QLatin1String( 
"LineString" ) || geomType == QLatin1String( 
"Polygon" ) ||
 
   85           geomType == QLatin1String( 
"MultiPoint" ) || geomType == QLatin1String( 
"MultiLineString" ) || geomType == QLatin1String( 
"MultiPolygon" ) ||
 
   86           geomType == QLatin1String( 
"Box" ) || geomType == QLatin1String( 
"Envelope" ) ) )
 
   88     const QDomNode geometryChild = geometryNode.firstChild();
 
   89     if ( geometryChild.isNull() )
 
   93     geometryTypeElement = geometryChild.toElement();
 
   94     geomType = geometryTypeElement.tagName();
 
   97   if ( !( geomType == QLatin1String( 
"Point" ) || geomType == QLatin1String( 
"LineString" ) || geomType == QLatin1String( 
"Polygon" ) ||
 
   98           geomType == QLatin1String( 
"MultiPoint" ) || geomType == QLatin1String( 
"MultiLineString" ) || geomType == QLatin1String( 
"MultiPolygon" ) ||
 
   99           geomType == QLatin1String( 
"Box" ) || geomType == QLatin1String( 
"Envelope" ) ) )
 
  102   if ( geomType == QLatin1String( 
"Point" ) )
 
  104     geometry = geometryFromGMLPoint( geometryTypeElement );
 
  106   else if ( geomType == QLatin1String( 
"LineString" ) )
 
  108     geometry = geometryFromGMLLineString( geometryTypeElement );
 
  110   else if ( geomType == QLatin1String( 
"Polygon" ) )
 
  112     geometry = geometryFromGMLPolygon( geometryTypeElement );
 
  114   else if ( geomType == QLatin1String( 
"MultiPoint" ) )
 
  116     geometry = geometryFromGMLMultiPoint( geometryTypeElement );
 
  118   else if ( geomType == QLatin1String( 
"MultiLineString" ) )
 
  120     geometry = geometryFromGMLMultiLineString( geometryTypeElement );
 
  122   else if ( geomType == QLatin1String( 
"MultiPolygon" ) )
 
  124     geometry = geometryFromGMLMultiPolygon( geometryTypeElement );
 
  126   else if ( geomType == QLatin1String( 
"Box" ) )
 
  130   else if ( geomType == QLatin1String( 
"Envelope" ) )
 
  144     if ( geometryTypeElement.hasAttribute( QStringLiteral( 
"srsName" ) ) )
 
  146       QString 
srsName { geometryTypeElement.attribute( QStringLiteral( 
"srsName" ) ) };
 
  149       const bool ignoreAxisOrientation { 
srsName.startsWith( QLatin1String( 
"http://www.opengis.net/gml/srs/" ) ) || 
srsName.startsWith( QLatin1String( 
"EPSG:" ) ) };
 
  153       if ( 
srsName.startsWith( QLatin1String( 
"http://www.opengis.net/gml/srs/" ) ) )
 
  155         const auto parts { 
srsName.split( QRegularExpression( QStringLiteral( R
"raw(/|#|\.)raw" ) ) ) }; 
  156         if ( parts.length() == 10 )
 
  158           srsName = QStringLiteral( 
"http://www.opengis.net/def/crs/%1/0/%2" ).arg( parts[ 7 ].toUpper(), parts[ 9 ] );
 
  191   const QString xml = QStringLiteral( 
"<tmp xmlns=\"%1\" xmlns:gml=\"%1\">%2</tmp>" ).arg( 
GML_NAMESPACE, xmlString );
 
  193   if ( !doc.setContent( xml, 
true ) )
 
  196   return geometryFromGML( doc.documentElement().firstChildElement(), context );
 
  200 QgsGeometry QgsOgcUtils::geometryFromGMLPoint( 
const QDomElement &geometryElement )
 
  204   const QDomNodeList coordList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  205   if ( !coordList.isEmpty() )
 
  207     const QDomElement coordElement = coordList.at( 0 ).toElement();
 
  208     if ( readGMLCoordinates( pointCoordinate, coordElement ) != 0 )
 
  215     const QDomNodeList posList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"pos" ) );
 
  216     if ( posList.size() < 1 )
 
  220     const QDomElement posElement = posList.at( 0 ).toElement();
 
  221     if ( readGMLPositions( pointCoordinate, posElement ) != 0 )
 
  227   if ( pointCoordinate.empty() )
 
  232   QgsPolylineXY::const_iterator point_it = pointCoordinate.constBegin();
 
  233   char e = htonl( 1 ) != 1;
 
  234   double x = point_it->x();
 
  235   double y = point_it->y();
 
  236   const int size = 1 + 
sizeof( int ) + 2 * 
sizeof( 
double );
 
  239   unsigned char *wkb = 
new unsigned char[size];
 
  242   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  244   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  245   wkbPosition += 
sizeof( int );
 
  246   memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  247   wkbPosition += 
sizeof( double );
 
  248   memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  255 QgsGeometry QgsOgcUtils::geometryFromGMLLineString( 
const QDomElement &geometryElement )
 
  259   const QDomNodeList coordList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  260   if ( !coordList.isEmpty() )
 
  262     const QDomElement coordElement = coordList.at( 0 ).toElement();
 
  263     if ( readGMLCoordinates( lineCoordinates, coordElement ) != 0 )
 
  270     const QDomNodeList posList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"posList" ) );
 
  271     if ( posList.size() < 1 )
 
  275     const QDomElement posElement = posList.at( 0 ).toElement();
 
  276     if ( readGMLPositions( lineCoordinates, posElement ) != 0 )
 
  282   char e = htonl( 1 ) != 1;
 
  283   const int size = 1 + 2 * 
sizeof( int ) + lineCoordinates.size() * 2 * 
sizeof( double );
 
  286   unsigned char *wkb = 
new unsigned char[size];
 
  290   int nPoints = lineCoordinates.size();
 
  293   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  295   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  296   wkbPosition += 
sizeof( int );
 
  297   memcpy( &( wkb )[wkbPosition], &nPoints, 
sizeof( 
int ) );
 
  298   wkbPosition += 
sizeof( int );
 
  300   QgsPolylineXY::const_iterator iter;
 
  301   for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
 
  305     memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  306     wkbPosition += 
sizeof( double );
 
  307     memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  308     wkbPosition += 
sizeof( double );
 
  316 QgsGeometry QgsOgcUtils::geometryFromGMLPolygon( 
const QDomElement &geometryElement )
 
  323   const QDomNodeList outerBoundaryList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"outerBoundaryIs" ) );
 
  324   if ( !outerBoundaryList.isEmpty() ) 
 
  326     QDomElement coordinatesElement = outerBoundaryList.at( 0 ).firstChild().firstChild().toElement();
 
  327     if ( coordinatesElement.isNull() )
 
  331     if ( readGMLCoordinates( exteriorPointList, coordinatesElement ) != 0 )
 
  335     ringCoordinates.push_back( exteriorPointList );
 
  338     const QDomNodeList innerBoundaryList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"innerBoundaryIs" ) );
 
  339     for ( 
int i = 0; i < innerBoundaryList.size(); ++i )
 
  342       coordinatesElement = innerBoundaryList.at( i ).firstChild().firstChild().toElement();
 
  343       if ( coordinatesElement.isNull() )
 
  347       if ( readGMLCoordinates( interiorPointList, coordinatesElement ) != 0 )
 
  351       ringCoordinates.push_back( interiorPointList );
 
  357     const QDomNodeList exteriorList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"exterior" ) );
 
  358     if ( exteriorList.size() < 1 ) 
 
  362     const QDomElement posElement = exteriorList.at( 0 ).firstChild().firstChild().toElement();
 
  363     if ( posElement.isNull() )
 
  367     if ( readGMLPositions( exteriorPointList, posElement ) != 0 )
 
  371     ringCoordinates.push_back( exteriorPointList );
 
  374     const QDomNodeList interiorList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"interior" ) );
 
  375     for ( 
int i = 0; i < interiorList.size(); ++i )
 
  378       const QDomElement posElement = interiorList.at( i ).firstChild().firstChild().toElement();
 
  379       if ( posElement.isNull() )
 
  384       if ( readGMLPositions( interiorPointList, posElement ) )
 
  388       ringCoordinates.push_back( interiorPointList );
 
  393   int nrings = ringCoordinates.size();
 
  398   for ( QgsMultiPolylineXY::const_iterator it = ringCoordinates.constBegin(); it != ringCoordinates.constEnd(); ++it )
 
  400     npoints += it->size();
 
  402   const int size = 1 + 2 * 
sizeof( int ) + nrings * 
sizeof( 
int ) + 2 * npoints * 
sizeof( double );
 
  405   unsigned char *wkb = 
new unsigned char[size];
 
  408   char e = htonl( 1 ) != 1;
 
  410   int nPointsInRing = 0;
 
  414   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  416   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  417   wkbPosition += 
sizeof( int );
 
  418   memcpy( &( wkb )[wkbPosition], &nrings, 
sizeof( 
int ) );
 
  419   wkbPosition += 
sizeof( int );
 
  420   for ( QgsMultiPolylineXY::const_iterator it = ringCoordinates.constBegin(); it != ringCoordinates.constEnd(); ++it )
 
  422     nPointsInRing = it->size();
 
  423     memcpy( &( wkb )[wkbPosition], &nPointsInRing, 
sizeof( 
int ) );
 
  424     wkbPosition += 
sizeof( int );
 
  426     QgsPolylineXY::const_iterator iter;
 
  427     for ( iter = it->begin(); iter != it->end(); ++iter )
 
  432       memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  433       wkbPosition += 
sizeof( double );
 
  434       memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  435       wkbPosition += 
sizeof( double );
 
  444 QgsGeometry QgsOgcUtils::geometryFromGMLMultiPoint( 
const QDomElement &geometryElement )
 
  448   const QDomNodeList pointMemberList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"pointMember" ) );
 
  449   if ( pointMemberList.size() < 1 )
 
  453   QDomNodeList pointNodeList;
 
  455   QDomNodeList coordinatesList;
 
  456   QDomNodeList posList;
 
  457   for ( 
int i = 0; i < pointMemberList.size(); ++i )
 
  460     pointNodeList = pointMemberList.at( i ).toElement().elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"Point" ) );
 
  461     if ( pointNodeList.size() < 1 )
 
  466     coordinatesList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  467     if ( !coordinatesList.isEmpty() )
 
  469       currentPoint.clear();
 
  470       if ( readGMLCoordinates( currentPoint, coordinatesList.at( 0 ).toElement() ) != 0 )
 
  474       if ( currentPoint.empty() )
 
  478       pointList.push_back( ( *currentPoint.begin() ) );
 
  484       posList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"pos" ) );
 
  485       if ( posList.size() < 1 )
 
  489       currentPoint.clear();
 
  490       if ( readGMLPositions( currentPoint, posList.at( 0 ).toElement() ) != 0 )
 
  494       if ( currentPoint.empty() )
 
  498       pointList.push_back( ( *currentPoint.begin() ) );
 
  502   int nPoints = pointList.size(); 
 
  507   const int size = 1 + 2 * 
sizeof( int ) + pointList.size() * ( 2 * 
sizeof( double ) + 1 + 
sizeof( 
int ) );
 
  510   unsigned char *wkb = 
new unsigned char[size];
 
  513   char e = htonl( 1 ) != 1;
 
  516   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  518   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  519   wkbPosition += 
sizeof( int );
 
  520   memcpy( &( wkb )[wkbPosition], &nPoints, 
sizeof( 
int ) );
 
  521   wkbPosition += 
sizeof( int );
 
  523   for ( QgsPolylineXY::const_iterator it = pointList.constBegin(); it != pointList.constEnd(); ++it )
 
  525     memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  527     memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  528     wkbPosition += 
sizeof( int );
 
  530     memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  531     wkbPosition += 
sizeof( double );
 
  533     memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  534     wkbPosition += 
sizeof( double );
 
  542 QgsGeometry QgsOgcUtils::geometryFromGMLMultiLineString( 
const QDomElement &geometryElement )
 
  553   QList< QgsPolylineXY > lineCoordinates; 
 
  554   QDomElement currentLineStringElement;
 
  555   QDomNodeList currentCoordList;
 
  556   QDomNodeList currentPosList;
 
  558   const QDomNodeList lineStringMemberList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"lineStringMember" ) );
 
  559   if ( !lineStringMemberList.isEmpty() ) 
 
  561     for ( 
int i = 0; i < lineStringMemberList.size(); ++i )
 
  563       const QDomNodeList lineStringNodeList = lineStringMemberList.at( i ).toElement().elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LineString" ) );
 
  564       if ( lineStringNodeList.size() < 1 )
 
  568       currentLineStringElement = lineStringNodeList.at( 0 ).toElement();
 
  569       currentCoordList = currentLineStringElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  570       if ( !currentCoordList.isEmpty() )
 
  573         if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 )
 
  577         lineCoordinates.push_back( currentPointList );
 
  581         currentPosList = currentLineStringElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"posList" ) );
 
  582         if ( currentPosList.size() < 1 )
 
  587         if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 )
 
  591         lineCoordinates.push_back( currentPointList );
 
  597     const QDomNodeList lineStringList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LineString" ) );
 
  598     if ( !lineStringList.isEmpty() ) 
 
  600       for ( 
int i = 0; i < lineStringList.size(); ++i )
 
  602         currentLineStringElement = lineStringList.at( i ).toElement();
 
  603         currentCoordList = currentLineStringElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  604         if ( !currentCoordList.isEmpty() )
 
  607           if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 )
 
  611           lineCoordinates.push_back( currentPointList );
 
  616           currentPosList = currentLineStringElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"posList" ) );
 
  617           if ( currentPosList.size() < 1 )
 
  622           if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 )
 
  626           lineCoordinates.push_back( currentPointList );
 
  636   int nLines = lineCoordinates.size();
 
  641   int size = ( lineCoordinates.size() + 1 ) * ( 1 + 2 * 
sizeof( 
int ) );
 
  642   for ( QList< QgsPolylineXY >::const_iterator it = lineCoordinates.constBegin(); it != lineCoordinates.constEnd(); ++it )
 
  644     size += it->size() * 2 * 
sizeof( double );
 
  648   unsigned char *wkb = 
new unsigned char[size];
 
  651   char e = htonl( 1 ) != 1;
 
  655   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  657   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  658   wkbPosition += 
sizeof( int );
 
  659   memcpy( &( wkb )[wkbPosition], &nLines, 
sizeof( 
int ) );
 
  660   wkbPosition += 
sizeof( int );
 
  662   for ( QList< QgsPolylineXY >::const_iterator it = lineCoordinates.constBegin(); it != lineCoordinates.constEnd(); ++it )
 
  664     memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  666     memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  667     wkbPosition += 
sizeof( int );
 
  668     nPoints = it->size();
 
  669     memcpy( &( wkb )[wkbPosition], &nPoints, 
sizeof( 
int ) );
 
  670     wkbPosition += 
sizeof( int );
 
  671     for ( QgsPolylineXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
 
  676       memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  677       wkbPosition += 
sizeof( double );
 
  678       memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  679       wkbPosition += 
sizeof( double );
 
  688 QgsGeometry QgsOgcUtils::geometryFromGMLMultiPolygon( 
const QDomElement &geometryElement )
 
  692   QDomElement currentPolygonMemberElement;
 
  693   QDomNodeList polygonList;
 
  694   QDomElement currentPolygonElement;
 
  696   QDomNodeList outerBoundaryList;
 
  697   QDomElement currentOuterBoundaryElement;
 
  698   const QDomNodeList innerBoundaryList;
 
  699   QDomElement currentInnerBoundaryElement;
 
  701   QDomNodeList exteriorList;
 
  702   QDomElement currentExteriorElement;
 
  703   QDomElement currentInteriorElement;
 
  704   const QDomNodeList interiorList;
 
  706   QDomNodeList linearRingNodeList;
 
  707   QDomElement currentLinearRingElement;
 
  709   QDomNodeList currentCoordinateList;
 
  710   QDomNodeList currentPosList;
 
  712   const QDomNodeList polygonMemberList = geometryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"polygonMember" ) );
 
  714   for ( 
int i = 0; i < polygonMemberList.size(); ++i )
 
  716     currentPolygonList.resize( 0 ); 
 
  717     currentPolygonMemberElement = polygonMemberList.at( i ).toElement();
 
  718     polygonList = currentPolygonMemberElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"Polygon" ) );
 
  719     if ( polygonList.size() < 1 )
 
  723     currentPolygonElement = polygonList.at( 0 ).toElement();
 
  726     outerBoundaryList = currentPolygonElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"outerBoundaryIs" ) );
 
  727     if ( !outerBoundaryList.isEmpty() )
 
  729       currentOuterBoundaryElement = outerBoundaryList.at( 0 ).toElement();
 
  732       linearRingNodeList = currentOuterBoundaryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LinearRing" ) );
 
  733       if ( linearRingNodeList.size() < 1 )
 
  737       currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
 
  738       currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  739       if ( currentCoordinateList.size() < 1 )
 
  743       if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 )
 
  747       currentPolygonList.push_back( ringCoordinates );
 
  750       const QDomNodeList innerBoundaryList = currentPolygonElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"innerBoundaryIs" ) );
 
  751       for ( 
int j = 0; j < innerBoundaryList.size(); ++j )
 
  754         currentInnerBoundaryElement = innerBoundaryList.at( j ).toElement();
 
  755         linearRingNodeList = currentInnerBoundaryElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LinearRing" ) );
 
  756         if ( linearRingNodeList.size() < 1 )
 
  760         currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
 
  761         currentCoordinateList = currentLinearRingElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"coordinates" ) );
 
  762         if ( currentCoordinateList.size() < 1 )
 
  766         if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 )
 
  770         currentPolygonList.push_back( ringCoordinates );
 
  776       exteriorList = currentPolygonElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"exterior" ) );
 
  777       if ( exteriorList.size() < 1 )
 
  782       currentExteriorElement = exteriorList.at( 0 ).toElement();
 
  785       linearRingNodeList = currentExteriorElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LinearRing" ) );
 
  786       if ( linearRingNodeList.size() < 1 )
 
  790       currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
 
  791       currentPosList = currentLinearRingElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"posList" ) );
 
  792       if ( currentPosList.size() < 1 )
 
  796       if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 )
 
  800       currentPolygonList.push_back( ringPositions );
 
  803       const QDomNodeList interiorList = currentPolygonElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"interior" ) );
 
  804       for ( 
int j = 0; j < interiorList.size(); ++j )
 
  807         currentInteriorElement = interiorList.at( j ).toElement();
 
  808         linearRingNodeList = currentInteriorElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"LinearRing" ) );
 
  809         if ( linearRingNodeList.size() < 1 )
 
  813         currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
 
  814         currentPosList = currentLinearRingElement.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"posList" ) );
 
  815         if ( currentPosList.size() < 1 )
 
  819         if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 )
 
  823         currentPolygonList.push_back( ringPositions );
 
  826     multiPolygonPoints.push_back( currentPolygonList );
 
  829   int nPolygons = multiPolygonPoints.size();
 
  833   int size = 1 + 2 * 
sizeof( int );
 
  835   for ( QgsMultiPolygonXY::const_iterator it = multiPolygonPoints.constBegin(); it != multiPolygonPoints.constEnd(); ++it )
 
  837     size += 1 + 2 * 
sizeof( int );
 
  838     for ( QgsPolygonXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
 
  840       size += 
sizeof( int ) + 2 * iter->size() * 
sizeof( double );
 
  845   unsigned char *wkb = 
new unsigned char[size];
 
  847   char e = htonl( 1 ) != 1;
 
  854   memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  856   memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  857   wkbPosition += 
sizeof( int );
 
  858   memcpy( &( wkb )[wkbPosition], &nPolygons, 
sizeof( 
int ) );
 
  859   wkbPosition += 
sizeof( int );
 
  863   for ( QgsMultiPolygonXY::const_iterator it = multiPolygonPoints.constBegin(); it != multiPolygonPoints.constEnd(); ++it )
 
  865     memcpy( &( wkb )[wkbPosition], &e, 1 );
 
  867     memcpy( &( wkb )[wkbPosition], &type, 
sizeof( 
int ) );
 
  868     wkbPosition += 
sizeof( int );
 
  870     memcpy( &( wkb )[wkbPosition], &nRings, 
sizeof( 
int ) );
 
  871     wkbPosition += 
sizeof( int );
 
  872     for ( QgsPolygonXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
 
  874       nPointsInRing = iter->size();
 
  875       memcpy( &( wkb )[wkbPosition], &nPointsInRing, 
sizeof( 
int ) );
 
  876       wkbPosition += 
sizeof( int );
 
  877       for ( QgsPolylineXY::const_iterator iterator = iter->begin(); iterator != iter->end(); ++iterator )
 
  881         memcpy( &( wkb )[wkbPosition], &x, 
sizeof( 
double ) );
 
  882         wkbPosition += 
sizeof( double );
 
  883         memcpy( &( wkb )[wkbPosition], &y, 
sizeof( 
double ) );
 
  884         wkbPosition += 
sizeof( double );
 
  894 bool QgsOgcUtils::readGMLCoordinates( 
QgsPolylineXY &coords, 
const QDomElement &elem )
 
  896   QString coordSeparator = QStringLiteral( 
"," );
 
  897   QString tupelSeparator = QStringLiteral( 
" " );
 
  902   if ( elem.hasAttribute( QStringLiteral( 
"cs" ) ) )
 
  904     coordSeparator = elem.attribute( QStringLiteral( 
"cs" ) );
 
  906   if ( elem.hasAttribute( QStringLiteral( 
"ts" ) ) )
 
  908     tupelSeparator = elem.attribute( QStringLiteral( 
"ts" ) );
 
  911 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
  912   QStringList tupels = elem.text().split( tupelSeparator, QString::SkipEmptyParts );
 
  914   const QStringList tupels = elem.text().split( tupelSeparator, Qt::SkipEmptyParts );
 
  916   QStringList tuple_coords;
 
  918   bool conversionSuccess;
 
  920   QStringList::const_iterator it;
 
  921   for ( it = tupels.constBegin(); it != tupels.constEnd(); ++it )
 
  923 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
  924     tuple_coords = ( *it ).split( coordSeparator, QString::SkipEmptyParts );
 
  926     tuple_coords = ( *it ).split( coordSeparator, Qt::SkipEmptyParts );
 
  928     if ( tuple_coords.size() < 2 )
 
  932     x = tuple_coords.at( 0 ).toDouble( &conversionSuccess );
 
  933     if ( !conversionSuccess )
 
  937     y = tuple_coords.at( 1 ).toDouble( &conversionSuccess );
 
  938     if ( !conversionSuccess )
 
  951   const QDomElement boxElem = boxNode.toElement();
 
  952   if ( boxElem.tagName() != QLatin1String( 
"Box" ) )
 
  955   const QDomElement bElem = boxElem.firstChild().toElement();
 
  956   QString coordSeparator = QStringLiteral( 
"," );
 
  957   QString tupelSeparator = QStringLiteral( 
" " );
 
  958   if ( bElem.hasAttribute( QStringLiteral( 
"cs" ) ) )
 
  960     coordSeparator = bElem.attribute( QStringLiteral( 
"cs" ) );
 
  962   if ( bElem.hasAttribute( QStringLiteral( 
"ts" ) ) )
 
  964     tupelSeparator = bElem.attribute( QStringLiteral( 
"ts" ) );
 
  967   const QString bString = bElem.text();
 
  968   bool ok1, ok2, ok3, ok4;
 
  969   const double xmin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 0, 0 ).toDouble( &ok1 );
 
  970   const double ymin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 1, 1 ).toDouble( &ok2 );
 
  971   const double xmax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 0, 0 ).toDouble( &ok3 );
 
  972   const double ymax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 1, 1 ).toDouble( &ok4 );
 
  974   if ( ok1 && ok2 && ok3 && ok4 )
 
  983 bool QgsOgcUtils::readGMLPositions( 
QgsPolylineXY &coords, 
const QDomElement &elem )
 
  987 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
  988   QStringList pos = elem.text().split( 
' ', QString::SkipEmptyParts );
 
  990   const QStringList pos = elem.text().split( 
' ', Qt::SkipEmptyParts );
 
  993   bool conversionSuccess;
 
  994   const int posSize = pos.size();
 
  996   int srsDimension = 2;
 
  997   if ( elem.hasAttribute( QStringLiteral( 
"srsDimension" ) ) )
 
  999     srsDimension = elem.attribute( QStringLiteral( 
"srsDimension" ) ).toInt( &conversionSuccess );
 
 1000     if ( !conversionSuccess )
 
 1005   else if ( elem.hasAttribute( QStringLiteral( 
"dimension" ) ) )
 
 1007     srsDimension = elem.attribute( QStringLiteral( 
"dimension" ) ).toInt( &conversionSuccess );
 
 1008     if ( !conversionSuccess )
 
 1014   for ( 
int i = 0; i < posSize / srsDimension; i++ )
 
 1016     x = pos.at( i * srsDimension ).toDouble( &conversionSuccess );
 
 1017     if ( !conversionSuccess )
 
 1021     y = pos.at( i * srsDimension + 1 ).toDouble( &conversionSuccess );
 
 1022     if ( !conversionSuccess )
 
 1036   const QDomElement envelopeElem = envelopeNode.toElement();
 
 1037   if ( envelopeElem.tagName() != QLatin1String( 
"Envelope" ) )
 
 1040   const QDomNodeList lowerCornerList = envelopeElem.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"lowerCorner" ) );
 
 1041   if ( lowerCornerList.size() < 1 )
 
 1044   const QDomNodeList upperCornerList = envelopeElem.elementsByTagNameNS( 
GML_NAMESPACE, QStringLiteral( 
"upperCorner" ) );
 
 1045   if ( upperCornerList.size() < 1 )
 
 1048   bool conversionSuccess;
 
 1049   int srsDimension = 2;
 
 1051   QDomElement elem = lowerCornerList.at( 0 ).toElement();
 
 1052   if ( elem.hasAttribute( QStringLiteral( 
"srsDimension" ) ) )
 
 1054     srsDimension = elem.attribute( QStringLiteral( 
"srsDimension" ) ).toInt( &conversionSuccess );
 
 1055     if ( !conversionSuccess )
 
 1060   else if ( elem.hasAttribute( QStringLiteral( 
"dimension" ) ) )
 
 1062     srsDimension = elem.attribute( QStringLiteral( 
"dimension" ) ).toInt( &conversionSuccess );
 
 1063     if ( !conversionSuccess )
 
 1068   QString bString = elem.text();
 
 1070   const double xmin = bString.section( 
' ', 0, 0 ).toDouble( &conversionSuccess );
 
 1071   if ( !conversionSuccess )
 
 1073   const double ymin = bString.section( 
' ', 1, 1 ).toDouble( &conversionSuccess );
 
 1074   if ( !conversionSuccess )
 
 1077   elem = upperCornerList.at( 0 ).toElement();
 
 1078   if ( elem.hasAttribute( QStringLiteral( 
"srsDimension" ) ) )
 
 1080     srsDimension = elem.attribute( QStringLiteral( 
"srsDimension" ) ).toInt( &conversionSuccess );
 
 1081     if ( !conversionSuccess )
 
 1086   else if ( elem.hasAttribute( QStringLiteral( 
"dimension" ) ) )
 
 1088     srsDimension = elem.attribute( QStringLiteral( 
"dimension" ) ).toInt( &conversionSuccess );
 
 1089     if ( !conversionSuccess )
 
 1095   Q_UNUSED( srsDimension )
 
 1097   bString = elem.text();
 
 1098   const double xmax = bString.section( 
' ', 0, 0 ).toDouble( &conversionSuccess );
 
 1099   if ( !conversionSuccess )
 
 1101   const double ymax = bString.section( 
' ', 1, 1 ).toDouble( &conversionSuccess );
 
 1102   if ( !conversionSuccess )
 
 1118     bool invertAxisOrientation,
 
 1123     return QDomElement();
 
 1126   QDomElement boxElem = doc.createElement( QStringLiteral( 
"gml:Box" ) );
 
 1129     boxElem.setAttribute( QStringLiteral( 
"srsName" ), 
srsName );
 
 1131   QDomElement coordElem = doc.createElement( QStringLiteral( 
"gml:coordinates" ) );
 
 1132   coordElem.setAttribute( QStringLiteral( 
"cs" ), QStringLiteral( 
"," ) );
 
 1133   coordElem.setAttribute( QStringLiteral( 
"ts" ), QStringLiteral( 
" " ) );
 
 1135   QString coordString;
 
 1144   const QDomText coordText = doc.createTextNode( coordString );
 
 1145   coordElem.appendChild( coordText );
 
 1146   boxElem.appendChild( coordElem );
 
 1158     bool invertAxisOrientation,
 
 1163     return QDomElement();
 
 1166   QDomElement envElem = doc.createElement( QStringLiteral( 
"gml:Envelope" ) );
 
 1169     envElem.setAttribute( QStringLiteral( 
"srsName" ), 
srsName );
 
 1173   QDomElement lowerCornerElem = doc.createElement( QStringLiteral( 
"gml:lowerCorner" ) );
 
 1177   const QDomText lowerCornerText = doc.createTextNode( posList );
 
 1178   lowerCornerElem.appendChild( lowerCornerText );
 
 1179   envElem.appendChild( lowerCornerElem );
 
 1181   QDomElement upperCornerElem = doc.createElement( QStringLiteral( 
"gml:upperCorner" ) );
 
 1185   const QDomText upperCornerText = doc.createTextNode( posList );
 
 1186   upperCornerElem.appendChild( upperCornerText );
 
 1187   envElem.appendChild( upperCornerElem );
 
 1201                                         bool invertAxisOrientation,
 
 1202                                         const QString &gmlIdBase,
 
 1206     return QDomElement();
 
 1209   QString cs = QStringLiteral( 
"," );
 
 1211   const QString ts = QStringLiteral( 
" " );
 
 1213   QDomElement baseCoordElem;
 
 1215   bool hasZValue = 
false;
 
 1217   const QByteArray wkb( geometry.
asWkb() );
 
 1227     return QDomElement();
 
 1238         baseCoordElem = doc.createElement( QStringLiteral( 
"gml:pos" ) );
 
 1241         baseCoordElem = doc.createElement( QStringLiteral( 
"gml:posList" ) );
 
 1244     baseCoordElem.setAttribute( QStringLiteral( 
"srsDimension" ), QStringLiteral( 
"2" ) );
 
 1249     baseCoordElem = doc.createElement( QStringLiteral( 
"gml:coordinates" ) );
 
 1250     baseCoordElem.setAttribute( QStringLiteral( 
"cs" ), cs );
 
 1251     baseCoordElem.setAttribute( QStringLiteral( 
"ts" ), ts );
 
 1261         QDomElement pointElem = doc.createElement( QStringLiteral( 
"gml:Point" ) );
 
 1262         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1263           pointElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1265           pointElem.setAttribute( QStringLiteral( 
"srsName" ), 
srsName );
 
 1266         QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1270         if ( invertAxisOrientation )
 
 1276         coordElem.appendChild( coordText );
 
 1277         pointElem.appendChild( coordElem );
 
 1286         QDomElement multiPointElem = doc.createElement( QStringLiteral( 
"gml:MultiPoint" ) );
 
 1287         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1288           multiPointElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1290           multiPointElem.setAttribute( QStringLiteral( 
"srsName" ), 
srsName );
 
 1295         for ( 
int idx = 0; idx < nPoints; ++idx )
 
 1297           QDomElement pointMemberElem = doc.createElement( QStringLiteral( 
"gml:pointMember" ) );
 
 1298           QDomElement pointElem = doc.createElement( QStringLiteral( 
"gml:Point" ) );
 
 1299           if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1300             pointElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase + QStringLiteral( 
".%1" ).arg( idx + 1 ) );
 
 1301           QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1307           if ( invertAxisOrientation )
 
 1313           coordElem.appendChild( coordText );
 
 1314           pointElem.appendChild( coordElem );
 
 1318             wkbPtr += 
sizeof( double );
 
 1320           pointMemberElem.appendChild( pointElem );
 
 1321           multiPointElem.appendChild( pointMemberElem );
 
 1323         return multiPointElem;
 
 1331         QDomElement lineStringElem = doc.createElement( QStringLiteral( 
"gml:LineString" ) );
 
 1332         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1333           lineStringElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1335           lineStringElem.setAttribute( QStringLiteral( 
"srsName" ), 
srsName );
 
 1341         QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1342         QString coordString;
 
 1343         for ( 
int idx = 0; idx < nPoints; ++idx )
 
 1352           if ( invertAxisOrientation )
 
 1360             wkbPtr += 
sizeof( double );
 
 1363         const QDomText coordText = doc.createTextNode( coordString );
 
 1364         coordElem.appendChild( coordText );
 
 1365         lineStringElem.appendChild( coordElem );
 
 1366         return lineStringElem;
 
 1374         QDomElement multiLineStringElem = doc.createElement( QStringLiteral( 
"gml:MultiLineString" ) );
 
 1375         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1376           multiLineStringElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1378           multiLineStringElem.setAttribute( QStringLiteral( 
"srsName" ), 
srsName );
 
 1383         for ( 
int jdx = 0; jdx < nLines; jdx++ )
 
 1385           QDomElement lineStringMemberElem = doc.createElement( QStringLiteral( 
"gml:lineStringMember" ) );
 
 1386           QDomElement lineStringElem = doc.createElement( QStringLiteral( 
"gml:LineString" ) );
 
 1387           if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1388             lineStringElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase + QStringLiteral( 
".%1" ).arg( jdx + 1 ) );
 
 1395           QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1396           QString coordString;
 
 1397           for ( 
int idx = 0; idx < nPoints; idx++ )
 
 1406             if ( invertAxisOrientation )
 
 1415               wkbPtr += 
sizeof( double );
 
 1418           const QDomText coordText = doc.createTextNode( coordString );
 
 1419           coordElem.appendChild( coordText );
 
 1420           lineStringElem.appendChild( coordElem );
 
 1421           lineStringMemberElem.appendChild( lineStringElem );
 
 1422           multiLineStringElem.appendChild( lineStringMemberElem );
 
 1424         return multiLineStringElem;
 
 1432         QDomElement polygonElem = doc.createElement( QStringLiteral( 
"gml:Polygon" ) );
 
 1433         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1434           polygonElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1436           polygonElem.setAttribute( QStringLiteral( 
"srsName" ), 
srsName );
 
 1442         if ( numRings == 0 ) 
 
 1443           return QDomElement();
 
 1445         for ( 
int idx = 0; idx < numRings; idx++ )
 
 1447           QString boundaryName = ( gmlVersion == 
GML_2_1_2 ) ? 
"gml:outerBoundaryIs" : 
"gml:exterior";
 
 1450             boundaryName = ( gmlVersion == 
GML_2_1_2 ) ? 
"gml:innerBoundaryIs" : 
"gml:interior";
 
 1452           QDomElement boundaryElem = doc.createElement( boundaryName );
 
 1453           QDomElement ringElem = doc.createElement( QStringLiteral( 
"gml:LinearRing" ) );
 
 1458           QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1459           QString coordString;
 
 1460           for ( 
int jdx = 0; jdx < nPoints; jdx++ )
 
 1469             if ( invertAxisOrientation )
 
 1477               wkbPtr += 
sizeof( double );
 
 1480           const QDomText coordText = doc.createTextNode( coordString );
 
 1481           coordElem.appendChild( coordText );
 
 1482           ringElem.appendChild( coordElem );
 
 1483           boundaryElem.appendChild( ringElem );
 
 1484           polygonElem.appendChild( boundaryElem );
 
 1494         QDomElement multiPolygonElem = doc.createElement( QStringLiteral( 
"gml:MultiPolygon" ) );
 
 1495         if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1496           multiPolygonElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase );
 
 1498           multiPolygonElem.setAttribute( QStringLiteral( 
"srsName" ), 
srsName );
 
 1501         wkbPtr >> numPolygons;
 
 1503         for ( 
int kdx = 0; kdx < numPolygons; kdx++ )
 
 1505           QDomElement polygonMemberElem = doc.createElement( QStringLiteral( 
"gml:polygonMember" ) );
 
 1506           QDomElement polygonElem = doc.createElement( QStringLiteral( 
"gml:Polygon" ) );
 
 1507           if ( gmlVersion == 
GML_3_2_1 && !gmlIdBase.isEmpty() )
 
 1508             polygonElem.setAttribute( QStringLiteral( 
"gml:id" ), gmlIdBase + QStringLiteral( 
".%1" ).arg( kdx + 1 ) );
 
 1515           for ( 
int idx = 0; idx < numRings; idx++ )
 
 1517             QString boundaryName = ( gmlVersion == 
GML_2_1_2 ) ? 
"gml:outerBoundaryIs" : 
"gml:exterior";
 
 1520               boundaryName = ( gmlVersion == 
GML_2_1_2 ) ? 
"gml:innerBoundaryIs" : 
"gml:interior";
 
 1522             QDomElement boundaryElem = doc.createElement( boundaryName );
 
 1523             QDomElement ringElem = doc.createElement( QStringLiteral( 
"gml:LinearRing" ) );
 
 1528             QDomElement coordElem = baseCoordElem.cloneNode().toElement();
 
 1529             QString coordString;
 
 1530             for ( 
int jdx = 0; jdx < nPoints; jdx++ )
 
 1539               if ( invertAxisOrientation )
 
 1548                 wkbPtr += 
sizeof( double );
 
 1551             const QDomText coordText = doc.createTextNode( coordString );
 
 1552             coordElem.appendChild( coordText );
 
 1553             ringElem.appendChild( coordElem );
 
 1554             boundaryElem.appendChild( ringElem );
 
 1555             polygonElem.appendChild( boundaryElem );
 
 1556             polygonMemberElem.appendChild( polygonElem );
 
 1557             multiPolygonElem.appendChild( polygonMemberElem );
 
 1560         return multiPolygonElem;
 
 1563         return QDomElement();
 
 1569     return QDomElement();
 
 1578 QDomElement QgsOgcUtils::createGMLCoordinates( 
const QgsPolylineXY &points, QDomDocument &doc )
 
 1580   QDomElement coordElem = doc.createElement( QStringLiteral( 
"gml:coordinates" ) );
 
 1581   coordElem.setAttribute( QStringLiteral( 
"cs" ), QStringLiteral( 
"," ) );
 
 1582   coordElem.setAttribute( QStringLiteral( 
"ts" ), QStringLiteral( 
" " ) );
 
 1584   QString coordString;
 
 1585   QVector<QgsPointXY>::const_iterator pointIt = points.constBegin();
 
 1586   for ( ; pointIt != points.constEnd(); ++pointIt )
 
 1588     if ( pointIt != points.constBegin() )
 
 1597   const QDomText coordText = doc.createTextNode( coordString );
 
 1598   coordElem.appendChild( coordText );
 
 1602 QDomElement QgsOgcUtils::createGMLPositions( 
const QgsPolylineXY &points, QDomDocument &doc )
 
 1604   QDomElement posElem = doc.createElement( QStringLiteral( 
"gml:pos" ) );
 
 1605   if ( points.size() > 1 )
 
 1606     posElem = doc.createElement( QStringLiteral( 
"gml:posList" ) );
 
 1607   posElem.setAttribute( QStringLiteral( 
"srsDimension" ), QStringLiteral( 
"2" ) );
 
 1609   QString coordString;
 
 1610   QVector<QgsPointXY>::const_iterator pointIt = points.constBegin();
 
 1611   for ( ; pointIt != points.constEnd(); ++pointIt )
 
 1613     if ( pointIt != points.constBegin() )
 
 1622   const QDomText coordText = doc.createTextNode( coordString );
 
 1623   posElem.appendChild( coordText );
 
 1633   if ( fillElement.isNull() || !fillElement.hasChildNodes() )
 
 1641   QDomElement cssElem = fillElement.firstChildElement( QStringLiteral( 
"CssParameter" ) );
 
 1642   while ( !cssElem.isNull() )
 
 1644     cssName = cssElem.attribute( QStringLiteral( 
"name" ), QStringLiteral( 
"not_found" ) );
 
 1645     if ( cssName != QLatin1String( 
"not_found" ) )
 
 1647       elemText = cssElem.text();
 
 1648       if ( cssName == QLatin1String( 
"fill" ) )
 
 1650         color.setNamedColor( elemText );
 
 1652       else if ( cssName == QLatin1String( 
"fill-opacity" ) )
 
 1655         const double opacity = elemText.toDouble( &ok );
 
 1658           color.setAlphaF( opacity );
 
 1663     cssElem = cssElem.nextSiblingElement( QStringLiteral( 
"CssParameter" ) );
 
 1677   if ( element.isNull() || !element.hasChildNodes() )
 
 1684   if ( element.firstChild().nodeType() == QDomNode::TextNode )
 
 1694   QDomElement childElem = element.firstChildElement();
 
 1695   while ( !childElem.isNull() )
 
 1707     if ( !expr->d->mRootNode )
 
 1709       expr->d->mRootNode = node;
 
 1716     childElem = childElem.nextSiblingElement();
 
 1720   expr->d->mExp = expr->
dump();
 
 1746 static 
int binaryOperatorFromTagName( const QString &tagName )
 
 1749   return BINARY_OPERATORS_TAG_NAMES_MAP()->value( tagName, -1 );
 
 1756     return QStringLiteral( 
"PropertyIsLike" );
 
 1758   return BINARY_OPERATORS_TAG_NAMES_MAP()->key( op, QString() );
 
 1761 static bool isBinaryOperator( 
const QString &tagName )
 
 1763   return binaryOperatorFromTagName( tagName ) >= 0;
 
 1767 static bool isSpatialOperator( 
const QString &tagName )
 
 1769   static QStringList spatialOps;
 
 1770   if ( spatialOps.isEmpty() )
 
 1772     spatialOps << QStringLiteral( 
"BBOX" ) << QStringLiteral( 
"Intersects" ) << QStringLiteral( 
"Contains" ) << QStringLiteral( 
"Crosses" ) << QStringLiteral( 
"Equals" )
 
 1773                << QStringLiteral( 
"Disjoint" ) << QStringLiteral( 
"Overlaps" ) << QStringLiteral( 
"Touches" ) << QStringLiteral( 
"Within" );
 
 1776   return spatialOps.contains( tagName );
 
 1783   errorMessage = utils.errorMessage();
 
 1791   errorMessage = utils.errorMessage();
 
 1799   errorMessage = utils.errorMessage();
 
 1807   errorMessage = utils.errorMessage();
 
 1815   errorMessage = utils.errorMessage();
 
 1823   errorMessage = utils.errorMessage();
 
 1831   errorMessage = utils.errorMessage();
 
 1835 QgsExpressionNode *QgsOgcUtils::nodeIsBetweenFromOgcFilter( QDomElement &element, QString &errorMessage )
 
 1839   errorMessage = utils.errorMessage();
 
 1847   errorMessage = utils.errorMessage();
 
 1858                                 QStringLiteral( 
"geometry" ), QString(), 
false, 
false, errorMessage );
 
 1864                                     QStringLiteral( 
"geometry" ), QString(), 
false, 
false, errorMessage );
 
 1873     bool honourAxisOrientation,
 
 1874     bool invertAxisOrientation,
 
 1875     QString *errorMessage )
 
 1878     return QDomElement();
 
 1888   if ( exprRootElem.isNull() )
 
 1889     return QDomElement();
 
 1891   QDomElement filterElem =
 
 1893     doc.createElementNS( 
FES_NAMESPACE, QStringLiteral( 
"fes:Filter" ) ) :
 
 1894     doc.createElementNS( 
OGC_NAMESPACE, QStringLiteral( 
"ogc:Filter" ) );
 
 1897     QDomAttr attr = doc.createAttribute( QStringLiteral( 
"xmlns:gml" ) );
 
 1902     filterElem.setAttributeNode( attr );
 
 1904   filterElem.appendChild( exprRootElem );
 
 1914     bool honourAxisOrientation,
 
 1915     bool invertAxisOrientation,
 
 1916     QString *errorMessage )
 
 1925     return QDomElement();
 
 1939       if ( !exprRootElem.isNull() )
 
 1941         return exprRootElem;
 
 1948         *errorMessage = QObject::tr( 
"Node type not supported in expression translation: %1" ).arg( node->
nodeType() );
 
 1952   return QDomElement();
 
 1959     const QList<LayerProperties> &layerProperties,
 
 1960     bool honourAxisOrientation,
 
 1961     bool invertAxisOrientation,
 
 1962     const QMap< QString, QString> &mapUnprefixedTypenameToPrefixedTypename,
 
 1963     QString *errorMessage )
 
 1966     return QDomElement();
 
 1969                                          layerProperties, honourAxisOrientation, invertAxisOrientation,
 
 1970                                          mapUnprefixedTypenameToPrefixedTypename );
 
 1974   if ( exprRootElem.isNull() )
 
 1975     return QDomElement();
 
 1977   QDomElement filterElem =
 
 1979     doc.createElementNS( 
FES_NAMESPACE, QStringLiteral( 
"fes:Filter" ) ) :
 
 1980     doc.createElementNS( 
OGC_NAMESPACE, QStringLiteral( 
"ogc:Filter" ) );
 
 1983     QDomAttr attr = doc.createAttribute( QStringLiteral( 
"xmlns:gml" ) );
 
 1988     filterElem.setAttributeNode( attr );
 
 1991   QSet<QString> setNamespaceURI;
 
 1994     if ( !props.mNamespacePrefix.isEmpty() && !props.mNamespaceURI.isEmpty() &&
 
 1995          !setNamespaceURI.contains( props.mNamespaceURI ) )
 
 1997       setNamespaceURI.insert( props.mNamespaceURI );
 
 1998       QDomAttr attr = doc.createAttribute( QStringLiteral( 
"xmlns:" ) + props.mNamespacePrefix );
 
 1999       attr.setValue( props.mNamespaceURI );
 
 2000       filterElem.setAttributeNode( attr );
 
 2004   filterElem.appendChild( exprRootElem );
 
 2029       mErrorMessage = QObject::tr( 
"Node type not supported: %1" ).arg( node->
nodeType() );
 
 2030       return QDomElement();
 
 2037   if ( !mErrorMessage.isEmpty() )
 
 2038     return QDomElement();
 
 2041   switch ( node->
op() )
 
 2044       uoElem = mDoc.createElement( mFilterPrefix + 
":Literal" );
 
 2049         uoElem.appendChild( mDoc.createTextNode( 
"-" + operandElem.text() ) );
 
 2050         mDoc.removeChild( operandElem );
 
 2054         mErrorMessage = QObject::tr( 
"This use of unary operator not implemented yet" );
 
 2055         return QDomElement();
 
 2059       uoElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2060       uoElem.appendChild( operandElem );
 
 2064       mErrorMessage = QObject::tr( 
"Unary operator '%1' not implemented yet" ).arg( node->
text() );
 
 2065       return QDomElement();
 
 2075   if ( !mErrorMessage.isEmpty() )
 
 2076     return QDomElement();
 
 2086       if ( rightLit->
value().isNull() )
 
 2089         QDomElement elem = mDoc.createElement( mFilterPrefix + 
":PropertyIsNull" );
 
 2090         elem.appendChild( leftElem );
 
 2094           QDomElement notElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2095           notElem.appendChild( elem );
 
 2109   if ( !mErrorMessage.isEmpty() )
 
 2110     return QDomElement();
 
 2113   const QString opText = binaryOperatorToTagName( op );
 
 2114   if ( opText.isEmpty() )
 
 2118     mErrorMessage = QObject::tr( 
"Binary operator %1 not implemented yet" ).arg( node->
text() );
 
 2119     return QDomElement();
 
 2122   QDomElement boElem = mDoc.createElement( mFilterPrefix + 
":" + opText );
 
 2127       boElem.setAttribute( QStringLiteral( 
"matchCase" ), QStringLiteral( 
"false" ) );
 
 2130     boElem.setAttribute( QStringLiteral( 
"wildCard" ), QStringLiteral( 
"%" ) );
 
 2131     boElem.setAttribute( QStringLiteral( 
"singleChar" ), QStringLiteral( 
"_" ) );
 
 2133       boElem.setAttribute( QStringLiteral( 
"escape" ), QStringLiteral( 
"\\" ) );
 
 2135       boElem.setAttribute( QStringLiteral( 
"escapeChar" ), QStringLiteral( 
"\\" ) );
 
 2138   boElem.appendChild( leftElem );
 
 2139   boElem.appendChild( rightElem );
 
 2146   Q_UNUSED( expression )
 
 2149   switch ( node->
value().type() )
 
 2152       value = QString::number( node->
value().toInt() );
 
 2154     case QVariant::Double:
 
 2157     case QVariant::String:
 
 2158       value = node->
value().toString();
 
 2160     case QVariant::Date:
 
 2161       value = node->
value().toDate().toString( Qt::ISODate );
 
 2163     case QVariant::DateTime:
 
 2164       value = node->
value().toDateTime().toString( Qt::ISODate );
 
 2168       mErrorMessage = QObject::tr( 
"Literal type not supported: %1" ).arg( node->
value().type() );
 
 2169       return QDomElement();
 
 2172   QDomElement litElem = mDoc.createElement( mFilterPrefix + 
":Literal" );
 
 2173   litElem.appendChild( mDoc.createTextNode( value ) );
 
 2180   Q_UNUSED( expression )
 
 2182   QDomElement propElem = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 2183   propElem.appendChild( mDoc.createTextNode( node->
name() ) );
 
 2191   if ( node->
list()->
list().size() == 1 )
 
 2194   QDomElement orElem = mDoc.createElement( mFilterPrefix + 
":Or" );
 
 2197   const auto constList = node->
list()->
list();
 
 2201     if ( !mErrorMessage.isEmpty() )
 
 2202       return QDomElement();
 
 2204     QDomElement eqElem = mDoc.createElement( mFilterPrefix + 
":PropertyIsEqualTo" );
 
 2205     eqElem.appendChild( leftNode.cloneNode() );
 
 2206     eqElem.appendChild( listNode );
 
 2208     orElem.appendChild( eqElem );
 
 2213     QDomElement notElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2214     notElem.appendChild( orElem );
 
 2223   { QLatin1String( 
"disjoint" ),   QLatin1String( 
"Disjoint" ) },
 
 2224   { QLatin1String( 
"intersects" ), QLatin1String( 
"Intersects" )},
 
 2225   { QLatin1String( 
"touches" ),    QLatin1String( 
"Touches" ) },
 
 2226   { QLatin1String( 
"crosses" ),    QLatin1String( 
"Crosses" ) },
 
 2227   { QLatin1String( 
"contains" ),   QLatin1String( 
"Contains" ) },
 
 2228   { QLatin1String( 
"overlaps" ),   QLatin1String( 
"Overlaps" ) },
 
 2229   { QLatin1String( 
"within" ),     QLatin1String( 
"Within" ) }
 
 2232 static 
bool isBinarySpatialOperator( const QString &fnName )
 
 2234   return BINARY_SPATIAL_OPS_MAP()->contains( fnName );
 
 2237 static QString tagNameForSpatialOperator( 
const QString &fnName )
 
 2239   return BINARY_SPATIAL_OPS_MAP()->value( fnName );
 
 2249   return fd->
name() == QLatin1String( 
"$geometry" );
 
 2261     if ( fnDef->
name() == QLatin1String( 
"geom_from_wkt" ) )
 
 2263       const QList<QgsExpressionNode *> &args = fnNode->
args()->
list();
 
 2279   if ( fd->
name() == QLatin1String( 
"intersects_bbox" ) )
 
 2281     QList<QgsExpressionNode *> argNodes = node->
args()->
list();
 
 2282     Q_ASSERT( argNodes.count() == 2 ); 
 
 2284     const QgsGeometry geom = geometryFromConstExpr( argNodes[1] );
 
 2285     if ( !geom.
isNull() && isGeometryColumn( argNodes[0] ) )
 
 2295       QDomElement geomProperty = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 2296       geomProperty.appendChild( mDoc.createTextNode( mGeometryName ) );
 
 2298       QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":BBOX" );
 
 2299       funcElem.appendChild( geomProperty );
 
 2300       funcElem.appendChild( elemBox );
 
 2305       mErrorMessage = QObject::tr( 
"<BBOX> is currently supported only in form: bbox($geometry, geomFromWKT('…'))" );
 
 2306       return QDomElement();
 
 2310   if ( isBinarySpatialOperator( fd->
name() ) )
 
 2312     QList<QgsExpressionNode *> argNodes = node->
args()->
list();
 
 2313     Q_ASSERT( argNodes.count() == 2 ); 
 
 2316     if ( isGeometryColumn( argNodes[0] ) )
 
 2317       otherNode = argNodes[1];
 
 2318     else if ( isGeometryColumn( argNodes[1] ) )
 
 2319       otherNode = argNodes[0];
 
 2322       mErrorMessage = QObject::tr( 
"Unable to translate spatial operator: at least one must refer to geometry." );
 
 2323       return QDomElement();
 
 2326     QDomElement otherGeomElem;
 
 2331       mErrorMessage = QObject::tr( 
"spatial operator: the other operator must be a geometry constructor function" );
 
 2332       return QDomElement();
 
 2337     if ( otherFnDef->
name() == QLatin1String( 
"geom_from_wkt" ) )
 
 2342         mErrorMessage = QObject::tr( 
"geom_from_wkt: argument must be string literal" );
 
 2343         return QDomElement();
 
 2348                       QStringLiteral( 
"qgis_id_geom_%1" ).arg( mGeomId ) );
 
 2351     else if ( otherFnDef->
name() == QLatin1String( 
"geom_from_gml" ) )
 
 2356         mErrorMessage = QObject::tr( 
"geom_from_gml: argument must be string literal" );
 
 2357         return QDomElement();
 
 2360       QDomDocument geomDoc;
 
 2362       if ( !geomDoc.setContent( gml, 
true ) )
 
 2364         mErrorMessage = QObject::tr( 
"geom_from_gml: unable to parse XML" );
 
 2365         return QDomElement();
 
 2368       const QDomNode geomNode = mDoc.importNode( geomDoc.documentElement(), 
true );
 
 2369       otherGeomElem = geomNode.toElement();
 
 2373       mErrorMessage = QObject::tr( 
"spatial operator: unknown geometry constructor function" );
 
 2374       return QDomElement();
 
 2379     QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":" + tagNameForSpatialOperator( fd->
name() ) );
 
 2380     QDomElement geomProperty = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 2381     geomProperty.appendChild( mDoc.createTextNode( mGeometryName ) );
 
 2382     funcElem.appendChild( geomProperty );
 
 2383     funcElem.appendChild( otherGeomElem );
 
 2387   if ( fd->
isStatic( node, expression, context ) )
 
 2389     const QVariant result = fd->
run( node->
args(), context, expression, node );
 
 2391     return expressionLiteralToOgcFilter( &literal, expression, context );
 
 2396     mErrorMessage = QObject::tr( 
"Special columns/constants are not supported." );
 
 2397     return QDomElement();
 
 2401   QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":Function" );
 
 2402   funcElem.setAttribute( QStringLiteral( 
"name" ), fd->
name() );
 
 2403   const auto constList = node->
args()->
list();
 
 2407     if ( !mErrorMessage.isEmpty() )
 
 2408       return QDomElement();
 
 2410     funcElem.appendChild( childElem );
 
 2421     const QList<QgsOgcUtils::LayerProperties> &layerProperties,
 
 2422     bool honourAxisOrientation,
 
 2423     bool invertAxisOrientation,
 
 2424     const QMap< QString, QString> &mapUnprefixedTypenameToPrefixedTypename )
 
 2427   , mGMLVersion( gmlVersion )
 
 2428   , mFilterVersion( filterVersion )
 
 2429   , mLayerProperties( layerProperties )
 
 2430   , mHonourAxisOrientation( honourAxisOrientation )
 
 2431   , mInvertAxisOrientation( invertAxisOrientation )
 
 2432   , mFilterPrefix( ( filterVersion == 
QgsOgcUtils::FILTER_FES_2_0 ) ? 
"fes" : 
"ogc" )
 
 2433   , mPropertyName( ( filterVersion == 
QgsOgcUtils::FILTER_FES_2_0 ) ? 
"ValueReference" : 
"PropertyName" )
 
 2435   , mMapUnprefixedTypenameToPrefixedTypename( mapUnprefixedTypenameToPrefixedTypename )
 
 2461       mErrorMessage = QObject::tr( 
"Node type not supported: %1" ).arg( node->
nodeType() );
 
 2462       return QDomElement();
 
 2471   if ( !mErrorMessage.isEmpty() )
 
 2472     return QDomElement();
 
 2475   switch ( node->
op() )
 
 2478       uoElem = mDoc.createElement( mFilterPrefix + 
":Literal" );
 
 2483         uoElem.appendChild( mDoc.createTextNode( 
"-" + operandElem.text() ) );
 
 2484         mDoc.removeChild( operandElem );
 
 2488         mErrorMessage = QObject::tr( 
"This use of unary operator not implemented yet" );
 
 2489         return QDomElement();
 
 2493       uoElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2494       uoElem.appendChild( operandElem );
 
 2499       return QDomElement();
 
 2509   if ( !mErrorMessage.isEmpty() )
 
 2510     return QDomElement();
 
 2520       if ( rightLit->
value().isNull() )
 
 2523         QDomElement elem = mDoc.createElement( mFilterPrefix + 
":PropertyIsNull" );
 
 2524         elem.appendChild( leftElem );
 
 2528           QDomElement notElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2529           notElem.appendChild( elem );
 
 2543   if ( !mErrorMessage.isEmpty() )
 
 2544     return QDomElement();
 
 2549     opText = QStringLiteral( 
"Or" );
 
 2551     opText = QStringLiteral( 
"And" );
 
 2553     opText = QStringLiteral( 
"PropertyIsEqualTo" );
 
 2555     opText = QStringLiteral( 
"PropertyIsNotEqualTo" );
 
 2557     opText = QStringLiteral( 
"PropertyIsLessThanOrEqualTo" );
 
 2559     opText = QStringLiteral( 
"PropertyIsGreaterThanOrEqualTo" );
 
 2561     opText = QStringLiteral( 
"PropertyIsLessThan" );
 
 2563     opText = QStringLiteral( 
"PropertyIsGreaterThan" );
 
 2565     opText = QStringLiteral( 
"PropertyIsLike" );
 
 2567     opText = QStringLiteral( 
"PropertyIsLike" );
 
 2569   if ( opText.isEmpty() )
 
 2573     return QDomElement();
 
 2576   QDomElement boElem = mDoc.createElement( mFilterPrefix + 
":" + opText );
 
 2581       boElem.setAttribute( QStringLiteral( 
"matchCase" ), QStringLiteral( 
"false" ) );
 
 2584     boElem.setAttribute( QStringLiteral( 
"wildCard" ), QStringLiteral( 
"%" ) );
 
 2585     boElem.setAttribute( QStringLiteral( 
"singleChar" ), QStringLiteral( 
"_" ) );
 
 2587       boElem.setAttribute( QStringLiteral( 
"escape" ), QStringLiteral( 
"\\" ) );
 
 2589       boElem.setAttribute( QStringLiteral( 
"escapeChar" ), QStringLiteral( 
"\\" ) );
 
 2592   boElem.appendChild( leftElem );
 
 2593   boElem.appendChild( rightElem );
 
 2601   switch ( node->
value().type() )
 
 2604       value = QString::number( node->
value().toInt() );
 
 2606     case QVariant::LongLong:
 
 2607       value = QString::number( node->
value().toLongLong() );
 
 2609     case QVariant::Double:
 
 2612     case QVariant::String:
 
 2613       value = node->
value().toString();
 
 2617       mErrorMessage = QObject::tr( 
"Literal type not supported: %1" ).arg( node->
value().type() );
 
 2618       return QDomElement();
 
 2621   QDomElement litElem = mDoc.createElement( mFilterPrefix + 
":Literal" );
 
 2622   litElem.appendChild( mDoc.createTextNode( value ) );
 
 2629   QDomElement propElem = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 2630   if ( node->
tableName().isEmpty() || mLayerProperties.size() == 1 )
 
 2632     if ( mLayerProperties.size() == 1 && !mLayerProperties[0].mNamespacePrefix.isEmpty() )
 
 2633       propElem.appendChild( mDoc.createTextNode(
 
 2634                               mLayerProperties[0].mNamespacePrefix + QStringLiteral( 
":" ) + node->
name() ) );
 
 2636       propElem.appendChild( mDoc.createTextNode( node->
name() ) );
 
 2640     QString tableName( mMapTableAliasToNames[node->
tableName()] );
 
 2641     if ( mMapUnprefixedTypenameToPrefixedTypename.contains( tableName ) )
 
 2642       tableName = mMapUnprefixedTypenameToPrefixedTypename[tableName];
 
 2643     propElem.appendChild( mDoc.createTextNode( tableName + 
"/" + node->
name() ) );
 
 2650   if ( node->
list()->
list().size() == 1 )
 
 2653   QDomElement orElem = mDoc.createElement( mFilterPrefix + 
":Or" );
 
 2656   const auto constList = node->
list()->
list();
 
 2660     if ( !mErrorMessage.isEmpty() )
 
 2661       return QDomElement();
 
 2663     QDomElement eqElem = mDoc.createElement( mFilterPrefix + 
":PropertyIsEqualTo" );
 
 2664     eqElem.appendChild( leftNode.cloneNode() );
 
 2665     eqElem.appendChild( listNode );
 
 2667     orElem.appendChild( eqElem );
 
 2672     QDomElement notElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2673     notElem.appendChild( orElem );
 
 2682   QDomElement elem = mDoc.createElement( mFilterPrefix + 
":PropertyIsBetween" );
 
 2684   QDomElement lowerBoundary = mDoc.createElement( mFilterPrefix + 
":LowerBoundary" );
 
 2686   elem.appendChild( lowerBoundary );
 
 2687   QDomElement upperBoundary = mDoc.createElement( mFilterPrefix + 
":UpperBoundary" );
 
 2689   elem.appendChild( upperBoundary );
 
 2693     QDomElement notElem = mDoc.createElement( mFilterPrefix + 
":Not" );
 
 2694     notElem.appendChild( elem );
 
 2701 static QString mapBinarySpatialToOgc( 
const QString &name )
 
 2703   QString nameCompare( name );
 
 2704 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 2) 
 2705   if ( name.size() > 3 && name.midRef( 0, 3 ).compare( QLatin1String( 
"ST_" ), Qt::CaseInsensitive ) == 0 )
 
 2706     nameCompare = name.mid( 3 );
 
 2708   if ( name.size() > 3 && QStringView {name}.mid( 0, 3 ).toString().compare( QLatin1String( 
"ST_" ), Qt::CaseInsensitive ) == 0 )
 
 2709     nameCompare = name.mid( 3 );
 
 2711   QStringList spatialOps;
 
 2712   spatialOps << QStringLiteral( 
"BBOX" ) << QStringLiteral( 
"Intersects" ) << QStringLiteral( 
"Contains" ) << QStringLiteral( 
"Crosses" ) << QStringLiteral( 
"Equals" )
 
 2713              << QStringLiteral( 
"Disjoint" ) << QStringLiteral( 
"Overlaps" ) << QStringLiteral( 
"Touches" ) << QStringLiteral( 
"Within" );
 
 2714   const auto constSpatialOps = spatialOps;
 
 2715   for ( QString op : constSpatialOps )
 
 2717     if ( nameCompare.compare( op, Qt::CaseInsensitive ) == 0 )
 
 2723 static QString mapTernarySpatialToOgc( 
const QString &name )
 
 2725   QString nameCompare( name );
 
 2726 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 2) 
 2727   if ( name.size() > 3 && name.midRef( 0, 3 ).compare( QLatin1String( 
"ST_" ), Qt::CaseInsensitive ) == 0 )
 
 2728     nameCompare = name.mid( 3 );
 
 2730   if ( name.size() > 3 && QStringView {name}.mid( 0, 3 ).compare( QLatin1String( 
"ST_" ), Qt::CaseInsensitive ) == 0 )
 
 2731     nameCompare = name.mid( 3 );
 
 2733   if ( nameCompare.compare( QLatin1String( 
"DWithin" ), Qt::CaseInsensitive ) == 0 )
 
 2734     return QStringLiteral( 
"DWithin" );
 
 2735   if ( nameCompare.compare( QLatin1String( 
"Beyond" ), Qt::CaseInsensitive ) == 0 )
 
 2736     return QStringLiteral( 
"Beyond" );
 
 2740 QString QgsOgcUtilsSQLStatementToFilter::getGeometryColumnSRSName( 
const QgsSQLStatement::Node *node )
 
 2748     const auto constMLayerProperties = mLayerProperties;
 
 2751       if ( prop.mName.compare( mMapTableAliasToNames[col->
tableName()], Qt::CaseInsensitive ) == 0 &&
 
 2752            prop.mGeometryAttribute.compare( col->
name(), Qt::CaseInsensitive ) == 0 )
 
 2754         return prop.mSRSName;
 
 2758   if ( !mLayerProperties.empty() &&
 
 2759        mLayerProperties.at( 0 ).mGeometryAttribute.compare( col->
name(), Qt::CaseInsensitive ) == 0 )
 
 2761     return  mLayerProperties.at( 0 ).mSRSName;
 
 2767     QList<QgsSQLStatement::Node *> args,
 
 2768     bool lastArgIsSRSName,
 
 2770     bool &axisInversion )
 
 2773   axisInversion = mInvertAxisOrientation;
 
 2775   if ( lastArgIsSRSName )
 
 2780       mErrorMessage = QObject::tr( 
"%1: Last argument must be string or integer literal" ).arg( mainNode->
name() );
 
 2784     if ( lit->
value().type() == QVariant::Int )
 
 2788         srsName = 
"EPSG:" + QString::number( lit->
value().toInt() );
 
 2792         srsName = 
"urn:ogc:def:crs:EPSG::" + QString::number( lit->
value().toInt() );
 
 2798       if ( 
srsName.startsWith( QLatin1String( 
"EPSG:" ), Qt::CaseInsensitive ) )
 
 2810       axisInversion = !axisInversion;
 
 2820   if ( node->
name().compare( QLatin1String( 
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 )
 
 2822     QList<QgsSQLStatement::Node *> args = node->
args()->
list();
 
 2823     if ( args.size() != 1 && args.size() != 2 )
 
 2825       mErrorMessage = QObject::tr( 
"Function %1 should have 1 or 2 arguments" ).arg( node->
name() );
 
 2826       return QDomElement();
 
 2832       mErrorMessage = QObject::tr( 
"%1: First argument must be string literal" ).arg( node->
name() );
 
 2833       return QDomElement();
 
 2838     if ( ! processSRSName( node, args, args.size() == 2, 
srsName, axisInversion ) )
 
 2840       return QDomElement();
 
 2846                                  QStringLiteral( 
"qgis_id_geom_%1" ).arg( mGeomId ) );
 
 2848     if ( geomElem.isNull() )
 
 2850       mErrorMessage = QObject::tr( 
"%1: invalid WKT" ).arg( node->
name() );
 
 2851       return QDomElement();
 
 2858   if ( node->
name().compare( QLatin1String( 
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 )
 
 2860     QList<QgsSQLStatement::Node *> args = node->
args()->
list();
 
 2861     if ( args.size() != 4 && args.size() != 5 )
 
 2863       mErrorMessage = QObject::tr( 
"Function %1 should have 4 or 5 arguments" ).arg( node->
name() );
 
 2864       return QDomElement();
 
 2869     for ( 
int i = 0; i < 4; i++ )
 
 2874         mErrorMessage = QObject::tr( 
"%1: Argument %2 must be numeric literal" ).arg( node->
name() ).arg( i + 1 );
 
 2875         return QDomElement();
 
 2879       if ( lit->
value().type() == QVariant::Int )
 
 2880         val = lit->
value().toInt();
 
 2881       else if ( lit->
value().type() == QVariant::LongLong )
 
 2882         val = lit->
value().toLongLong();
 
 2883       else if ( lit->
value().type() == QVariant::Double )
 
 2884         val = lit->
value().toDouble();
 
 2887         mErrorMessage = QObject::tr( 
"%1 Argument %2 must be numeric literal" ).arg( node->
name() ).arg( i + 1 );
 
 2888         return QDomElement();
 
 2902     if ( ! processSRSName( node, args, args.size() == 5, 
srsName, axisInversion ) )
 
 2904       return QDomElement();
 
 2915   if ( node->
name().compare( QLatin1String( 
"ST_GeomFromGML" ), Qt::CaseInsensitive ) == 0 )
 
 2917     QList<QgsSQLStatement::Node *> args = node->
args()->
list();
 
 2918     if ( args.size() != 1 )
 
 2920       mErrorMessage = QObject::tr( 
"Function %1 should have 1 argument" ).arg( node->
name() );
 
 2921       return QDomElement();
 
 2927       mErrorMessage = QObject::tr( 
"%1: Argument must be string literal" ).arg( node->
name() );
 
 2928       return QDomElement();
 
 2931     QDomDocument geomDoc;
 
 2933     if ( !geomDoc.setContent( gml, 
true ) )
 
 2935       mErrorMessage = QObject::tr( 
"ST_GeomFromGML: unable to parse XML" );
 
 2936       return QDomElement();
 
 2939     const QDomNode geomNode = mDoc.importNode( geomDoc.documentElement(), 
true );
 
 2941     return geomNode.toElement();
 
 2945   QString ogcName( mapBinarySpatialToOgc( node->
name() ) );
 
 2946   if ( !ogcName.isEmpty() )
 
 2948     QList<QgsSQLStatement::Node *> args = node->
args()->
list();
 
 2949     if ( args.size() != 2 )
 
 2951       mErrorMessage = QObject::tr( 
"Function %1 should have 2 arguments" ).arg( node->
name() );
 
 2952       return QDomElement();
 
 2955     for ( 
int i = 0; i < 2; i ++ )
 
 2958            ( 
static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String( 
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 ||
 
 2959              static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String( 
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 ) )
 
 2961         mCurrentSRSName = getGeometryColumnSRSName( args[1 - i] );
 
 2968     QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":" + ogcName );
 
 2969     const auto constArgs = args;
 
 2973       if ( !mErrorMessage.isEmpty() )
 
 2975         mCurrentSRSName.clear();
 
 2976         return QDomElement();
 
 2979       funcElem.appendChild( childElem );
 
 2982     mCurrentSRSName.clear();
 
 2986   ogcName = mapTernarySpatialToOgc( node->
name() );
 
 2987   if ( !ogcName.isEmpty() )
 
 2989     QList<QgsSQLStatement::Node *> args = node->
args()->
list();
 
 2990     if ( args.size() != 3 )
 
 2992       mErrorMessage = QObject::tr( 
"Function %1 should have 3 arguments" ).arg( node->
name() );
 
 2993       return QDomElement();
 
 2996     for ( 
int i = 0; i < 2; i ++ )
 
 2999            ( 
static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String( 
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 ||
 
 3000              static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String( 
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 ) )
 
 3002         mCurrentSRSName = getGeometryColumnSRSName( args[1 - i] );
 
 3007     QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":" + node->
name().mid( 3 ) );
 
 3008     for ( 
int i = 0; i < 2; i++ )
 
 3010       const QDomElement childElem = 
toOgcFilter( args[i] );
 
 3011       if ( !mErrorMessage.isEmpty() )
 
 3013         mCurrentSRSName.clear();
 
 3014         return QDomElement();
 
 3017       funcElem.appendChild( childElem );
 
 3019     mCurrentSRSName.clear();
 
 3024       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() );
 
 3025       return QDomElement();
 
 3028     if ( lit->
value().isNull() )
 
 3030       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() );
 
 3031       return QDomElement();
 
 3034     QString unit( QStringLiteral( 
"m" ) );
 
 3035     switch ( lit->
value().type() )
 
 3038         distance = QString::number( lit->
value().toInt() );
 
 3040       case QVariant::LongLong:
 
 3041         distance = QString::number( lit->
value().toLongLong() );
 
 3043       case QVariant::Double:
 
 3046       case QVariant::String:
 
 3048         distance = lit->
value().toString();
 
 3049         for ( 
int i = 0; i < distance.size(); i++ )
 
 3051           if ( !( ( distance[i] >= 
'0' && distance[i] <= 
'9' ) || distance[i] == 
'-' || distance[i] == 
'.' || distance[i] == 
'e' || distance[i] == 
'E' ) )
 
 3053             unit = distance.mid( i ).trimmed();
 
 3054             distance = distance.mid( 0, i );
 
 3062         mErrorMessage = QObject::tr( 
"Literal type not supported: %1" ).arg( lit->
value().type() );
 
 3063         return QDomElement();
 
 3066     QDomElement distanceElem = mDoc.createElement( mFilterPrefix + 
":Distance" );
 
 3068       distanceElem.setAttribute( QStringLiteral( 
"uom" ), unit );
 
 3070       distanceElem.setAttribute( QStringLiteral( 
"unit" ), unit );
 
 3071     distanceElem.appendChild( mDoc.createTextNode( distance ) );
 
 3072     funcElem.appendChild( distanceElem );
 
 3077   QDomElement funcElem = mDoc.createElement( mFilterPrefix + 
":Function" );
 
 3078   funcElem.setAttribute( QStringLiteral( 
"name" ), node->
name() );
 
 3079   const auto constList = node->
args()->
list();
 
 3083     if ( !mErrorMessage.isEmpty() )
 
 3084       return QDomElement();
 
 3086     funcElem.appendChild( childElem );
 
 3092     const QString &leftTable )
 
 3100   QList<QDomElement> listElem;
 
 3102   for ( 
const QString &columnName : constUsingColumns )
 
 3104     QDomElement eqElem = mDoc.createElement( mFilterPrefix + 
":PropertyIsEqualTo" );
 
 3105     QDomElement propElem1 = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 3106     propElem1.appendChild( mDoc.createTextNode( leftTable + 
"/" + columnName ) );
 
 3107     eqElem.appendChild( propElem1 );
 
 3108     QDomElement propElem2 = mDoc.createElement( mFilterPrefix + 
":" + mPropertyName );
 
 3109     propElem2.appendChild( mDoc.createTextNode( node->
tableDef()->
name() + 
"/" + columnName ) );
 
 3110     eqElem.appendChild( propElem2 );
 
 3111     listElem.append( eqElem );
 
 3114   if ( listElem.size() == 1 )
 
 3118   else if ( listElem.size() > 1 )
 
 3120     QDomElement andElem = mDoc.createElement( mFilterPrefix + 
":And" );
 
 3121     const auto constListElem = listElem;
 
 3122     for ( 
const QDomElement &elem : constListElem )
 
 3124       andElem.appendChild( elem );
 
 3129   return QDomElement();
 
 3134   if ( node->
alias().isEmpty() )
 
 3136     mMapTableAliasToNames[ node->
name()] = node->
name();
 
 3140     mMapTableAliasToNames[ node->
alias()] = node->
name();
 
 3146   QList<QDomElement> listElem;
 
 3149        ( node->
tables().size() != 1 || !node->
joins().empty() ) )
 
 3151     mErrorMessage = QObject::tr( 
"Joins are only supported with WFS 2.0" );
 
 3152     return QDomElement();
 
 3156   const auto constTables = node->
tables();
 
 3161   const auto constJoins = node->
joins();
 
 3164     visit( join->tableDef() );
 
 3168   const QList< QgsSQLStatement::NodeTableDef *> nodeTables = node->
tables();
 
 3169   QString leftTable = nodeTables.at( nodeTables.length() - 1 )->name();
 
 3172     const QDomElement joinElem = 
toOgcFilter( join, leftTable );
 
 3173     if ( !mErrorMessage.isEmpty() )
 
 3174       return QDomElement();
 
 3175     listElem.append( joinElem );
 
 3176     leftTable = join->tableDef()->name();
 
 3180   if ( node->
where() )
 
 3183     if ( !mErrorMessage.isEmpty() )
 
 3184       return QDomElement();
 
 3185     listElem.append( whereElem );
 
 3189   if ( listElem.size() == 1 )
 
 3193   else if ( listElem.size() > 1 )
 
 3195     QDomElement andElem = mDoc.createElement( mFilterPrefix + 
":And" );
 
 3196     const auto constListElem = listElem;
 
 3197     for ( 
const QDomElement &elem : constListElem )
 
 3199       andElem.appendChild( elem );
 
 3204   return QDomElement();
 
 3210   mPropertyName = QStringLiteral( 
"PropertyName" );
 
 3211   mPrefix = QStringLiteral( 
"ogc" );
 
 3215     mPropertyName = QStringLiteral( 
"ValueReference" );
 
 3216     mPrefix = QStringLiteral( 
"fes" );
 
 3222   if ( element.isNull() )
 
 3226   if ( isBinaryOperator( element.tagName() ) )
 
 3232   if ( isSpatialOperator( element.tagName() ) )
 
 3238   if ( element.tagName() == QLatin1String( 
"Not" ) )
 
 3242   else if ( element.tagName() == QLatin1String( 
"PropertyIsNull" ) )
 
 3246   else if ( element.tagName() == QLatin1String( 
"Literal" ) )
 
 3250   else if ( element.tagName() == QLatin1String( 
"Function" ) )
 
 3254   else if ( element.tagName() == mPropertyName )
 
 3258   else if ( element.tagName() == QLatin1String( 
"PropertyIsBetween" ) )
 
 3263   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() );
 
 3269   if ( element.isNull() )
 
 3272   int op = binaryOperatorFromTagName( element.tagName() );
 
 3275     mErrorMessage = QObject::tr( 
"'%1' binary operator not supported." ).arg( element.tagName() );
 
 3279   if ( op == 
QgsExpressionNodeBinaryOperator::boLike && element.hasAttribute( QStringLiteral( 
"matchCase" ) ) && element.attribute( QStringLiteral( 
"matchCase" ) ) == QLatin1String( 
"false" ) )
 
 3284   QDomElement operandElem = element.firstChildElement();
 
 3289     mErrorMessage = QObject::tr( 
"invalid left operand for '%1' binary operator" ).arg( element.tagName() );
 
 3293   const std::unique_ptr<QgsExpressionNode> leftOp( expr->clone() );
 
 3294   for ( operandElem = operandElem.nextSiblingElement(); !operandElem.isNull(); operandElem = operandElem.nextSiblingElement() )
 
 3299       mErrorMessage = QObject::tr( 
"invalid right operand for '%1' binary operator" ).arg( element.tagName() );
 
 3306       if ( element.hasAttribute( QStringLiteral( 
"wildCard" ) ) )
 
 3308         wildCard = element.attribute( QStringLiteral( 
"wildCard" ) );
 
 3311       if ( element.hasAttribute( QStringLiteral( 
"singleChar" ) ) )
 
 3313         singleChar = element.attribute( QStringLiteral( 
"singleChar" ) );
 
 3315       QString escape = QStringLiteral( 
"\\" );
 
 3316       if ( element.hasAttribute( QStringLiteral( 
"escape" ) ) )
 
 3318         escape = element.attribute( QStringLiteral( 
"escape" ) );
 
 3320       if ( element.hasAttribute( QStringLiteral( 
"escapeChar" ) ) )
 
 3322         escape = element.attribute( QStringLiteral( 
"escapeChar" ) );
 
 3326       if ( !wildCard.isEmpty() && wildCard != QLatin1String( 
"%" ) )
 
 3328         oprValue.replace( 
'%', QLatin1String( 
"\\%" ) );
 
 3329         if ( oprValue.startsWith( wildCard ) )
 
 3331           oprValue.replace( 0, 1, QStringLiteral( 
"%" ) );
 
 3334         QRegularExpressionMatch match = rx.match( oprValue );
 
 3336         while ( match.hasMatch() )
 
 3338           pos = match.capturedStart();
 
 3339           oprValue.replace( pos + 1, 1, QStringLiteral( 
"%" ) );
 
 3341           match = rx.match( oprValue, pos );
 
 3343         oprValue.replace( escape + wildCard, wildCard );
 
 3345       if ( !singleChar.isEmpty() && singleChar != QLatin1String( 
"_" ) )
 
 3347         oprValue.replace( 
'_', QLatin1String( 
"\\_" ) );
 
 3348         if ( oprValue.startsWith( singleChar ) )
 
 3350           oprValue.replace( 0, 1, QStringLiteral( 
"_" ) );
 
 3353         QRegularExpressionMatch match = rx.match( oprValue );
 
 3355         while ( match.hasMatch() )
 
 3357           pos = match.capturedStart();
 
 3358           oprValue.replace( pos + 1, 1, QStringLiteral( 
"_" ) );
 
 3360           match = rx.match( oprValue, pos );
 
 3362         oprValue.replace( escape + singleChar, singleChar );
 
 3364       if ( !escape.isEmpty() && escape != QLatin1String( 
"\\" ) )
 
 3366         oprValue.replace( escape + escape, escape );
 
 3374   if ( expr == leftOp )
 
 3376     mErrorMessage = QObject::tr( 
"only one operand for '%1' binary operator" ).arg( element.tagName() );
 
 3390   QDomElement childElem = element.firstChildElement();
 
 3392   while ( !childElem.isNull() && gml2Str.isEmpty() )
 
 3394     if ( childElem.tagName() != mPropertyName )
 
 3396       QTextStream gml2Stream( &gml2Str );
 
 3397       childElem.save( gml2Stream, 0 );
 
 3399     childElem = childElem.nextSiblingElement();
 
 3401   if ( !gml2Str.isEmpty() )
 
 3407     mErrorMessage = QObject::tr( 
"No OGC Geometry found" );
 
 3420   if ( element.isNull() || element.tagName() != mPropertyName )
 
 3422     mErrorMessage = QObject::tr( 
"%1:PropertyName expected, got %2" ).arg( mPrefix, element.tagName() );
 
 3431   if ( element.isNull() || element.tagName() != QLatin1String( 
"Literal" ) )
 
 3433     mErrorMessage = QObject::tr( 
"%1:Literal expected, got %2" ).arg( mPrefix, element.tagName() );
 
 3437   std::unique_ptr<QgsExpressionNode> root;
 
 3440   QDomNode childNode = element.firstChild();
 
 3441   while ( !childNode.isNull() )
 
 3443     std::unique_ptr<QgsExpressionNode> operand;
 
 3445     if ( childNode.nodeType() == QDomNode::ElementNode )
 
 3448       const QDomElement operandElem = childNode.toElement();
 
 3452         mErrorMessage = QObject::tr( 
"'%1' is an invalid or not supported content for %2:Literal" ).arg( operandElem.tagName(), mPrefix );
 
 3459       QVariant value = childNode.nodeValue();
 
 3461       bool converted = 
false;
 
 3466         QDomElement propertyNameElement = element.previousSiblingElement( mPropertyName );
 
 3467         if ( propertyNameElement.isNull() || propertyNameElement.tagName() != mPropertyName )
 
 3469           propertyNameElement = element.nextSiblingElement( mPropertyName );
 
 3471         if ( !propertyNameElement.isNull() || propertyNameElement.tagName() == mPropertyName )
 
 3473           const int fieldIndex = mLayer->
fields().
indexOf( propertyNameElement.firstChild().nodeValue() );
 
 3474           if ( fieldIndex != -1 )
 
 3487         const double d = value.toDouble( &ok );
 
 3500       root = std::move( operand );
 
 3507     childNode = childNode.nextSibling();
 
 3511     return root.release();
 
 3518   if ( element.tagName() != QLatin1String( 
"Not" ) )
 
 3521   const QDomElement operandElem = element.firstChildElement();
 
 3525     mErrorMessage = QObject::tr( 
"invalid operand for '%1' unary operator" ).arg( element.tagName() );
 
 3535   if ( element.tagName() != QLatin1String( 
"PropertyIsNull" ) )
 
 3540   const QDomElement operandElem = element.firstChildElement();
 
 3551   if ( element.isNull() || element.tagName() != QLatin1String( 
"Function" ) )
 
 3553     mErrorMessage = QObject::tr( 
"%1:Function expected, got %2" ).arg( mPrefix, element.tagName() );
 
 3561     if ( element.attribute( QStringLiteral( 
"name" ) ) != funcDef->
name() )
 
 3566     QDomElement operandElem = element.firstChildElement();
 
 3567     while ( !operandElem.isNull() )
 
 3574       args->append( op.release() );
 
 3576       operandElem = operandElem.nextSiblingElement();
 
 3588   std::unique_ptr<QgsExpressionNode> operand;
 
 3589   std::unique_ptr<QgsExpressionNode> lowerBound;
 
 3590   std::unique_ptr<QgsExpressionNode> upperBound;
 
 3592   QDomElement operandElem = element.firstChildElement();
 
 3593   while ( !operandElem.isNull() )
 
 3595     if ( operandElem.tagName() == QLatin1String( 
"LowerBoundary" ) )
 
 3597       const QDomElement lowerBoundElem = operandElem.firstChildElement();
 
 3600     else if ( operandElem.tagName() == QLatin1String( 
"UpperBoundary" ) )
 
 3602       const QDomElement upperBoundElem = operandElem.firstChildElement();
 
 3611     if ( operand && lowerBound && upperBound )
 
 3614     operandElem = operandElem.nextSiblingElement();
 
 3617   if ( !operand || !lowerBound || !upperBound )
 
 3619     mErrorMessage = QObject::tr( 
"missing some required sub-elements in %1:PropertyIsBetween" ).arg( mPrefix );
 
 3630   return mErrorMessage;
 
GeometryOperationResult
Success or failure of a geometry operation.
@ Success
Operation succeeded.
virtual void swapXy()=0
Swaps the x and y coordinates from the geometry.
QgsWkbTypes::Type readHeader() const
readHeader
This class represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool createFromUserInput(const QString &definition)
Set up this CRS from various text formats.
bool hasAxisInverted() const
Returns whether axis is inverted (e.g., for WMS 1.3) for the CRS.
Custom exception class for Coordinate Reference System related exceptions.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
A abstract base class for defining QgsExpression functions.
int params() const
The number of parameters this function takes.
virtual bool isStatic(const QgsExpressionNodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context) const
Will be called during prepare to determine if the function is static.
QString name() const
The name of the function.
virtual QVariant run(QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction *node)
Evaluates the function, first evaluating all required arguments before passing them to the function's...
A binary expression operator, which operates on two values.
QgsExpressionNodeBinaryOperator::BinaryOperator op() const
Returns the binary operator.
QgsExpressionNode * opRight() const
Returns the node to the right of the operator.
QString text() const
Returns a the name of this operator without the operands.
QgsExpressionNode * opLeft() const
Returns the node to the left of the operator.
BinaryOperator
list of binary operators
An expression node which takes it value from a feature's field.
QString name() const
The name of the column.
An expression node for expression functions.
int fnIndex() const
Returns the index of the node's function.
QgsExpressionNode::NodeList * args() const
Returns a list of arguments specified for the function.
An expression node for value IN or NOT IN clauses.
QgsExpressionNode * node() const
Returns the expression node.
QgsExpressionNode::NodeList * list() const
Returns the list of nodes to search for matching values within.
bool isNotIn() const
Returns true if this node is a "NOT IN" operator, or false if the node is a normal "IN" operator.
An expression node for literal values.
QVariant value() const
The value of the literal.
A unary node is either negative as in boolean (not) or as in numbers (minus).
QgsExpressionNodeUnaryOperator::UnaryOperator op() const
Returns the unary operator.
QString text() const
Returns a the name of this operator without the operands.
QgsExpressionNode * operand() const
Returns the node the operator will operate upon.
A list of expression nodes.
QList< QgsExpressionNode * > list()
Gets a list of all the nodes.
Abstract base class for all nodes that can appear in an expression.
virtual QgsExpressionNode::NodeType nodeType() const =0
Gets the type of this node.
Class for parsing and evaluation of expressions (formerly called "search strings").
static const QList< QgsExpressionFunction * > & Functions()
void setExpression(const QString &expression)
Set the expression string, will reset the whole internal structure.
static int functionIndex(const QString &name)
Returns index of the function in Functions array.
QString dump() const
Returns an expression string, constructed from the internal abstract syntax tree.
const QgsExpressionNode * rootNode() const
Returns the root node of the expression.
Encapsulate a field in an attribute table or data source.
bool convertCompatible(QVariant &v, QString *errorMessage=nullptr) const
Converts the provided variant to a compatible format.
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
A geometry is the spatial representation of a feature.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const
Export the geometry to WKB.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
QgsCoordinateReferenceSystem crs
Internal use by QgsOgcUtils.
bool GMLNamespaceUsed() const
Returns whether the gml: namespace is used.
QgsOgcUtilsExprToFilter(QDomDocument &doc, QgsOgcUtils::GMLVersion gmlVersion, QgsOgcUtils::FilterVersion filterVersion, const QString &geometryName, const QString &srsName, bool honourAxisOrientation, bool invertAxisOrientation)
Constructor.
QDomElement expressionNodeToOgcFilter(const QgsExpressionNode *node, QgsExpression *expression, const QgsExpressionContext *context)
Convert an expression to a OGC filter.
QString errorMessage() const
Returns the error message.
Internal use by QgsOgcUtils.
QgsExpressionNodeFunction * nodeSpatialOperatorFromOgcFilter(const QDomElement &element)
Returns an expression node from a WFS filter embedded in a document with spatial operators.
QgsExpressionNodeUnaryOperator * nodeNotFromOgcFilter(const QDomElement &element)
Returns an expression node from a WFS filter embedded in a document with Not operator.
QgsExpressionNodeColumnRef * nodeColumnRefFromOgcFilter(const QDomElement &element)
Returns an expression node from a WFS filter embedded in a document with column references.
QgsExpressionNode * nodeIsBetweenFromOgcFilter(const QDomElement &element)
Returns an expression node from a WFS filter embedded in a document with boudnaries operator.
QgsOgcUtilsExpressionFromFilter(QgsOgcUtils::FilterVersion version=QgsOgcUtils::FILTER_OGC_1_0, const QgsVectorLayer *layer=nullptr)
Constructor for QgsOgcUtilsExpressionFromFilter.
QgsExpressionNodeBinaryOperator * nodeBinaryOperatorFromOgcFilter(const QDomElement &element)
Returns an expression node from a WFS filter embedded in a document with binary operators.
QgsExpressionNodeFunction * nodeFunctionFromOgcFilter(const QDomElement &element)
Returns an expression node from a WFS filter embedded in a document with functions.
QgsExpressionNode * nodeFromOgcFilter(const QDomElement &element)
Returns an expression node from a WFS filter embedded in a document element.
QgsExpressionNodeBinaryOperator * nodePropertyIsNullFromOgcFilter(const QDomElement &element)
Returns an expression node from a WFS filter embedded in a document with IsNull operator.
QString errorMessage() const
Returns the underlying error message, or an empty string in case of no error.
QgsExpressionNode * nodeLiteralFromOgcFilter(const QDomElement &element)
Returns an expression node from a WFS filter embedded in a document with literal tag.
Internal use by QgsOgcUtils.
QgsOgcUtilsSQLStatementToFilter(QDomDocument &doc, QgsOgcUtils::GMLVersion gmlVersion, QgsOgcUtils::FilterVersion filterVersion, const QList< QgsOgcUtils::LayerProperties > &layerProperties, bool honourAxisOrientation, bool invertAxisOrientation, const QMap< QString, QString > &mapUnprefixedTypenameToPrefixedTypename)
Constructor.
QDomElement toOgcFilter(const QgsSQLStatement::Node *node)
Convert a SQL statement to a OGC filter.
bool GMLNamespaceUsed() const
Returns whether the gml: namespace is used.
QString errorMessage() const
Returns the error message.
The QgsOgcUtils class provides various utility functions for conversion between OGC (Open Geospatial ...
static QgsRectangle rectangleFromGMLBox(const QDomNode &boxNode)
Read rectangle from GML2 Box.
static QColor colorFromOgcFill(const QDomElement &fillElement)
Parse XML with OGC fill into QColor.
static QDomElement expressionToOgcFilter(const QgsExpression &exp, QDomDocument &doc, QString *errorMessage=nullptr)
Creates OGC filter XML element.
FilterVersion
OGC filter version.
static QDomElement SQLStatementToOgcFilter(const QgsSQLStatement &statement, QDomDocument &doc, QgsOgcUtils::GMLVersion gmlVersion, FilterVersion filterVersion, const QList< LayerProperties > &layerProperties, bool honourAxisOrientation, bool invertAxisOrientation, const QMap< QString, QString > &mapUnprefixedTypenameToPrefixedTypename, QString *errorMessage=nullptr)
Creates OGC filter XML element from the WHERE and JOIN clauses of a SQL statement.
static QDomElement expressionToOgcExpression(const QgsExpression &exp, QDomDocument &doc, QString *errorMessage=nullptr)
Creates an OGC expression XML element.
static QgsRectangle rectangleFromGMLEnvelope(const QDomNode &envelopeNode)
Read rectangle from GML3 Envelope.
static QDomElement geometryToGML(const QgsGeometry &geometry, QDomDocument &doc, QgsOgcUtils::GMLVersion gmlVersion, const QString &srsName, bool invertAxisOrientation, const QString &gmlIdBase, int precision=17)
Exports the geometry to GML.
static QgsGeometry geometryFromGML(const QString &xmlString, const QgsOgcUtils::Context &context=QgsOgcUtils::Context())
Static method that creates geometry from GML.
static QDomElement rectangleToGMLEnvelope(QgsRectangle *env, QDomDocument &doc, int precision=17)
Exports the rectangle to GML3 Envelope.
static QgsExpression * expressionFromOgcFilter(const QDomElement &element, QgsVectorLayer *layer=nullptr)
Parse XML with OGC filter into QGIS expression.
static QDomElement rectangleToGMLBox(QgsRectangle *box, QDomDocument &doc, int precision=17)
Exports the rectangle to GML2 Box.
A class to represent a 2D point.
A rectangle specified with double values.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
void normalize()
Normalize the rectangle so it has non-negative width/height.
'X BETWEEN y and z' operator
QgsSQLStatement::Node * maxVal() const
Maximum bound.
bool isNotBetween() const
Whether this is a NOT BETWEEN operator.
QgsSQLStatement::Node * node() const
Variable at the left of BETWEEN.
QgsSQLStatement::Node * minVal() const
Minimum bound.
Binary logical/arithmetical operator (AND, OR, =, +, ...)
QgsSQLStatement::Node * opRight() const
Right operand.
QgsSQLStatement::Node * opLeft() const
Left operand.
QgsSQLStatement::BinaryOperator op() const
Operator.
QString name() const
The name of the column.
QString tableName() const
The name of the table. May be empty.
Function with a name and arguments node.
QgsSQLStatement::NodeList * args() const
Returns arguments.
QString name() const
Returns function name.
bool isNotIn() const
Whether this is a NOT IN operator.
QgsSQLStatement::NodeList * list() const
Values list.
QgsSQLStatement::Node * node() const
Variable at the left of IN.
QgsSQLStatement::NodeTableDef * tableDef() const
Table definition.
QList< QString > usingColumns() const
Columns referenced by USING.
QgsSQLStatement::Node * onExpr() const
On expression. Will be nullptr if usingColumns() is not empty.
QList< QgsSQLStatement::Node * > list()
Returns list.
Literal value (integer, integer64, double, string)
QVariant value() const
The value of the literal.
QgsSQLStatement::Node * where() const
Returns the where clause.
QList< QgsSQLStatement::NodeJoin * > joins() const
Returns the list of joins.
QList< QgsSQLStatement::NodeTableDef * > tables() const
Returns the list of tables.
QString name() const
Table name.
QString alias() const
Table alias.
Unary logicial/arithmetical operator ( NOT, - )
QgsSQLStatement::Node * operand() const
Operand.
QgsSQLStatement::UnaryOperator op() const
Operator.
virtual QgsSQLStatement::NodeType nodeType() const =0
Abstract virtual that returns the type of this node.
Class for parsing SQL statements.
BinaryOperator
list of binary operators
static const char * BINARY_OPERATOR_TEXT[]
const QgsSQLStatement::Node * rootNode() const
Returns the root node of the statement.
static const char * UNARY_OPERATOR_TEXT[]
static QString qRegExpEscape(const QString &string)
Returns an escaped string matching the behavior of QRegExp::escape.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Custom exception class for Wkb related exceptions.
Type
The WKB type describes the number of dimensions a geometry has.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsEnumValueToKey(const T &value)
Returns the value for the given key of an enum.
QMap< QString, QString > QgsStringMap
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item.
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
#define QgsDebugMsgLevel(str, level)
Q_GLOBAL_STATIC_WITH_ARGS(IntMap, BINARY_OPERATORS_TAG_NAMES_MAP,({ { QLatin1String("Or"), QgsExpressionNodeBinaryOperator::boOr }, { QLatin1String("And"), QgsExpressionNodeBinaryOperator::boAnd }, { QLatin1String("PropertyIsEqualTo"), QgsExpressionNodeBinaryOperator::boEQ }, { QLatin1String("PropertyIsNotEqualTo"), QgsExpressionNodeBinaryOperator::boNE }, { QLatin1String("PropertyIsLessThanOrEqualTo"), QgsExpressionNodeBinaryOperator::boLE }, { QLatin1String("PropertyIsGreaterThanOrEqualTo"), QgsExpressionNodeBinaryOperator::boGE }, { QLatin1String("PropertyIsLessThan"), QgsExpressionNodeBinaryOperator::boLT }, { QLatin1String("PropertyIsGreaterThan"), QgsExpressionNodeBinaryOperator::boGT }, { QLatin1String("PropertyIsLike"), QgsExpressionNodeBinaryOperator::boLike }, { QLatin1String("Add"), QgsExpressionNodeBinaryOperator::boPlus }, { QLatin1String("Sub"), QgsExpressionNodeBinaryOperator::boMinus }, { QLatin1String("Mul"), QgsExpressionNodeBinaryOperator::boMul }, { QLatin1String("Div"), QgsExpressionNodeBinaryOperator::boDiv }, })) static int binaryOperatorFromTagName(const QString &tagName)
QMap< QString, int > IntMap
const QString & geometryName
const QgsCoordinateReferenceSystem & crs
The Context struct stores the current layer and coordinate transform context.
const QgsMapLayer * layer
QgsCoordinateTransformContext transformContext