38#include <QRegularExpression>
43#include <netinet/in.h>
49#define GML_NAMESPACE QStringLiteral( "http://www.opengis.net/gml" )
50#define GML32_NAMESPACE QStringLiteral( "http://www.opengis.net/gml/3.2" )
51#define OGC_NAMESPACE QStringLiteral( "http://www.opengis.net/ogc" )
52#define FES_NAMESPACE QStringLiteral( "http://www.opengis.net/fes/2.0" )
53#define SE_NAMESPACE QStringLiteral( "http://www.opengis.net/se" )
58 const QString &namespacePrefix,
59 const QString &namespaceURI,
60 const QString &geometryName,
61 const QString &srsName,
62 bool honourAxisOrientation,
63 bool invertAxisOrientation,
64 const QMap<QString, QString> &fieldNameToXPathMap,
65 const QMap<QString, QString> &namespacePrefixToUriMap )
68 , mGMLVersion( gmlVersion )
69 , mFilterVersion( filterVersion )
70 , mNamespacePrefix( namespacePrefix )
71 , mNamespaceURI( namespaceURI )
72 , mGeometryName( geometryName )
74 , mInvertAxisOrientation( invertAxisOrientation )
75 , mFieldNameToXPathMap( fieldNameToXPathMap )
76 , mNamespacePrefixToUriMap( namespacePrefixToUriMap )
77 , mFilterPrefix( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"fes" :
"ogc" )
78 , mPropertyName( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"ValueReference" :
"PropertyName" )
82 if ( !mSrsName.isEmpty() )
86 if ( honourAxisOrientation && crs.hasAxisInverted() )
88 mInvertAxisOrientation = !mInvertAxisOrientation;
95 QDomElement geometryTypeElement = geometryNode.toElement();
96 QString geomType = geometryTypeElement.tagName();
99 if ( !( geomType == QLatin1String(
"Point" ) || geomType == QLatin1String(
"LineString" ) || geomType == QLatin1String(
"Polygon" ) ||
100 geomType == QLatin1String(
"MultiPoint" ) || geomType == QLatin1String(
"MultiLineString" ) || geomType == QLatin1String(
"MultiPolygon" ) ||
101 geomType == QLatin1String(
"Box" ) || geomType == QLatin1String(
"Envelope" ) || geomType == QLatin1String(
"MultiCurve" ) ) )
103 const QDomNode geometryChild = geometryNode.firstChild();
104 if ( geometryChild.isNull() )
108 geometryTypeElement = geometryChild.toElement();
109 geomType = geometryTypeElement.tagName();
112 if ( !( geomType == QLatin1String(
"Point" ) || geomType == QLatin1String(
"LineString" ) || geomType == QLatin1String(
"Polygon" ) ||
113 geomType == QLatin1String(
"MultiPoint" ) || geomType == QLatin1String(
"MultiLineString" ) || geomType == QLatin1String(
"MultiPolygon" ) ||
114 geomType == QLatin1String(
"Box" ) || geomType == QLatin1String(
"Envelope" ) || geomType == QLatin1String(
"MultiCurve" ) ) )
117 if ( geomType == QLatin1String(
"Point" ) )
119 geometry = geometryFromGMLPoint( geometryTypeElement );
121 else if ( geomType == QLatin1String(
"LineString" ) )
123 geometry = geometryFromGMLLineString( geometryTypeElement );
125 else if ( geomType == QLatin1String(
"Polygon" ) )
127 geometry = geometryFromGMLPolygon( geometryTypeElement );
129 else if ( geomType == QLatin1String(
"MultiPoint" ) )
131 geometry = geometryFromGMLMultiPoint( geometryTypeElement );
133 else if ( geomType == QLatin1String(
"MultiLineString" ) )
135 geometry = geometryFromGMLMultiLineString( geometryTypeElement );
137 else if ( geomType == QLatin1String(
"MultiCurve" ) )
139 geometry = geometryFromGMLMultiCurve( geometryTypeElement );
141 else if ( geomType == QLatin1String(
"MultiPolygon" ) )
143 geometry = geometryFromGMLMultiPolygon( geometryTypeElement );
145 else if ( geomType == QLatin1String(
"Box" ) )
149 else if ( geomType == QLatin1String(
"Envelope" ) )
155 QgsDebugMsgLevel( QStringLiteral(
"Unknown geometry type %1" ).arg( geomType ), 2 );
162 if ( geometryTypeElement.hasAttribute( QStringLiteral(
"srsName" ) ) )
164 QString srsName { geometryTypeElement.attribute( QStringLiteral(
"srsName" ) ) };
167 const bool ignoreAxisOrientation { srsName.startsWith( QLatin1String(
"http://www.opengis.net/gml/srs/" ) ) || srsName.startsWith( QLatin1String(
"EPSG:" ) ) };
171 if ( srsName.startsWith( QLatin1String(
"http://www.opengis.net/gml/srs/" ) ) )
173 const auto parts { srsName.split( QRegularExpression( QStringLiteral( R
"raw(/|#|\.)raw" ) ) ) };
174 if ( parts.length() == 10 )
176 srsName = QStringLiteral(
"http://www.opengis.net/def/crs/%1/0/%2" ).arg( parts[ 7 ].toUpper(), parts[ 9 ] );
210 const QString xml = QStringLiteral(
"<tmp xmlns=\"%1\" xmlns:gml=\"%1\">%2</tmp>" ).arg(
GML_NAMESPACE, xmlString );
212 if ( !doc.setContent( xml,
true ) )
215 return geometryFromGML( doc.documentElement().firstChildElement(), context );
219QgsGeometry QgsOgcUtils::geometryFromGMLPoint(
const QDomElement &geometryElement )
223 const QDomNodeList coordList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
224 if ( !coordList.isEmpty() )
226 const QDomElement coordElement = coordList.at( 0 ).toElement();
227 if ( readGMLCoordinates( pointCoordinate, coordElement ) != 0 )
234 const QDomNodeList posList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"pos" ) );
235 if ( posList.size() < 1 )
237 return QgsGeometry();
239 const QDomElement posElement = posList.at( 0 ).toElement();
240 if ( readGMLPositions( pointCoordinate, posElement ) != 0 )
242 return QgsGeometry();
246 if ( pointCoordinate.empty() )
248 return QgsGeometry();
251 const bool hasZ { !std::isnan( pointCoordinate.first().z() ) };
252 QgsPolyline::const_iterator point_it = pointCoordinate.constBegin();
253 const char e =
static_cast<char>( htonl( 1 ) != 1 );
254 const double x = point_it->x();
255 const double y = point_it->y();
256 const int size = 1 +
static_cast<int>(
sizeof( int ) ) + ( hasZ ? 3 : 2 ) *
static_cast<int>(
sizeof( double ) );
259 unsigned char *wkb =
new unsigned char[size];
262 memcpy( &( wkb )[wkbPosition], &e, 1 );
264 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
265 wkbPosition +=
sizeof( int );
266 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
267 wkbPosition +=
sizeof( double );
268 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
272 wkbPosition +=
sizeof( double );
273 double z = point_it->z();
274 memcpy( &( wkb )[wkbPosition], &z,
sizeof(
double ) );
282QgsGeometry QgsOgcUtils::geometryFromGMLLineString(
const QDomElement &geometryElement )
286 const QDomNodeList coordList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
287 if ( !coordList.isEmpty() )
289 const QDomElement coordElement = coordList.at( 0 ).toElement();
290 if ( readGMLCoordinates( lineCoordinates, coordElement ) != 0 )
292 return QgsGeometry();
297 const QDomNodeList posList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
298 if ( posList.size() < 1 )
300 return QgsGeometry();
302 const QDomElement posElement = posList.at( 0 ).toElement();
303 if ( readGMLPositions( lineCoordinates, posElement ) != 0 )
305 return QgsGeometry();
309 const bool hasZ { !std::isnan( lineCoordinates.first().z() ) };
311 char e =
static_cast<char>( htonl( 1 ) != 1 );
312 const int size = 1 + 2 *
static_cast<int>(
sizeof( int ) + lineCoordinates.size() ) * ( hasZ ? 3 : 2 ) *
static_cast<int>(
sizeof(
double ) );
315 unsigned char *wkb =
new unsigned char[size];
319 int nPoints = lineCoordinates.size();
322 memcpy( &( wkb )[wkbPosition], &e, 1 );
324 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
325 wkbPosition +=
sizeof( int );
326 memcpy( &( wkb )[wkbPosition], &nPoints,
sizeof(
int ) );
327 wkbPosition +=
sizeof( int );
329 QgsPolyline::const_iterator iter;
330 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
334 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
335 wkbPosition +=
sizeof( double );
336 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
337 wkbPosition +=
sizeof( double );
341 double z = iter->z();
342 memcpy( &( wkb )[wkbPosition], &z,
sizeof(
double ) );
343 wkbPosition +=
sizeof( double );
353QgsGeometry QgsOgcUtils::geometryFromGMLPolygon(
const QDomElement &geometryElement )
360 const QDomNodeList outerBoundaryList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"outerBoundaryIs" ) );
361 if ( !outerBoundaryList.isEmpty() )
363 QDomElement coordinatesElement = outerBoundaryList.at( 0 ).firstChild().firstChild().toElement();
364 if ( coordinatesElement.isNull() )
366 return QgsGeometry();
368 if ( readGMLCoordinates( exteriorPointList, coordinatesElement ) != 0 )
370 return QgsGeometry();
372 ringCoordinates.push_back( exteriorPointList );
375 const QDomNodeList innerBoundaryList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"innerBoundaryIs" ) );
376 for (
int i = 0; i < innerBoundaryList.size(); ++i )
379 coordinatesElement = innerBoundaryList.at( i ).firstChild().firstChild().toElement();
380 if ( coordinatesElement.isNull() )
382 return QgsGeometry();
384 if ( readGMLCoordinates( interiorPointList, coordinatesElement ) != 0 )
386 return QgsGeometry();
388 ringCoordinates.push_back( interiorPointList );
394 const QDomNodeList exteriorList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"exterior" ) );
395 if ( exteriorList.size() < 1 )
397 return QgsGeometry();
399 const QDomElement posElement = exteriorList.at( 0 ).firstChild().firstChild().toElement();
400 if ( posElement.isNull() )
402 return QgsGeometry();
404 if ( readGMLPositions( exteriorPointList, posElement ) != 0 )
406 return QgsGeometry();
408 ringCoordinates.push_back( exteriorPointList );
411 const QDomNodeList interiorList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"interior" ) );
412 for (
int i = 0; i < interiorList.size(); ++i )
415 const QDomElement posElement = interiorList.at( i ).firstChild().firstChild().toElement();
416 if ( posElement.isNull() )
418 return QgsGeometry();
421 if ( readGMLPositions( interiorPointList, posElement ) )
423 return QgsGeometry();
425 ringCoordinates.push_back( interiorPointList );
430 int nrings = ringCoordinates.size();
432 return QgsGeometry();
435 for ( QgsMultiPolyline::const_iterator it = ringCoordinates.constBegin(); it != ringCoordinates.constEnd(); ++it )
437 npoints += it->size();
440 const bool hasZ { !std::isnan( ringCoordinates.first().first().z() ) };
442 const int size = 1 + 2 *
static_cast<int>(
sizeof( int ) ) + nrings *
static_cast<int>(
sizeof(
int ) ) + ( hasZ ? 3 : 2 ) * npoints *
static_cast<int>(
sizeof(
double ) );
445 unsigned char *wkb =
new unsigned char[size];
448 char e =
static_cast<char>( htonl( 1 ) != 1 );
450 int nPointsInRing = 0;
454 memcpy( &( wkb )[wkbPosition], &e, 1 );
456 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
457 wkbPosition +=
sizeof( int );
458 memcpy( &( wkb )[wkbPosition], &nrings,
sizeof(
int ) );
459 wkbPosition +=
sizeof( int );
460 for ( QgsMultiPolyline::const_iterator it = ringCoordinates.constBegin(); it != ringCoordinates.constEnd(); ++it )
462 nPointsInRing = it->size();
463 memcpy( &( wkb )[wkbPosition], &nPointsInRing,
sizeof(
int ) );
464 wkbPosition +=
sizeof( int );
466 QgsPolyline::const_iterator iter;
467 for ( iter = it->begin(); iter != it->end(); ++iter )
472 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
473 wkbPosition +=
sizeof( double );
474 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
475 wkbPosition +=
sizeof( double );
480 memcpy( &( wkb )[wkbPosition], &z,
sizeof(
double ) );
481 wkbPosition +=
sizeof( double );
491QgsGeometry QgsOgcUtils::geometryFromGMLMultiPoint(
const QDomElement &geometryElement )
495 const QDomNodeList pointMemberList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"pointMember" ) );
496 if ( pointMemberList.size() < 1 )
498 return QgsGeometry();
500 QDomNodeList pointNodeList;
502 QDomNodeList coordinatesList;
503 QDomNodeList posList;
504 for (
int i = 0; i < pointMemberList.size(); ++i )
507 pointNodeList = pointMemberList.at( i ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"Point" ) );
508 if ( pointNodeList.size() < 1 )
513 coordinatesList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
514 if ( !coordinatesList.isEmpty() )
516 currentPoint.clear();
517 if ( readGMLCoordinates( currentPoint, coordinatesList.at( 0 ).toElement() ) != 0 )
521 if ( currentPoint.empty() )
525 pointList.push_back( ( *currentPoint.begin() ) );
531 posList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"pos" ) );
532 if ( posList.size() < 1 )
536 currentPoint.clear();
537 if ( readGMLPositions( currentPoint, posList.at( 0 ).toElement() ) != 0 )
541 if ( currentPoint.empty() )
545 pointList.push_back( ( *currentPoint.begin() ) );
549 int nPoints = pointList.size();
551 return QgsGeometry();
553 const bool hasZ { !std::isnan( pointList.first().z() ) };
556 const int size = 1 + 2 *
static_cast<int>(
sizeof( int ) ) +
static_cast<int>( pointList.size() ) * ( ( hasZ ? 3 : 2 ) *
static_cast<int>(
sizeof( double ) ) + 1 +
static_cast<int>(
sizeof( int ) ) );
559 unsigned char *wkb =
new unsigned char[size];
562 char e =
static_cast<char>( htonl( 1 ) != 1 );
565 memcpy( &( wkb )[wkbPosition], &e, 1 );
567 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
568 wkbPosition +=
sizeof( int );
569 memcpy( &( wkb )[wkbPosition], &nPoints,
sizeof(
int ) );
570 wkbPosition +=
sizeof( int );
572 for ( QgsPolyline::const_iterator it = pointList.constBegin(); it != pointList.constEnd(); ++it )
574 memcpy( &( wkb )[wkbPosition], &e, 1 );
576 memcpy( &( wkb )[wkbPosition], &pointType,
sizeof(
int ) );
577 wkbPosition +=
sizeof( int );
579 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
580 wkbPosition +=
sizeof( double );
582 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
583 wkbPosition +=
sizeof( double );
588 memcpy( &( wkb )[wkbPosition], &z,
sizeof(
double ) );
589 wkbPosition +=
sizeof( double );
598QgsGeometry QgsOgcUtils::geometryFromGMLMultiLineString(
const QDomElement &geometryElement )
610 QList< QgsPolyline > lineCoordinates;
611 QDomElement currentLineStringElement;
612 QDomNodeList currentCoordList;
613 QDomNodeList currentPosList;
615 const QDomNodeList lineStringMemberList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"lineStringMember" ) );
616 if ( !lineStringMemberList.isEmpty() )
618 for (
int i = 0; i < lineStringMemberList.size(); ++i )
620 const QDomNodeList lineStringNodeList = lineStringMemberList.at( i ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LineString" ) );
621 if ( lineStringNodeList.size() < 1 )
623 return QgsGeometry();
625 currentLineStringElement = lineStringNodeList.at( 0 ).toElement();
626 currentCoordList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
627 if ( !currentCoordList.isEmpty() )
630 if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 )
632 return QgsGeometry();
634 lineCoordinates.push_back( currentPointList );
638 currentPosList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
639 if ( currentPosList.size() < 1 )
641 return QgsGeometry();
644 if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 )
646 return QgsGeometry();
648 lineCoordinates.push_back( currentPointList );
654 const QDomNodeList lineStringList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LineString" ) );
655 if ( !lineStringList.isEmpty() )
657 for (
int i = 0; i < lineStringList.size(); ++i )
659 currentLineStringElement = lineStringList.at( i ).toElement();
660 currentCoordList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
661 if ( !currentCoordList.isEmpty() )
664 if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 )
666 return QgsGeometry();
668 lineCoordinates.push_back( currentPointList );
669 return QgsGeometry();
673 currentPosList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
674 if ( currentPosList.size() < 1 )
676 return QgsGeometry();
679 if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 )
681 return QgsGeometry();
683 lineCoordinates.push_back( currentPointList );
689 return QgsGeometry();
693 int nLines = lineCoordinates.size();
695 return QgsGeometry();
697 const bool hasZ { !std::isnan( lineCoordinates.first().first().z() ) };
698 const int coordSize { hasZ ? 3 : 2 };
701 int size =
static_cast<int>( lineCoordinates.size() + 1 ) * ( 1 + 2 *
sizeof( int ) );
702 for ( QList< QgsPolyline >::const_iterator it = lineCoordinates.constBegin(); it != lineCoordinates.constEnd(); ++it )
704 size += it->size() * coordSize *
sizeof( double );
708 unsigned char *wkb =
new unsigned char[size];
711 char e =
static_cast<char>( htonl( 1 ) != 1 );
715 memcpy( &( wkb )[wkbPosition], &e, 1 );
717 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
718 wkbPosition +=
sizeof( int );
719 memcpy( &( wkb )[wkbPosition], &nLines,
sizeof(
int ) );
720 wkbPosition +=
sizeof( int );
722 for ( QList< QgsPolyline >::const_iterator it = lineCoordinates.constBegin(); it != lineCoordinates.constEnd(); ++it )
724 memcpy( &( wkb )[wkbPosition], &e, 1 );
726 memcpy( &( wkb )[wkbPosition], &lineType,
sizeof(
int ) );
727 wkbPosition +=
sizeof( int );
728 nPoints = it->size();
729 memcpy( &( wkb )[wkbPosition], &nPoints,
sizeof(
int ) );
730 wkbPosition +=
sizeof( int );
731 for ( QgsPolyline::const_iterator iter = it->begin(); iter != it->end(); ++iter )
736 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
737 wkbPosition +=
sizeof( double );
738 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
739 wkbPosition +=
sizeof( double );
744 memcpy( &( wkb )[wkbPosition], &z,
sizeof(
double ) );
745 wkbPosition +=
sizeof( double );
755QgsGeometry QgsOgcUtils::geometryFromGMLMultiPolygon(
const QDomElement &geometryElement )
758 QVector<QgsMultiPolyline> multiPolygonPoints;
759 QDomElement currentPolygonMemberElement;
760 QDomNodeList polygonList;
761 QDomElement currentPolygonElement;
763 QDomNodeList outerBoundaryList;
764 QDomElement currentOuterBoundaryElement;
765 QDomElement currentInnerBoundaryElement;
767 QDomNodeList exteriorList;
768 QDomElement currentExteriorElement;
769 QDomElement currentInteriorElement;
771 QDomNodeList linearRingNodeList;
772 QDomElement currentLinearRingElement;
774 QDomNodeList currentCoordinateList;
775 QDomNodeList currentPosList;
777 const QDomNodeList polygonMemberList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"polygonMember" ) );
779 for (
int i = 0; i < polygonMemberList.size(); ++i )
781 currentPolygonList.resize( 0 );
782 currentPolygonMemberElement = polygonMemberList.at( i ).toElement();
783 polygonList = currentPolygonMemberElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"Polygon" ) );
784 if ( polygonList.size() < 1 )
788 currentPolygonElement = polygonList.at( 0 ).toElement();
791 outerBoundaryList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"outerBoundaryIs" ) );
792 if ( !outerBoundaryList.isEmpty() )
794 currentOuterBoundaryElement = outerBoundaryList.at( 0 ).toElement();
797 linearRingNodeList = currentOuterBoundaryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
798 if ( linearRingNodeList.size() < 1 )
802 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
803 currentCoordinateList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
804 if ( currentCoordinateList.size() < 1 )
808 if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 )
812 currentPolygonList.push_back( ringCoordinates );
815 const QDomNodeList innerBoundaryList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"innerBoundaryIs" ) );
816 for (
int j = 0; j < innerBoundaryList.size(); ++j )
819 currentInnerBoundaryElement = innerBoundaryList.at( j ).toElement();
820 linearRingNodeList = currentInnerBoundaryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
821 if ( linearRingNodeList.size() < 1 )
825 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
826 currentCoordinateList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
827 if ( currentCoordinateList.size() < 1 )
831 if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 )
835 currentPolygonList.push_back( ringCoordinates );
841 exteriorList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"exterior" ) );
842 if ( exteriorList.size() < 1 )
847 currentExteriorElement = exteriorList.at( 0 ).toElement();
850 linearRingNodeList = currentExteriorElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
851 if ( linearRingNodeList.size() < 1 )
855 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
856 currentPosList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
857 if ( currentPosList.size() < 1 )
861 if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 )
865 currentPolygonList.push_back( ringPositions );
868 const QDomNodeList interiorList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"interior" ) );
869 for (
int j = 0; j < interiorList.size(); ++j )
872 currentInteriorElement = interiorList.at( j ).toElement();
873 linearRingNodeList = currentInteriorElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
874 if ( linearRingNodeList.size() < 1 )
878 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
879 currentPosList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
880 if ( currentPosList.size() < 1 )
884 if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 )
888 currentPolygonList.push_back( ringPositions );
891 multiPolygonPoints.push_back( currentPolygonList );
894 int nPolygons = multiPolygonPoints.size();
896 return QgsGeometry();
898 const bool hasZ { !std::isnan( multiPolygonPoints.first().first().first().z() ) };
900 int size = 1 + 2 *
sizeof( int );
903 for (
auto it = multiPolygonPoints.constBegin(); it != multiPolygonPoints.constEnd(); ++it )
905 size += 1 + 2 *
sizeof( int );
906 for (
auto iter = it->begin(); iter != it->end(); ++iter )
908 size +=
static_cast<int>(
sizeof( int ) ) + ( hasZ ? 3 : 2 ) *
static_cast<int>( iter->size() *
sizeof(
double ) );
913 unsigned char *wkb =
new unsigned char[size];
915 char e =
static_cast<char>( htonl( 1 ) != 1 );
922 memcpy( &( wkb )[wkbPosition], &e, 1 );
924 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
925 wkbPosition +=
sizeof( int );
926 memcpy( &( wkb )[wkbPosition], &nPolygons,
sizeof(
int ) );
927 wkbPosition +=
sizeof( int );
931 for (
auto it = multiPolygonPoints.constBegin(); it != multiPolygonPoints.constEnd(); ++it )
933 memcpy( &( wkb )[wkbPosition], &e, 1 );
935 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
936 wkbPosition +=
sizeof( int );
938 memcpy( &( wkb )[wkbPosition], &nRings,
sizeof(
int ) );
939 wkbPosition +=
sizeof( int );
940 for (
auto iter = it->begin(); iter != it->end(); ++iter )
942 nPointsInRing = iter->size();
943 memcpy( &( wkb )[wkbPosition], &nPointsInRing,
sizeof(
int ) );
944 wkbPosition +=
sizeof( int );
945 for (
auto iterator = iter->begin(); iterator != iter->end(); ++iterator )
949 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
950 wkbPosition +=
sizeof( double );
951 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
952 wkbPosition +=
sizeof( double );
955 double z = iterator->z();
956 memcpy( &( wkb )[wkbPosition], &z,
sizeof(
double ) );
957 wkbPosition +=
sizeof( double );
968QDomElement QgsOgcUtils::filterElement( QDomDocument &doc, GMLVersion gmlVersion, FilterVersion filterVersion,
bool GMLUsed )
970 QDomElement filterElem =
972 doc.createElementNS(
FES_NAMESPACE, QStringLiteral(
"fes:Filter" ) ) :
973 doc.createElementNS(
OGC_NAMESPACE, QStringLiteral(
"ogc:Filter" ) );
977 QDomAttr attr = doc.createAttribute( QStringLiteral(
"xmlns:gml" ) );
982 filterElem.setAttributeNode( attr );
988bool QgsOgcUtils::readGMLCoordinates(
QgsPolyline &coords,
const QDomElement &elem )
990 QString coordSeparator = QStringLiteral(
"," );
991 QString tupleSeparator = QStringLiteral(
" " );
996 if ( elem.hasAttribute( QStringLiteral(
"cs" ) ) )
998 coordSeparator = elem.attribute( QStringLiteral(
"cs" ) );
1000 if ( elem.hasAttribute( QStringLiteral(
"ts" ) ) )
1002 tupleSeparator = elem.attribute( QStringLiteral(
"ts" ) );
1005 const QStringList tupels = elem.text().split( tupleSeparator, Qt::SkipEmptyParts );
1006 QStringList tuple_coords;
1008 bool conversionSuccess;
1010 QStringList::const_iterator it;
1011 for ( it = tupels.constBegin(); it != tupels.constEnd(); ++it )
1013 tuple_coords = ( *it ).split( coordSeparator, Qt::SkipEmptyParts );
1014 if ( tuple_coords.size() < 2 )
1018 x = tuple_coords.at( 0 ).toDouble( &conversionSuccess );
1019 if ( !conversionSuccess )
1023 y = tuple_coords.at( 1 ).toDouble( &conversionSuccess );
1024 if ( !conversionSuccess )
1028 if ( tuple_coords.size() > 2 )
1030 z = tuple_coords.at( 2 ).toDouble( &conversionSuccess );
1031 if ( !conversionSuccess )
1038 z = std::numeric_limits<double>::quiet_NaN();
1040 coords.append( QgsPoint( x, y, z ) );
1049 const QDomElement boxElem = boxNode.toElement();
1050 if ( boxElem.tagName() != QLatin1String(
"Box" ) )
1053 const QDomElement bElem = boxElem.firstChild().toElement();
1054 QString coordSeparator = QStringLiteral(
"," );
1055 QString tupleSeparator = QStringLiteral(
" " );
1056 if ( bElem.hasAttribute( QStringLiteral(
"cs" ) ) )
1058 coordSeparator = bElem.attribute( QStringLiteral(
"cs" ) );
1060 if ( bElem.hasAttribute( QStringLiteral(
"ts" ) ) )
1062 tupleSeparator = bElem.attribute( QStringLiteral(
"ts" ) );
1065 const QString bString = bElem.text();
1066 bool ok1, ok2, ok3, ok4;
1067 const double xmin = bString.section( tupleSeparator, 0, 0 ).section( coordSeparator, 0, 0 ).toDouble( &ok1 );
1068 const double ymin = bString.section( tupleSeparator, 0, 0 ).section( coordSeparator, 1, 1 ).toDouble( &ok2 );
1069 const double xmax = bString.section( tupleSeparator, 1, 1 ).section( coordSeparator, 0, 0 ).toDouble( &ok3 );
1070 const double ymax = bString.section( tupleSeparator, 1, 1 ).section( coordSeparator, 1, 1 ).toDouble( &ok4 );
1072 if ( ok1 && ok2 && ok3 && ok4 )
1081bool QgsOgcUtils::readGMLPositions(
QgsPolyline &coords,
const QDomElement &elem )
1085 const QStringList pos = elem.text().split(
' ', Qt::SkipEmptyParts );
1087 bool conversionSuccess;
1088 const int posSize = pos.size();
1090 int srsDimension = 2;
1091 if ( elem.hasAttribute( QStringLiteral(
"srsDimension" ) ) )
1093 srsDimension = elem.attribute( QStringLiteral(
"srsDimension" ) ).toInt( &conversionSuccess );
1094 if ( !conversionSuccess )
1099 else if ( elem.hasAttribute( QStringLiteral(
"dimension" ) ) )
1101 srsDimension = elem.attribute( QStringLiteral(
"dimension" ) ).toInt( &conversionSuccess );
1102 if ( !conversionSuccess )
1108 for (
int i = 0; i < posSize / srsDimension; i++ )
1110 x = pos.at( i * srsDimension ).toDouble( &conversionSuccess );
1111 if ( !conversionSuccess )
1115 y = pos.at( i * srsDimension + 1 ).toDouble( &conversionSuccess );
1116 if ( !conversionSuccess )
1120 if ( srsDimension > 2 )
1122 z = pos.at( i * srsDimension + 2 ).toDouble( &conversionSuccess );
1123 if ( !conversionSuccess )
1130 z = std::numeric_limits<double>::quiet_NaN();
1132 coords.append( QgsPoint( x, y, z ) );
1142 const QDomElement envelopeElem = envelopeNode.toElement();
1143 if ( envelopeElem.tagName() != QLatin1String(
"Envelope" ) )
1146 const QDomNodeList lowerCornerList = envelopeElem.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"lowerCorner" ) );
1147 if ( lowerCornerList.size() < 1 )
1150 const QDomNodeList upperCornerList = envelopeElem.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"upperCorner" ) );
1151 if ( upperCornerList.size() < 1 )
1154 bool conversionSuccess;
1155 int srsDimension = 2;
1157 QDomElement elem = lowerCornerList.at( 0 ).toElement();
1158 if ( elem.hasAttribute( QStringLiteral(
"srsDimension" ) ) )
1160 srsDimension = elem.attribute( QStringLiteral(
"srsDimension" ) ).toInt( &conversionSuccess );
1161 if ( !conversionSuccess )
1166 else if ( elem.hasAttribute( QStringLiteral(
"dimension" ) ) )
1168 srsDimension = elem.attribute( QStringLiteral(
"dimension" ) ).toInt( &conversionSuccess );
1169 if ( !conversionSuccess )
1174 QString bString = elem.text();
1176 const double xmin = bString.section(
' ', 0, 0 ).toDouble( &conversionSuccess );
1177 if ( !conversionSuccess )
1179 const double ymin = bString.section(
' ', 1, 1 ).toDouble( &conversionSuccess );
1180 if ( !conversionSuccess )
1183 elem = upperCornerList.at( 0 ).toElement();
1184 if ( elem.hasAttribute( QStringLiteral(
"srsDimension" ) ) )
1186 srsDimension = elem.attribute( QStringLiteral(
"srsDimension" ) ).toInt( &conversionSuccess );
1187 if ( !conversionSuccess )
1192 else if ( elem.hasAttribute( QStringLiteral(
"dimension" ) ) )
1194 srsDimension = elem.attribute( QStringLiteral(
"dimension" ) ).toInt( &conversionSuccess );
1195 if ( !conversionSuccess )
1201 Q_UNUSED( srsDimension )
1203 bString = elem.text();
1204 const double xmax = bString.section(
' ', 0, 0 ).toDouble( &conversionSuccess );
1205 if ( !conversionSuccess )
1207 const double ymax = bString.section(
' ', 1, 1 ).toDouble( &conversionSuccess );
1208 if ( !conversionSuccess )
1223 const QString &srsName,
1224 bool invertAxisOrientation,
1229 return QDomElement();
1232 QDomElement boxElem = doc.createElement( QStringLiteral(
"gml:Box" ) );
1233 if ( !srsName.isEmpty() )
1235 boxElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1237 QDomElement coordElem = doc.createElement( QStringLiteral(
"gml:coordinates" ) );
1238 coordElem.setAttribute( QStringLiteral(
"cs" ), QStringLiteral(
"," ) );
1239 coordElem.setAttribute( QStringLiteral(
"ts" ), QStringLiteral(
" " ) );
1241 QString coordString;
1250 const QDomText coordText = doc.createTextNode( coordString );
1251 coordElem.appendChild( coordText );
1252 boxElem.appendChild( coordElem );
1263 const QString &srsName,
1264 bool invertAxisOrientation,
1269 return QDomElement();
1272 QDomElement envElem = doc.createElement( QStringLiteral(
"gml:Envelope" ) );
1273 if ( !srsName.isEmpty() )
1275 envElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1279 QDomElement lowerCornerElem = doc.createElement( QStringLiteral(
"gml:lowerCorner" ) );
1283 const QDomText lowerCornerText = doc.createTextNode( posList );
1284 lowerCornerElem.appendChild( lowerCornerText );
1285 envElem.appendChild( lowerCornerElem );
1287 QDomElement upperCornerElem = doc.createElement( QStringLiteral(
"gml:upperCorner" ) );
1291 const QDomText upperCornerText = doc.createTextNode( posList );
1292 upperCornerElem.appendChild( upperCornerText );
1293 envElem.appendChild( upperCornerElem );
1306 const QString &srsName,
1307 bool invertAxisOrientation,
1308 const QString &gmlIdBase,
1312 return QDomElement();
1315 QString cs = QStringLiteral(
"," );
1317 const QString ts = QStringLiteral(
" " );
1319 QDomElement baseCoordElem;
1321 bool hasZValue =
false;
1323 const QByteArray wkb( geometry.
asWkb() );
1333 return QDomElement();
1346 baseCoordElem = doc.createElement( QStringLiteral(
"gml:pos" ) );
1349 baseCoordElem = doc.createElement( QStringLiteral(
"gml:posList" ) );
1356 baseCoordElem = doc.createElement( QStringLiteral(
"gml:coordinates" ) );
1357 baseCoordElem.setAttribute( QStringLiteral(
"cs" ), cs );
1358 baseCoordElem.setAttribute( QStringLiteral(
"ts" ), ts );
1372 QDomElement pointElem = doc.createElement( QStringLiteral(
"gml:Point" ) );
1373 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1374 pointElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1375 if ( !srsName.isEmpty() )
1376 pointElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1377 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1381 if ( invertAxisOrientation )
1395 const QDomText coordText = doc.createTextNode( coordString );
1397 coordElem.appendChild( coordText );
1399 coordElem.setAttribute( QStringLiteral(
"srsDimension" ), hasZValue ? QStringLiteral(
"3" ) : QStringLiteral(
"2" ) );
1400 pointElem.appendChild( coordElem );
1410 QDomElement multiPointElem = doc.createElement( QStringLiteral(
"gml:MultiPoint" ) );
1411 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1412 multiPointElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1413 if ( !srsName.isEmpty() )
1414 multiPointElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1419 for (
int idx = 0; idx < nPoints; ++idx )
1421 QDomElement pointMemberElem = doc.createElement( QStringLiteral(
"gml:pointMember" ) );
1422 QDomElement pointElem = doc.createElement( QStringLiteral(
"gml:Point" ) );
1423 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1424 pointElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase + QStringLiteral(
".%1" ).arg( idx + 1 ) );
1425 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1431 if ( invertAxisOrientation )
1445 const QDomText coordText = doc.createTextNode( coordString );
1447 coordElem.appendChild( coordText );
1449 coordElem.setAttribute( QStringLiteral(
"srsDimension" ), hasZValue ? QStringLiteral(
"3" ) : QStringLiteral(
"2" ) );
1450 pointElem.appendChild( coordElem );
1453 pointMemberElem.appendChild( pointElem );
1454 multiPointElem.appendChild( pointMemberElem );
1456 return multiPointElem;
1465 QDomElement lineStringElem = doc.createElement( QStringLiteral(
"gml:LineString" ) );
1466 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1467 lineStringElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1468 if ( !srsName.isEmpty() )
1469 lineStringElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1475 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1476 QString coordString;
1477 for (
int idx = 0; idx < nPoints; ++idx )
1486 if ( invertAxisOrientation )
1500 const QDomText coordText = doc.createTextNode( coordString );
1501 coordElem.appendChild( coordText );
1503 coordElem.setAttribute( QStringLiteral(
"srsDimension" ), hasZValue ? QStringLiteral(
"3" ) : QStringLiteral(
"2" ) );
1504 lineStringElem.appendChild( coordElem );
1505 return lineStringElem;
1514 QDomElement multiLineStringElem = doc.createElement( QStringLiteral(
"gml:MultiLineString" ) );
1515 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1516 multiLineStringElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1517 if ( !srsName.isEmpty() )
1518 multiLineStringElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1523 for (
int jdx = 0; jdx < nLines; jdx++ )
1525 QDomElement lineStringMemberElem = doc.createElement( QStringLiteral(
"gml:lineStringMember" ) );
1526 QDomElement lineStringElem = doc.createElement( QStringLiteral(
"gml:LineString" ) );
1527 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1528 lineStringElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase + QStringLiteral(
".%1" ).arg( jdx + 1 ) );
1535 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1536 QString coordString;
1537 for (
int idx = 0; idx < nPoints; idx++ )
1546 if ( invertAxisOrientation )
1561 const QDomText coordText = doc.createTextNode( coordString );
1562 coordElem.appendChild( coordText );
1564 coordElem.setAttribute( QStringLiteral(
"srsDimension" ), hasZValue ? QStringLiteral(
"3" ) : QStringLiteral(
"2" ) );
1565 lineStringElem.appendChild( coordElem );
1566 lineStringMemberElem.appendChild( lineStringElem );
1567 multiLineStringElem.appendChild( lineStringMemberElem );
1569 return multiLineStringElem;
1578 QDomElement polygonElem = doc.createElement( QStringLiteral(
"gml:Polygon" ) );
1579 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1580 polygonElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1581 if ( !srsName.isEmpty() )
1582 polygonElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1588 if ( numRings == 0 )
1589 return QDomElement();
1591 for (
int idx = 0; idx < numRings; idx++ )
1593 QString boundaryName = ( gmlVersion ==
GML_2_1_2 ) ?
"gml:outerBoundaryIs" :
"gml:exterior";
1596 boundaryName = ( gmlVersion ==
GML_2_1_2 ) ?
"gml:innerBoundaryIs" :
"gml:interior";
1598 QDomElement boundaryElem = doc.createElement( boundaryName );
1599 QDomElement ringElem = doc.createElement( QStringLiteral(
"gml:LinearRing" ) );
1604 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1605 QString coordString;
1606 for (
int jdx = 0; jdx < nPoints; jdx++ )
1615 if ( invertAxisOrientation )
1629 const QDomText coordText = doc.createTextNode( coordString );
1630 coordElem.appendChild( coordText );
1632 coordElem.setAttribute( QStringLiteral(
"srsDimension" ), hasZValue ? QStringLiteral(
"3" ) : QStringLiteral(
"2" ) );
1633 ringElem.appendChild( coordElem );
1634 boundaryElem.appendChild( ringElem );
1635 polygonElem.appendChild( boundaryElem );
1647 QDomElement multiPolygonElem = doc.createElement( QStringLiteral(
"gml:MultiPolygon" ) );
1648 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1649 multiPolygonElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1650 if ( !srsName.isEmpty() )
1651 multiPolygonElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1654 wkbPtr >> numPolygons;
1656 for (
int kdx = 0; kdx < numPolygons; kdx++ )
1658 QDomElement polygonMemberElem = doc.createElement( QStringLiteral(
"gml:polygonMember" ) );
1659 QDomElement polygonElem = doc.createElement( QStringLiteral(
"gml:Polygon" ) );
1660 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1661 polygonElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase + QStringLiteral(
".%1" ).arg( kdx + 1 ) );
1668 for (
int idx = 0; idx < numRings; idx++ )
1670 QString boundaryName = ( gmlVersion ==
GML_2_1_2 ) ?
"gml:outerBoundaryIs" :
"gml:exterior";
1673 boundaryName = ( gmlVersion ==
GML_2_1_2 ) ?
"gml:innerBoundaryIs" :
"gml:interior";
1675 QDomElement boundaryElem = doc.createElement( boundaryName );
1676 QDomElement ringElem = doc.createElement( QStringLiteral(
"gml:LinearRing" ) );
1681 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1682 QString coordString;
1683 for (
int jdx = 0; jdx < nPoints; jdx++ )
1692 if ( invertAxisOrientation )
1707 const QDomText coordText = doc.createTextNode( coordString );
1708 coordElem.appendChild( coordText );
1710 coordElem.setAttribute( QStringLiteral(
"srsDimension" ), hasZValue ? QStringLiteral(
"3" ) : QStringLiteral(
"2" ) );
1711 ringElem.appendChild( coordElem );
1712 boundaryElem.appendChild( ringElem );
1713 polygonElem.appendChild( boundaryElem );
1714 polygonMemberElem.appendChild( polygonElem );
1715 multiPolygonElem.appendChild( polygonMemberElem );
1718 return multiPolygonElem;
1721 return QDomElement();
1727 return QDomElement();
1733 return geometryToGML( geometry, doc, QStringLiteral(
"GML2" ), precision );
1736QDomElement QgsOgcUtils::createGMLCoordinates(
const QgsPolylineXY &points, QDomDocument &doc )
1738 QDomElement coordElem = doc.createElement( QStringLiteral(
"gml:coordinates" ) );
1739 coordElem.setAttribute( QStringLiteral(
"cs" ), QStringLiteral(
"," ) );
1740 coordElem.setAttribute( QStringLiteral(
"ts" ), QStringLiteral(
" " ) );
1742 QString coordString;
1743 QVector<QgsPointXY>::const_iterator pointIt = points.constBegin();
1744 for ( ; pointIt != points.constEnd(); ++pointIt )
1746 if ( pointIt != points.constBegin() )
1755 const QDomText coordText = doc.createTextNode( coordString );
1756 coordElem.appendChild( coordText );
1760QDomElement QgsOgcUtils::createGMLPositions(
const QgsPolylineXY &points, QDomDocument &doc )
1762 QDomElement posElem = doc.createElement( QStringLiteral(
"gml:pos" ) );
1763 if ( points.size() > 1 )
1764 posElem = doc.createElement( QStringLiteral(
"gml:posList" ) );
1765 posElem.setAttribute( QStringLiteral(
"srsDimension" ), QStringLiteral(
"2" ) );
1767 QString coordString;
1768 QVector<QgsPointXY>::const_iterator pointIt = points.constBegin();
1769 for ( ; pointIt != points.constEnd(); ++pointIt )
1771 if ( pointIt != points.constBegin() )
1780 const QDomText coordText = doc.createTextNode( coordString );
1781 posElem.appendChild( coordText );
1791 if ( fillElement.isNull() || !fillElement.hasChildNodes() )
1799 QDomElement cssElem = fillElement.firstChildElement( QStringLiteral(
"CssParameter" ) );
1800 while ( !cssElem.isNull() )
1802 cssName = cssElem.attribute( QStringLiteral(
"name" ), QStringLiteral(
"not_found" ) );
1803 if ( cssName != QLatin1String(
"not_found" ) )
1805 elemText = cssElem.text();
1806 if ( cssName == QLatin1String(
"fill" ) )
1808 color.setNamedColor( elemText );
1810 else if ( cssName == QLatin1String(
"fill-opacity" ) )
1813 const double opacity = elemText.toDouble( &ok );
1816 color.setAlphaF( opacity );
1821 cssElem = cssElem.nextSiblingElement( QStringLiteral(
"CssParameter" ) );
1835 if ( element.isNull() || !element.hasChildNodes() )
1842 if ( element.firstChild().nodeType() == QDomNode::TextNode )
1852 QDomElement childElem = element.firstChildElement();
1853 while ( !childElem.isNull() )
1865 if ( !expr->d->mRootNode )
1867 expr->d->mRootNode.reset( node );
1874 childElem = childElem.nextSiblingElement();
1878 expr->d->mExp = expr->
dump();
1904static int binaryOperatorFromTagName(
const QString &tagName )
1907 return BINARY_OPERATORS_TAG_NAMES_MAP()->value( tagName, -1 );
1914 return QStringLiteral(
"PropertyIsLike" );
1916 return BINARY_OPERATORS_TAG_NAMES_MAP()->key( op, QString() );
1919static bool isBinaryOperator(
const QString &tagName )
1921 return binaryOperatorFromTagName( tagName ) >= 0;
1925static bool isSpatialOperator(
const QString &tagName )
1927 static QStringList spatialOps;
1928 if ( spatialOps.isEmpty() )
1930 spatialOps << QStringLiteral(
"BBOX" ) << QStringLiteral(
"Intersects" ) << QStringLiteral(
"Contains" ) << QStringLiteral(
"Crosses" ) << QStringLiteral(
"Equals" )
1931 << QStringLiteral(
"Disjoint" ) << QStringLiteral(
"Overlaps" ) << QStringLiteral(
"Touches" ) << QStringLiteral(
"Within" );
1934 return spatialOps.contains( tagName );
1940 QgsExpressionNode *node = utils.nodeFromOgcFilter( element );
1941 errorMessage = utils.errorMessage();
1948 QgsExpressionNodeBinaryOperator *node = utils.nodeBinaryOperatorFromOgcFilter( element );
1949 errorMessage = utils.errorMessage();
1956 QgsExpressionNodeFunction *node = utils.nodeSpatialOperatorFromOgcFilter( element );
1957 errorMessage = utils.errorMessage();
1964 QgsExpressionNodeUnaryOperator *node = utils.nodeNotFromOgcFilter( element );
1965 errorMessage = utils.errorMessage();
1972 QgsExpressionNodeFunction *node = utils.nodeFunctionFromOgcFilter( element );
1973 errorMessage = utils.errorMessage();
1980 QgsExpressionNode *node = utils.nodeLiteralFromOgcFilter( element );
1981 errorMessage = utils.errorMessage();
1988 QgsExpressionNodeColumnRef *node = utils.nodeColumnRefFromOgcFilter( element );
1989 errorMessage = utils.errorMessage();
1993QgsExpressionNode *QgsOgcUtils::nodeIsBetweenFromOgcFilter( QDomElement &element, QString &errorMessage )
1996 QgsExpressionNode *node = utils.nodeIsBetweenFromOgcFilter( element );
1997 errorMessage = utils.errorMessage();
2004 QgsExpressionNodeBinaryOperator *node = utils.nodePropertyIsNullFromOgcFilter( element );
2005 errorMessage = utils.errorMessage();
2016 QStringLiteral(
"geometry" ), QString(),
false,
false, errorMessage );
2022 QStringLiteral(
"geometry" ), QString(),
false,
false, errorMessage, requiresFilterElement );
2027 return doc.createElementNS(
SE_NAMESPACE, QStringLiteral(
"se:ElseFilter" ) );
2035 const QString &namespacePrefix,
2036 const QString &namespaceURI,
2037 const QString &geometryName,
2038 const QString &srsName,
2039 bool honourAxisOrientation,
2040 bool invertAxisOrientation,
2041 QString *errorMessage,
2042 const QMap<QString, QString> &fieldNameToXPathMap,
2043 const QMap<QString, QString> &namespacePrefixToUriMap )
2046 return QDomElement();
2052 QgsOgcUtilsExprToFilter utils( doc, gmlVersion, filterVersion, namespacePrefix, namespaceURI, geometryName, srsName, honourAxisOrientation, invertAxisOrientation, fieldNameToXPathMap, namespacePrefixToUriMap );
2056 if ( exprRootElem.isNull() )
2057 return QDomElement();
2059 QDomElement filterElem = filterElement( doc, gmlVersion, filterVersion, utils.
GMLNamespaceUsed() );
2061 if ( !namespacePrefix.isEmpty() && !namespaceURI.isEmpty() )
2063 QDomAttr attr = doc.createAttribute( QStringLiteral(
"xmlns:" ) + namespacePrefix );
2064 attr.setValue( namespaceURI );
2065 filterElem.setAttributeNode( attr );
2068 filterElem.appendChild( exprRootElem );
2076 const QString &geometryName,
2077 const QString &srsName,
2078 bool honourAxisOrientation,
2079 bool invertAxisOrientation,
2080 QString *errorMessage,
2081 bool requiresFilterElement,
2082 const QMap<QString, QString> &fieldNameToXPathMap,
2083 const QMap<QString, QString> &namespacePrefixToUriMap )
2092 return QDomElement();
2101 QgsOgcUtilsExprToFilter utils( doc, gmlVersion, filterVersion, QString(), QString(), geometryName, srsName, honourAxisOrientation, invertAxisOrientation, fieldNameToXPathMap, namespacePrefixToUriMap );
2107 if ( !exprRootElem.isNull() )
2109 if ( requiresFilterElement )
2111 QDomElement filterElem = filterElement( doc, gmlVersion, filterVersion, utils.
GMLNamespaceUsed() );
2113 filterElem.appendChild( exprRootElem );
2116 return exprRootElem;
2123 *errorMessage = QObject::tr(
"Node type not supported in expression translation: %1" ).arg( node->
nodeType() );
2127 return QDomElement();
2134 const QList<LayerProperties> &layerProperties,
2135 bool honourAxisOrientation,
2136 bool invertAxisOrientation,
2137 const QMap< QString, QString> &mapUnprefixedTypenameToPrefixedTypename,
2138 QString *errorMessage,
2139 const QMap<QString, QString> &fieldNameToXPathMap,
2140 const QMap<QString, QString> &namespacePrefixToUriMap )
2143 return QDomElement();
2146 layerProperties, honourAxisOrientation, invertAxisOrientation,
2147 mapUnprefixedTypenameToPrefixedTypename, fieldNameToXPathMap, namespacePrefixToUriMap );
2151 if ( exprRootElem.isNull() )
2152 return QDomElement();
2154 QDomElement filterElem = filterElement( doc, gmlVersion, filterVersion, utils.
GMLNamespaceUsed() );
2156 QSet<QString> setNamespaceURI;
2159 if ( !props.mNamespacePrefix.isEmpty() && !props.mNamespaceURI.isEmpty() &&
2160 !setNamespaceURI.contains( props.mNamespaceURI ) )
2162 setNamespaceURI.insert( props.mNamespaceURI );
2163 QDomAttr attr = doc.createAttribute( QStringLiteral(
"xmlns:" ) + props.mNamespacePrefix );
2164 attr.setValue( props.mNamespaceURI );
2165 filterElem.setAttributeNode( attr );
2168 filterElem.appendChild( exprRootElem );
2193 mErrorMessage = QObject::tr(
"Node type not supported: %1" ).arg( node->
nodeType() );
2194 return QDomElement();
2201 if ( !mErrorMessage.isEmpty() )
2202 return QDomElement();
2205 switch ( node->
op() )
2208 uoElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2213 uoElem.appendChild( mDoc.createTextNode(
"-" + operandElem.text() ) );
2214 mDoc.removeChild( operandElem );
2218 mErrorMessage = QObject::tr(
"This use of unary operator not implemented yet" );
2219 return QDomElement();
2223 uoElem = mDoc.createElement( mFilterPrefix +
":Not" );
2224 uoElem.appendChild( operandElem );
2228 mErrorMessage = QObject::tr(
"Unary operator '%1' not implemented yet" ).arg( node->
text() );
2229 return QDomElement();
2239 if ( !mErrorMessage.isEmpty() )
2240 return QDomElement();
2249 const QgsExpressionNodeLiteral *rightLit =
static_cast<const QgsExpressionNodeLiteral *
>( node->
opRight() );
2253 QDomElement elem = mDoc.createElement( mFilterPrefix +
":PropertyIsNull" );
2254 elem.appendChild( leftElem );
2258 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2259 notElem.appendChild( elem );
2273 if ( !mErrorMessage.isEmpty() )
2274 return QDomElement();
2277 const QString opText = binaryOperatorToTagName( op );
2278 if ( opText.isEmpty() )
2282 mErrorMessage = QObject::tr(
"Binary operator %1 not implemented yet" ).arg( node->
text() );
2283 return QDomElement();
2286 QDomElement boElem = mDoc.createElement( mFilterPrefix +
":" + opText );
2291 boElem.setAttribute( QStringLiteral(
"matchCase" ), QStringLiteral(
"false" ) );
2294 boElem.setAttribute( QStringLiteral(
"wildCard" ), QStringLiteral(
"%" ) );
2295 boElem.setAttribute( QStringLiteral(
"singleChar" ), QStringLiteral(
"_" ) );
2297 boElem.setAttribute( QStringLiteral(
"escape" ), QStringLiteral(
"\\" ) );
2299 boElem.setAttribute( QStringLiteral(
"escapeChar" ), QStringLiteral(
"\\" ) );
2302 boElem.appendChild( leftElem );
2303 boElem.appendChild( rightElem );
2310 Q_UNUSED( expression )
2313 switch ( node->
value().userType() )
2315 case QMetaType::Type::Int:
2316 value = QString::number( node->
value().toInt() );
2318 case QMetaType::Type::Double:
2321 case QMetaType::Type::QString:
2322 value = node->
value().toString();
2324 case QMetaType::Type::QDate:
2325 value = node->
value().toDate().toString( Qt::ISODate );
2327 case QMetaType::Type::QDateTime:
2328 value = node->
value().toDateTime().toString( Qt::ISODate );
2332 mErrorMessage = QObject::tr(
"Literal type not supported: %1" ).arg(
static_cast<QMetaType::Type
>( node->
value().userType() ) );
2333 return QDomElement();
2336 QDomElement litElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2337 litElem.appendChild( mDoc.createTextNode( value ) );
2344 Q_UNUSED( expression )
2346 QDomElement propElem = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2347 if ( !mFieldNameToXPathMap.isEmpty() )
2349 const auto iterFieldName = mFieldNameToXPathMap.constFind( node->
name() );
2350 if ( iterFieldName != mFieldNameToXPathMap.constEnd() )
2352 const QString xpath( *iterFieldName );
2354 if ( !mNamespacePrefixToUriMap.isEmpty() )
2356 const QStringList parts = xpath.split(
'/' );
2357 QSet<QString> setNamespacePrefix;
2358 for (
const QString &part : std::as_const( parts ) )
2360 const QStringList subparts = part.split(
':' );
2361 if ( subparts.size() == 2 && !setNamespacePrefix.contains( subparts[0] ) )
2363 const auto iterNamespacePrefix = mNamespacePrefixToUriMap.constFind( subparts[0] );
2364 if ( iterNamespacePrefix != mNamespacePrefixToUriMap.constEnd() )
2366 setNamespacePrefix.insert( subparts[0] );
2367 QDomAttr attr = mDoc.createAttribute( QStringLiteral(
"xmlns:" ) + subparts[0] );
2368 attr.setValue( *iterNamespacePrefix );
2369 propElem.setAttributeNode( attr );
2375 propElem.appendChild( mDoc.createTextNode( xpath ) );
2380 QString columnRef( node->
name() );
2381 if ( !mNamespacePrefix.isEmpty() && !mNamespaceURI.isEmpty() )
2382 columnRef = mNamespacePrefix + QStringLiteral(
":" ) + columnRef;
2383 propElem.appendChild( mDoc.createTextNode( columnRef ) );
2391 if ( node->
list()->
list().size() == 1 )
2395 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
2396 eqElem.appendChild( leftNode );
2397 eqElem.appendChild( firstListNode );
2400 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2401 notElem.appendChild( eqElem );
2407 QDomElement orElem = mDoc.createElement( mFilterPrefix +
":Or" );
2410 const auto constList = node->
list()->
list();
2411 for ( QgsExpressionNode *n : constList )
2414 if ( !mErrorMessage.isEmpty() )
2415 return QDomElement();
2417 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
2418 eqElem.appendChild( leftNode.cloneNode() );
2419 eqElem.appendChild( listNode );
2421 orElem.appendChild( eqElem );
2426 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2427 notElem.appendChild( orElem );
2436 { QLatin1String(
"disjoint" ), QLatin1String(
"Disjoint" ) },
2437 { QLatin1String(
"intersects" ), QLatin1String(
"Intersects" )},
2438 { QLatin1String(
"touches" ), QLatin1String(
"Touches" ) },
2439 { QLatin1String(
"crosses" ), QLatin1String(
"Crosses" ) },
2440 { QLatin1String(
"contains" ), QLatin1String(
"Contains" ) },
2441 { QLatin1String(
"overlaps" ), QLatin1String(
"Overlaps" ) },
2442 { QLatin1String(
"within" ), QLatin1String(
"Within" ) }
2445static bool isBinarySpatialOperator(
const QString &fnName )
2447 return BINARY_SPATIAL_OPS_MAP()->contains( fnName );
2450static QString tagNameForSpatialOperator(
const QString &fnName )
2452 return BINARY_SPATIAL_OPS_MAP()->value( fnName );
2462 return fd->
name() == QLatin1String(
"$geometry" ) || ( fd->
name() == QLatin1String(
"var" ) && fn->
referencedVariables().contains( QLatin1String(
"geometry" ) ) );
2474 if ( fnDef->
name() == QLatin1String(
"geom_from_wkt" ) )
2476 const QList<QgsExpressionNode *> &args = fnNode->
args()->
list();
2492 if ( fd->
name() == QLatin1String(
"intersects_bbox" ) )
2494 QList<QgsExpressionNode *> argNodes = node->
args()->
list();
2495 Q_ASSERT( argNodes.count() == 2 );
2497 const QgsGeometry geom = geometryFromConstExpr( argNodes[1] );
2498 if ( !geom.
isNull() && isGeometryColumn( argNodes[0] ) )
2508 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":BBOX" );
2510 if ( !mGeometryName.isEmpty() )
2513 QDomElement geomProperty = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2514 QString columnRef( mGeometryName );
2515 if ( !mNamespacePrefix.isEmpty() && !mNamespaceURI.isEmpty() )
2516 columnRef = mNamespacePrefix + QStringLiteral(
":" ) + columnRef;
2517 geomProperty.appendChild( mDoc.createTextNode( columnRef ) );
2519 funcElem.appendChild( geomProperty );
2521 funcElem.appendChild( elemBox );
2526 mErrorMessage = QObject::tr(
"<BBOX> is currently supported only in form: bbox(@geometry, geomFromWKT('…'))" );
2527 return QDomElement();
2531 if ( isBinarySpatialOperator( fd->
name() ) )
2533 QList<QgsExpressionNode *> argNodes = node->
args()->
list();
2534 Q_ASSERT( argNodes.count() == 2 );
2536 QgsExpressionNode *otherNode =
nullptr;
2537 if ( isGeometryColumn( argNodes[0] ) )
2538 otherNode = argNodes[1];
2539 else if ( isGeometryColumn( argNodes[1] ) )
2540 otherNode = argNodes[0];
2543 mErrorMessage = QObject::tr(
"Unable to translate spatial operator: at least one must refer to geometry." );
2544 return QDomElement();
2547 QDomElement otherGeomElem;
2552 mErrorMessage = QObject::tr(
"spatial operator: the other operator must be a geometry constructor function" );
2553 return QDomElement();
2556 const QgsExpressionNodeFunction *otherFn =
static_cast<const QgsExpressionNodeFunction *
>( otherNode );
2558 if ( otherFnDef->
name() == QLatin1String(
"geom_from_wkt" ) )
2560 QgsExpressionNode *firstFnArg = otherFn->
args()->
list()[0];
2563 mErrorMessage = QObject::tr(
"geom_from_wkt: argument must be string literal" );
2564 return QDomElement();
2566 const QString wkt =
static_cast<const QgsExpressionNodeLiteral *
>( firstFnArg )->value().toString();
2569 QStringLiteral(
"qgis_id_geom_%1" ).arg( mGeomId ) );
2570 if ( otherGeomElem.isNull() )
2572 mErrorMessage = QObject::tr(
"geom_from_wkt: unable to generate GML from wkt geometry" );
2573 return QDomElement();
2577 else if ( otherFnDef->
name() == QLatin1String(
"geom_from_gml" ) )
2579 QgsExpressionNode *firstFnArg = otherFn->
args()->
list()[0];
2582 mErrorMessage = QObject::tr(
"geom_from_gml: argument must be string literal" );
2583 return QDomElement();
2586 QDomDocument geomDoc;
2587 const QString gml =
static_cast<const QgsExpressionNodeLiteral *
>( firstFnArg )->value().toString();
2589 const QString xml = QStringLiteral(
"<tmp xmlns:gml=\"%1\">%2</tmp>" ).arg(
GML_NAMESPACE, gml );
2590 if ( !geomDoc.setContent( xml,
true ) )
2592 mErrorMessage = QObject::tr(
"geom_from_gml: unable to parse XML" );
2593 return QDomElement();
2596 const QDomNode geomNode = mDoc.importNode( geomDoc.documentElement().firstChildElement(),
true );
2597 otherGeomElem = geomNode.toElement();
2603 QStringLiteral(
"qgis_id_geom_%1" ).arg( mGeomId ) );
2604 if ( otherGeomElem.
isNull() )
2606 mErrorMessage = QObject::tr(
"geom from static value: unable to generate GML from static variable" );
2607 return QDomElement();
2613 mErrorMessage = QObject::tr(
"spatial operator: unknown geometry constructor function" );
2614 return QDomElement();
2619 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":" + tagNameForSpatialOperator( fd->
name() ) );
2620 QDomElement geomProperty = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2621 QString columnRef( mGeometryName );
2622 if ( !mNamespacePrefix.isEmpty() && !mNamespaceURI.isEmpty() )
2623 columnRef = mNamespacePrefix + QStringLiteral(
":" ) + columnRef;
2624 geomProperty.appendChild( mDoc.createTextNode( columnRef ) );
2625 funcElem.appendChild( geomProperty );
2626 funcElem.appendChild( otherGeomElem );
2630 if ( fd->
isStatic( node, expression, context ) )
2632 const QVariant result = fd->
run( node->
args(), context, expression, node );
2633 const QgsExpressionNodeLiteral literal( result );
2634 return expressionLiteralToOgcFilter( &literal, expression, context );
2639 mErrorMessage = QObject::tr(
"Special columns/constants are not supported." );
2640 return QDomElement();
2644 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":Function" );
2645 funcElem.setAttribute( QStringLiteral(
"name" ), fd->
name() );
2646 const auto constList = node->
args()->
list();
2647 for ( QgsExpressionNode *n : constList )
2650 if ( !mErrorMessage.isEmpty() )
2651 return QDomElement();
2653 funcElem.appendChild( childElem );
2664 const QList<QgsOgcUtils::LayerProperties> &layerProperties,
2665 bool honourAxisOrientation,
2666 bool invertAxisOrientation,
2667 const QMap< QString, QString> &mapUnprefixedTypenameToPrefixedTypename,
2668 const QMap<QString, QString> &fieldNameToXPathMap,
2669 const QMap<QString, QString> &namespacePrefixToUriMap )
2672 , mGMLVersion( gmlVersion )
2673 , mFilterVersion( filterVersion )
2674 , mLayerProperties( layerProperties )
2675 , mHonourAxisOrientation( honourAxisOrientation )
2676 , mInvertAxisOrientation( invertAxisOrientation )
2677 , mFilterPrefix( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"fes" :
"ogc" )
2678 , mPropertyName( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"ValueReference" :
"PropertyName" )
2680 , mMapUnprefixedTypenameToPrefixedTypename( mapUnprefixedTypenameToPrefixedTypename )
2681 , mFieldNameToXPathMap( fieldNameToXPathMap )
2682 , mNamespacePrefixToUriMap( namespacePrefixToUriMap )
2708 mErrorMessage = QObject::tr(
"Node type not supported: %1" ).arg( node->
nodeType() );
2709 return QDomElement();
2718 if ( !mErrorMessage.isEmpty() )
2719 return QDomElement();
2722 switch ( node->
op() )
2725 uoElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2730 uoElem.appendChild( mDoc.createTextNode(
"-" + operandElem.text() ) );
2731 mDoc.removeChild( operandElem );
2735 mErrorMessage = QObject::tr(
"This use of unary operator not implemented yet" );
2736 return QDomElement();
2740 uoElem = mDoc.createElement( mFilterPrefix +
":Not" );
2741 uoElem.appendChild( operandElem );
2746 return QDomElement();
2756 if ( !mErrorMessage.isEmpty() )
2757 return QDomElement();
2766 const QgsSQLStatement::NodeLiteral *rightLit =
static_cast<const QgsSQLStatement::NodeLiteral *
>( node->
opRight() );
2770 QDomElement elem = mDoc.createElement( mFilterPrefix +
":PropertyIsNull" );
2771 elem.appendChild( leftElem );
2775 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2776 notElem.appendChild( elem );
2790 if ( !mErrorMessage.isEmpty() )
2791 return QDomElement();
2796 opText = QStringLiteral(
"Or" );
2798 opText = QStringLiteral(
"And" );
2800 opText = QStringLiteral(
"PropertyIsEqualTo" );
2802 opText = QStringLiteral(
"PropertyIsNotEqualTo" );
2804 opText = QStringLiteral(
"PropertyIsLessThanOrEqualTo" );
2806 opText = QStringLiteral(
"PropertyIsGreaterThanOrEqualTo" );
2808 opText = QStringLiteral(
"PropertyIsLessThan" );
2810 opText = QStringLiteral(
"PropertyIsGreaterThan" );
2812 opText = QStringLiteral(
"PropertyIsLike" );
2814 opText = QStringLiteral(
"PropertyIsLike" );
2816 if ( opText.isEmpty() )
2820 return QDomElement();
2823 QDomElement boElem = mDoc.createElement( mFilterPrefix +
":" + opText );
2828 boElem.setAttribute( QStringLiteral(
"matchCase" ), QStringLiteral(
"false" ) );
2831 boElem.setAttribute( QStringLiteral(
"wildCard" ), QStringLiteral(
"%" ) );
2832 boElem.setAttribute( QStringLiteral(
"singleChar" ), QStringLiteral(
"_" ) );
2834 boElem.setAttribute( QStringLiteral(
"escape" ), QStringLiteral(
"\\" ) );
2836 boElem.setAttribute( QStringLiteral(
"escapeChar" ), QStringLiteral(
"\\" ) );
2839 boElem.appendChild( leftElem );
2840 boElem.appendChild( rightElem );
2848 switch ( node->
value().userType() )
2850 case QMetaType::Type::Int:
2851 value = QString::number( node->
value().toInt() );
2853 case QMetaType::Type::LongLong:
2854 value = QString::number( node->
value().toLongLong() );
2856 case QMetaType::Type::Double:
2859 case QMetaType::Type::QString:
2860 value = node->
value().toString();
2864 mErrorMessage = QObject::tr(
"Literal type not supported: %1" ).arg(
static_cast<QMetaType::Type
>( node->
value().userType() ) );
2865 return QDomElement();
2868 QDomElement litElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2869 litElem.appendChild( mDoc.createTextNode( value ) );
2876 QDomElement propElem = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2877 if ( node->
tableName().isEmpty() || mLayerProperties.size() == 1 )
2879 if ( !mFieldNameToXPathMap.isEmpty() )
2881 const auto iterFieldName = mFieldNameToXPathMap.constFind( node->
name() );
2882 if ( iterFieldName != mFieldNameToXPathMap.constEnd() )
2884 const QString xpath( *iterFieldName );
2886 if ( !mNamespacePrefixToUriMap.isEmpty() )
2888 const QStringList parts = xpath.split(
'/' );
2889 QSet<QString> setNamespacePrefix;
2890 for (
const QString &part : std::as_const( parts ) )
2892 const QStringList subparts = part.split(
':' );
2893 if ( subparts.size() == 2 && !setNamespacePrefix.contains( subparts[0] ) )
2895 const auto iterNamespacePrefix = mNamespacePrefixToUriMap.constFind( subparts[0] );
2896 if ( iterNamespacePrefix != mNamespacePrefixToUriMap.constEnd() )
2898 setNamespacePrefix.insert( subparts[0] );
2899 QDomAttr attr = mDoc.createAttribute( QStringLiteral(
"xmlns:" ) + subparts[0] );
2900 attr.setValue( *iterNamespacePrefix );
2901 propElem.setAttributeNode( attr );
2907 propElem.appendChild( mDoc.createTextNode( xpath ) );
2912 if ( mLayerProperties.size() == 1 && !mLayerProperties[0].mNamespacePrefix.isEmpty() && !mLayerProperties[0].mNamespaceURI.isEmpty() )
2913 propElem.appendChild( mDoc.createTextNode(
2914 mLayerProperties[0].mNamespacePrefix + QStringLiteral(
":" ) + node->
name() ) );
2916 propElem.appendChild( mDoc.createTextNode( node->
name() ) );
2920 QString tableName( mMapTableAliasToNames[node->
tableName()] );
2921 if ( mMapUnprefixedTypenameToPrefixedTypename.contains( tableName ) )
2922 tableName = mMapUnprefixedTypenameToPrefixedTypename[tableName];
2923 propElem.appendChild( mDoc.createTextNode( tableName +
"/" + node->
name() ) );
2930 if ( node->
list()->
list().size() == 1 )
2934 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
2935 eqElem.appendChild( leftNode );
2936 eqElem.appendChild( firstListNode );
2939 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2940 notElem.appendChild( eqElem );
2946 QDomElement orElem = mDoc.createElement( mFilterPrefix +
":Or" );
2949 const auto constList = node->
list()->
list();
2950 for ( QgsSQLStatement::Node *n : constList )
2953 if ( !mErrorMessage.isEmpty() )
2954 return QDomElement();
2956 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
2957 eqElem.appendChild( leftNode.cloneNode() );
2958 eqElem.appendChild( listNode );
2960 orElem.appendChild( eqElem );
2965 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2966 notElem.appendChild( orElem );
2975 QDomElement elem = mDoc.createElement( mFilterPrefix +
":PropertyIsBetween" );
2977 QDomElement lowerBoundary = mDoc.createElement( mFilterPrefix +
":LowerBoundary" );
2979 elem.appendChild( lowerBoundary );
2980 QDomElement upperBoundary = mDoc.createElement( mFilterPrefix +
":UpperBoundary" );
2982 elem.appendChild( upperBoundary );
2986 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2987 notElem.appendChild( elem );
2994static QString mapBinarySpatialToOgc(
const QString &name )
2996 QString nameCompare( name );
2997 if ( name.size() > 3 && QStringView {name} .mid( 0, 3 ).toString().compare( QLatin1String(
"ST_" ), Qt::CaseInsensitive ) == 0 )
2998 nameCompare = name.mid( 3 );
2999 QStringList spatialOps;
3000 spatialOps << QStringLiteral(
"BBOX" ) << QStringLiteral(
"Intersects" ) << QStringLiteral(
"Contains" ) << QStringLiteral(
"Crosses" ) << QStringLiteral(
"Equals" )
3001 << QStringLiteral(
"Disjoint" ) << QStringLiteral(
"Overlaps" ) << QStringLiteral(
"Touches" ) << QStringLiteral(
"Within" );
3002 const auto constSpatialOps = spatialOps;
3003 for ( QString op : constSpatialOps )
3005 if ( nameCompare.compare( op, Qt::CaseInsensitive ) == 0 )
3011static QString mapTernarySpatialToOgc(
const QString &name )
3013 QString nameCompare( name );
3014 if ( name.size() > 3 && QStringView {name} .mid( 0, 3 ).compare( QLatin1String(
"ST_" ), Qt::CaseInsensitive ) == 0 )
3015 nameCompare = name.mid( 3 );
3016 if ( nameCompare.compare( QLatin1String(
"DWithin" ), Qt::CaseInsensitive ) == 0 )
3017 return QStringLiteral(
"DWithin" );
3018 if ( nameCompare.compare( QLatin1String(
"Beyond" ), Qt::CaseInsensitive ) == 0 )
3019 return QStringLiteral(
"Beyond" );
3023QString QgsOgcUtilsSQLStatementToFilter::getGeometryColumnSRSName(
const QgsSQLStatement::Node *node )
3028 const QgsSQLStatement::NodeColumnRef *col =
static_cast<const QgsSQLStatement::NodeColumnRef *
>( node );
3031 const auto constMLayerProperties = mLayerProperties;
3032 for (
const QgsOgcUtils::LayerProperties &prop : constMLayerProperties )
3034 if ( prop.mName.compare( mMapTableAliasToNames[col->
tableName()], Qt::CaseInsensitive ) == 0 &&
3035 prop.mGeometryAttribute.compare( col->
name(), Qt::CaseInsensitive ) == 0 )
3037 return prop.mSRSName;
3041 if ( !mLayerProperties.empty() &&
3042 mLayerProperties.at( 0 ).mGeometryAttribute.compare( col->
name(), Qt::CaseInsensitive ) == 0 )
3044 return mLayerProperties.at( 0 ).mSRSName;
3050 QList<QgsSQLStatement::Node *> args,
3051 bool lastArgIsSRSName,
3053 bool &axisInversion )
3055 srsName = mCurrentSRSName;
3056 axisInversion = mInvertAxisOrientation;
3058 if ( lastArgIsSRSName )
3060 QgsSQLStatement::Node *lastArg = args[ args.size() - 1 ];
3063 mErrorMessage = QObject::tr(
"%1: Last argument must be string or integer literal" ).arg( mainNode->
name() );
3066 const QgsSQLStatement::NodeLiteral *lit =
static_cast<const QgsSQLStatement::NodeLiteral *
>( lastArg );
3067 if ( lit->
value().userType() == QMetaType::Type::Int )
3071 srsName =
"EPSG:" + QString::number( lit->
value().toInt() );
3075 srsName =
"urn:ogc:def:crs:EPSG::" + QString::number( lit->
value().toInt() );
3080 srsName = lit->
value().toString();
3081 if ( srsName.startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
3086 QgsCoordinateReferenceSystem crs;
3087 if ( !srsName.isEmpty() )
3093 axisInversion = !axisInversion;
3103 if ( node->
name().compare( QLatin1String(
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 )
3105 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3106 if ( args.size() != 1 && args.size() != 2 )
3108 mErrorMessage = QObject::tr(
"Function %1 should have 1 or 2 arguments" ).arg( node->
name() );
3109 return QDomElement();
3112 QgsSQLStatement::Node *firstFnArg = args[0];
3115 mErrorMessage = QObject::tr(
"%1: First argument must be string literal" ).arg( node->
name() );
3116 return QDomElement();
3121 if ( ! processSRSName( node, args, args.size() == 2, srsName, axisInversion ) )
3123 return QDomElement();
3126 const QString wkt =
static_cast<const QgsSQLStatement::NodeLiteral *
>( firstFnArg )->value().toString();
3129 QStringLiteral(
"qgis_id_geom_%1" ).arg( mGeomId ) );
3131 if ( geomElem.isNull() )
3133 mErrorMessage = QObject::tr(
"%1: invalid WKT" ).arg( node->
name() );
3134 return QDomElement();
3141 if ( node->
name().compare( QLatin1String(
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 )
3143 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3144 if ( args.size() != 4 && args.size() != 5 )
3146 mErrorMessage = QObject::tr(
"Function %1 should have 4 or 5 arguments" ).arg( node->
name() );
3147 return QDomElement();
3152 for (
int i = 0; i < 4; i++ )
3154 QgsSQLStatement::Node *arg = args[i];
3157 mErrorMessage = QObject::tr(
"%1: Argument %2 must be numeric literal" ).arg( node->
name() ).arg( i + 1 );
3158 return QDomElement();
3160 const QgsSQLStatement::NodeLiteral *lit =
static_cast<const QgsSQLStatement::NodeLiteral *
>( arg );
3162 if ( lit->
value().userType() == QMetaType::Type::Int )
3163 val = lit->
value().toInt();
3164 else if ( lit->
value().userType() == QMetaType::Type::LongLong )
3165 val = lit->
value().toLongLong();
3166 else if ( lit->
value().userType() == QMetaType::Type::Double )
3167 val = lit->
value().toDouble();
3170 mErrorMessage = QObject::tr(
"%1 Argument %2 must be numeric literal" ).arg( node->
name() ).arg( i + 1 );
3171 return QDomElement();
3185 if ( ! processSRSName( node, args, args.size() == 5, srsName, axisInversion ) )
3187 return QDomElement();
3194 QgsOgcUtils::rectangleToGMLEnvelope( &rect, mDoc, srsName, axisInversion, 15 );
3198 if ( node->
name().compare( QLatin1String(
"ST_GeomFromGML" ), Qt::CaseInsensitive ) == 0 )
3200 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3201 if ( args.size() != 1 )
3203 mErrorMessage = QObject::tr(
"Function %1 should have 1 argument" ).arg( node->
name() );
3204 return QDomElement();
3207 QgsSQLStatement::Node *firstFnArg = args[0];
3210 mErrorMessage = QObject::tr(
"%1: Argument must be string literal" ).arg( node->
name() );
3211 return QDomElement();
3214 QDomDocument geomDoc;
3215 const QString gml =
static_cast<const QgsSQLStatement::NodeLiteral *
>( firstFnArg )->value().toString();
3217 const QString xml = QStringLiteral(
"<tmp xmlns:gml=\"%1\">%2</tmp>" ).arg(
GML_NAMESPACE, gml );
3218 if ( !geomDoc.setContent( xml,
true ) )
3220 mErrorMessage = QObject::tr(
"ST_GeomFromGML: unable to parse XML" );
3221 return QDomElement();
3224 const QDomNode geomNode = mDoc.importNode( geomDoc.documentElement().firstChildElement(),
true );
3226 return geomNode.toElement();
3230 QString ogcName( mapBinarySpatialToOgc( node->
name() ) );
3231 if ( !ogcName.isEmpty() )
3233 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3234 if ( args.size() != 2 )
3236 mErrorMessage = QObject::tr(
"Function %1 should have 2 arguments" ).arg( node->
name() );
3237 return QDomElement();
3240 for (
int i = 0; i < 2; i ++ )
3243 (
static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String(
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 ||
3244 static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String(
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 ) )
3246 mCurrentSRSName = getGeometryColumnSRSName( args[1 - i] );
3253 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":" + ogcName );
3254 const auto constArgs = args;
3255 for ( QgsSQLStatement::Node *n : constArgs )
3258 if ( !mErrorMessage.isEmpty() )
3260 mCurrentSRSName.clear();
3261 return QDomElement();
3264 funcElem.appendChild( childElem );
3267 mCurrentSRSName.clear();
3271 ogcName = mapTernarySpatialToOgc( node->
name() );
3272 if ( !ogcName.isEmpty() )
3274 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3275 if ( args.size() != 3 )
3277 mErrorMessage = QObject::tr(
"Function %1 should have 3 arguments" ).arg( node->
name() );
3278 return QDomElement();
3281 for (
int i = 0; i < 2; i ++ )
3284 (
static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String(
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 ||
3285 static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String(
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 ) )
3287 mCurrentSRSName = getGeometryColumnSRSName( args[1 - i] );
3292 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":" + node->
name().mid( 3 ) );
3293 for (
int i = 0; i < 2; i++ )
3295 const QDomElement childElem =
toOgcFilter( args[i] );
3296 if ( !mErrorMessage.isEmpty() )
3298 mCurrentSRSName.clear();
3299 return QDomElement();
3302 funcElem.appendChild( childElem );
3304 mCurrentSRSName.clear();
3306 QgsSQLStatement::Node *distanceNode = args[2];
3309 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() );
3310 return QDomElement();
3312 const QgsSQLStatement::NodeLiteral *lit =
static_cast<const QgsSQLStatement::NodeLiteral *
>( distanceNode );
3315 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() );
3316 return QDomElement();
3319 QString unit( QStringLiteral(
"m" ) );
3320 switch ( lit->
value().userType() )
3322 case QMetaType::Type::Int:
3323 distance = QString::number( lit->
value().toInt() );
3325 case QMetaType::Type::LongLong:
3326 distance = QString::number( lit->
value().toLongLong() );
3328 case QMetaType::Type::Double:
3331 case QMetaType::Type::QString:
3333 distance = lit->
value().toString();
3334 for (
int i = 0; i < distance.size(); i++ )
3336 if ( !( ( distance[i] >=
'0' && distance[i] <=
'9' ) || distance[i] ==
'-' || distance[i] ==
'.' || distance[i] ==
'e' || distance[i] ==
'E' ) )
3338 unit = distance.mid( i ).trimmed();
3339 distance = distance.mid( 0, i );
3347 mErrorMessage = QObject::tr(
"Literal type not supported: %1" ).arg(
static_cast<QMetaType::Type
>( lit->
value().userType() ) );
3348 return QDomElement();
3351 QDomElement distanceElem = mDoc.createElement( mFilterPrefix +
":Distance" );
3353 distanceElem.setAttribute( QStringLiteral(
"uom" ), unit );
3355 distanceElem.setAttribute( QStringLiteral(
"unit" ), unit );
3356 distanceElem.appendChild( mDoc.createTextNode( distance ) );
3357 funcElem.appendChild( distanceElem );
3362 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":Function" );
3363 funcElem.setAttribute( QStringLiteral(
"name" ), node->
name() );
3364 const auto constList = node->
args()->
list();
3365 for ( QgsSQLStatement::Node *n : constList )
3368 if ( !mErrorMessage.isEmpty() )
3369 return QDomElement();
3371 funcElem.appendChild( childElem );
3377 const QString &leftTable )
3379 QgsSQLStatement::Node *onExpr = node->
onExpr();
3385 QList<QDomElement> listElem;
3387 for (
const QString &columnName : constUsingColumns )
3389 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
3390 QDomElement propElem1 = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
3391 propElem1.appendChild( mDoc.createTextNode( leftTable +
"/" + columnName ) );
3392 eqElem.appendChild( propElem1 );
3393 QDomElement propElem2 = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
3394 propElem2.appendChild( mDoc.createTextNode( node->
tableDef()->
name() +
"/" + columnName ) );
3395 eqElem.appendChild( propElem2 );
3396 listElem.append( eqElem );
3399 if ( listElem.size() == 1 )
3403 else if ( listElem.size() > 1 )
3405 QDomElement andElem = mDoc.createElement( mFilterPrefix +
":And" );
3406 const auto constListElem = listElem;
3407 for (
const QDomElement &elem : constListElem )
3409 andElem.appendChild( elem );
3414 return QDomElement();
3419 if ( node->
alias().isEmpty() )
3421 mMapTableAliasToNames[ node->
name()] = node->
name();
3425 mMapTableAliasToNames[ node->
alias()] = node->
name();
3431 QList<QDomElement> listElem;
3434 ( node->
tables().size() != 1 || !node->
joins().empty() ) )
3436 mErrorMessage = QObject::tr(
"Joins are only supported with WFS 2.0" );
3437 return QDomElement();
3441 const auto constTables = node->
tables();
3442 for ( QgsSQLStatement::NodeTableDef *table : constTables )
3446 const auto constJoins = node->
joins();
3447 for ( QgsSQLStatement::NodeJoin *join : constJoins )
3449 visit( join->tableDef() );
3453 const QList< QgsSQLStatement::NodeTableDef *> nodeTables = node->
tables();
3454 QString leftTable = nodeTables.at( nodeTables.length() - 1 )->name();
3455 for ( QgsSQLStatement::NodeJoin *join : constJoins )
3457 const QDomElement joinElem =
toOgcFilter( join, leftTable );
3458 if ( !mErrorMessage.isEmpty() )
3459 return QDomElement();
3460 listElem.append( joinElem );
3461 leftTable = join->tableDef()->name();
3465 if ( node->
where() )
3468 if ( !mErrorMessage.isEmpty() )
3469 return QDomElement();
3470 listElem.append( whereElem );
3474 if ( listElem.size() == 1 )
3478 else if ( listElem.size() > 1 )
3480 QDomElement andElem = mDoc.createElement( mFilterPrefix +
":And" );
3481 const auto constListElem = listElem;
3482 for (
const QDomElement &elem : constListElem )
3484 andElem.appendChild( elem );
3489 return QDomElement();
3495 mPropertyName = QStringLiteral(
"PropertyName" );
3496 mPrefix = QStringLiteral(
"ogc" );
3500 mPropertyName = QStringLiteral(
"ValueReference" );
3501 mPrefix = QStringLiteral(
"fes" );
3507 if ( element.isNull() )
3511 if ( isBinaryOperator( element.tagName() ) )
3517 if ( isSpatialOperator( element.tagName() ) )
3523 if ( element.tagName() == QLatin1String(
"Not" ) )
3527 else if ( element.tagName() == QLatin1String(
"PropertyIsNull" ) )
3531 else if ( element.tagName() == QLatin1String(
"Literal" ) )
3535 else if ( element.tagName() == QLatin1String(
"Function" ) )
3539 else if ( element.tagName() == mPropertyName )
3543 else if ( element.tagName() == QLatin1String(
"PropertyIsBetween" ) )
3548 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() );
3554 if ( element.isNull() )
3557 int op = binaryOperatorFromTagName( element.tagName() );
3560 mErrorMessage = QObject::tr(
"'%1' binary operator not supported." ).arg( element.tagName() );
3564 if ( op ==
QgsExpressionNodeBinaryOperator::boLike && element.hasAttribute( QStringLiteral(
"matchCase" ) ) && element.attribute( QStringLiteral(
"matchCase" ) ) == QLatin1String(
"false" ) )
3569 QDomElement operandElem = element.firstChildElement();
3574 mErrorMessage = QObject::tr(
"invalid left operand for '%1' binary operator" ).arg( element.tagName() );
3578 const std::unique_ptr<QgsExpressionNode> leftOp( expr->clone() );
3579 for ( operandElem = operandElem.nextSiblingElement(); !operandElem.isNull(); operandElem = operandElem.nextSiblingElement() )
3584 mErrorMessage = QObject::tr(
"invalid right operand for '%1' binary operator" ).arg( element.tagName() );
3591 if ( element.hasAttribute( QStringLiteral(
"wildCard" ) ) )
3593 wildCard = element.attribute( QStringLiteral(
"wildCard" ) );
3596 if ( element.hasAttribute( QStringLiteral(
"singleChar" ) ) )
3598 singleChar = element.attribute( QStringLiteral(
"singleChar" ) );
3600 QString escape = QStringLiteral(
"\\" );
3601 if ( element.hasAttribute( QStringLiteral(
"escape" ) ) )
3603 escape = element.attribute( QStringLiteral(
"escape" ) );
3605 if ( element.hasAttribute( QStringLiteral(
"escapeChar" ) ) )
3607 escape = element.attribute( QStringLiteral(
"escapeChar" ) );
3611 if ( !wildCard.isEmpty() && wildCard != QLatin1String(
"%" ) )
3613 oprValue.replace(
'%', QLatin1String(
"\\%" ) );
3614 if ( oprValue.startsWith( wildCard ) )
3616 oprValue.replace( 0, 1, QStringLiteral(
"%" ) );
3619 QRegularExpressionMatch match = rx.match( oprValue );
3621 while ( match.hasMatch() )
3623 pos = match.capturedStart();
3624 oprValue.replace( pos + 1, 1, QStringLiteral(
"%" ) );
3626 match = rx.match( oprValue, pos );
3628 oprValue.replace( escape + wildCard, wildCard );
3630 if ( !singleChar.isEmpty() && singleChar != QLatin1String(
"_" ) )
3632 oprValue.replace(
'_', QLatin1String(
"\\_" ) );
3633 if ( oprValue.startsWith( singleChar ) )
3635 oprValue.replace( 0, 1, QStringLiteral(
"_" ) );
3638 QRegularExpressionMatch match = rx.match( oprValue );
3640 while ( match.hasMatch() )
3642 pos = match.capturedStart();
3643 oprValue.replace( pos + 1, 1, QStringLiteral(
"_" ) );
3645 match = rx.match( oprValue, pos );
3647 oprValue.replace( escape + singleChar, singleChar );
3649 if ( !escape.isEmpty() && escape != QLatin1String(
"\\" ) )
3651 oprValue.replace( escape + escape, escape );
3653 opRight = std::make_unique<QgsExpressionNodeLiteral>( oprValue );
3659 if ( expr == leftOp )
3661 mErrorMessage = QObject::tr(
"only one operand for '%1' binary operator" ).arg( element.tagName() );
3674 auto gml2Args = std::make_unique<QgsExpressionNode::NodeList>();
3675 QDomElement childElem = element.firstChildElement();
3677 while ( !childElem.isNull() && gml2Str.isEmpty() )
3679 if ( childElem.tagName() != mPropertyName )
3681 QTextStream gml2Stream( &gml2Str );
3682 childElem.save( gml2Stream, 0 );
3684 childElem = childElem.nextSiblingElement();
3686 if ( !gml2Str.isEmpty() )
3692 mErrorMessage = QObject::tr(
"No OGC Geometry found" );
3696 auto opArgs = std::make_unique<QgsExpressionNode::NodeList>();
3705 if ( element.isNull() || element.tagName() != mPropertyName )
3707 mErrorMessage = QObject::tr(
"%1:PropertyName expected, got %2" ).arg( mPrefix, element.tagName() );
3716 if ( element.isNull() || element.tagName() != QLatin1String(
"Literal" ) )
3718 mErrorMessage = QObject::tr(
"%1:Literal expected, got %2" ).arg( mPrefix, element.tagName() );
3722 std::unique_ptr<QgsExpressionNode> root;
3723 if ( !element.hasChildNodes() )
3725 root = std::make_unique<QgsExpressionNodeLiteral>( QVariant(
"" ) );
3726 return root.release();
3730 QDomNode childNode = element.firstChild();
3731 while ( !childNode.isNull() )
3733 std::unique_ptr<QgsExpressionNode> operand;
3735 if ( childNode.nodeType() == QDomNode::ElementNode )
3738 const QDomElement operandElem = childNode.toElement();
3742 mErrorMessage = QObject::tr(
"'%1' is an invalid or not supported content for %2:Literal" ).arg( operandElem.tagName(), mPrefix );
3749 QVariant value = childNode.nodeValue();
3751 bool converted =
false;
3756 QDomElement propertyNameElement = element.previousSiblingElement( mPropertyName );
3757 if ( propertyNameElement.isNull() || propertyNameElement.tagName() != mPropertyName )
3759 propertyNameElement = element.nextSiblingElement( mPropertyName );
3761 if ( !propertyNameElement.isNull() || propertyNameElement.tagName() == mPropertyName )
3763 const int fieldIndex = mLayer->fields().indexOf( propertyNameElement.firstChild().nodeValue() );
3764 if ( fieldIndex != -1 )
3766 const QgsField field = mLayer->fields().field( propertyNameElement.firstChild().nodeValue() );
3777 const double d = value.toDouble( &ok );
3782 operand = std::make_unique<QgsExpressionNodeLiteral>( value );
3790 root = std::move( operand );
3797 childNode = childNode.nextSibling();
3801 return root.release();
3808 if ( element.tagName() != QLatin1String(
"Not" ) )
3811 const QDomElement operandElem = element.firstChildElement();
3815 mErrorMessage = QObject::tr(
"invalid operand for '%1' unary operator" ).arg( element.tagName() );
3825 if ( element.tagName() != QLatin1String(
"PropertyIsNull" ) )
3830 const QDomElement operandElem = element.firstChildElement();
3841 if ( element.isNull() || element.tagName() != QLatin1String(
"Function" ) )
3843 mErrorMessage = QObject::tr(
"%1:Function expected, got %2" ).arg( mPrefix, element.tagName() );
3851 if ( element.attribute( QStringLiteral(
"name" ) ) != funcDef->
name() )
3854 auto args = std::make_unique<QgsExpressionNode::NodeList>();
3856 QDomElement operandElem = element.firstChildElement();
3857 while ( !operandElem.isNull() )
3864 args->append( op.release() );
3866 operandElem = operandElem.nextSiblingElement();
3878 std::unique_ptr<QgsExpressionNode> operand;
3879 std::unique_ptr<QgsExpressionNode> lowerBound;
3880 std::unique_ptr<QgsExpressionNode> upperBound;
3882 QDomElement operandElem = element.firstChildElement();
3883 while ( !operandElem.isNull() )
3885 if ( operandElem.tagName() == QLatin1String(
"LowerBoundary" ) )
3887 const QDomElement lowerBoundElem = operandElem.firstChildElement();
3890 else if ( operandElem.tagName() == QLatin1String(
"UpperBoundary" ) )
3892 const QDomElement upperBoundElem = operandElem.firstChildElement();
3901 if ( operand && lowerBound && upperBound )
3904 operandElem = operandElem.nextSiblingElement();
3907 if ( !operand || !lowerBound || !upperBound )
3909 mErrorMessage = QObject::tr(
"missing some required sub-elements in %1:PropertyIsBetween" ).arg( mPrefix );
3920 return mErrorMessage;
3925 const thread_local QRegularExpression re_url( QRegularExpression::anchoredPattern( QStringLiteral(
"http://www\\.opengis\\.net/gml/srs/epsg\\.xml#(.+)" ) ), QRegularExpression::CaseInsensitiveOption );
3926 if (
const QRegularExpressionMatch match = re_url.match( crsName ); match.hasMatch() )
3928 authority = QStringLiteral(
"EPSG" );
3929 code = match.captured( 1 );
3933 const thread_local QRegularExpression re_ogc_urn( QRegularExpression::anchoredPattern( QStringLiteral(
"urn:ogc:def:crs:([^:]+).+(?<=:)([^:]+)" ) ), QRegularExpression::CaseInsensitiveOption );
3934 if (
const QRegularExpressionMatch match = re_ogc_urn.match( crsName ); match.hasMatch() )
3936 authority = match.captured( 1 );
3937 code = match.captured( 2 );
3941 const thread_local QRegularExpression re_x_ogc_urn( QRegularExpression::anchoredPattern( QStringLiteral(
"urn:x-ogc:def:crs:([^:]+).+(?<=:)([^:]+)" ) ), QRegularExpression::CaseInsensitiveOption );
3942 if (
const QRegularExpressionMatch match = re_x_ogc_urn.match( crsName ); match.hasMatch() )
3944 authority = match.captured( 1 );
3945 code = match.captured( 2 );
3949 const thread_local QRegularExpression re_http_uri( QRegularExpression::anchoredPattern( QStringLiteral(
"http://www\\.opengis\\.net/def/crs/([^/]+).+/([^/]+)" ) ), QRegularExpression::CaseInsensitiveOption );
3950 if (
const QRegularExpressionMatch match = re_http_uri.match( crsName ); match.hasMatch() )
3952 authority = match.captured( 1 );
3953 code = match.captured( 2 );
3957 const thread_local QRegularExpression re_auth_code( QRegularExpression::anchoredPattern( QStringLiteral(
"([^:]+):(.+)" ) ), QRegularExpression::CaseInsensitiveOption );
3958 if (
const QRegularExpressionMatch match = re_auth_code.match( crsName ); match.hasMatch() )
3960 authority = match.captured( 1 );
3961 code = match.captured( 2 );
3968QgsGeometry QgsOgcUtils::geometryFromGMLUsingGdal(
const QDomElement &geometryElement )
3971 QTextStream gmlStream( &gml );
3972 geometryElement.save( gmlStream, 0 );
3977QgsGeometry QgsOgcUtils::geometryFromGMLMultiCurve(
const QDomElement &geometryElement )
3979 return geometryFromGMLUsingGdal( geometryElement );
GeometryOperationResult
Success or failure of a geometry operation.
@ Success
Operation succeeded.
WkbType
The WKB type describes the number of dimensions a geometry has.
@ LineString25D
LineString25D.
@ MultiPointZ
MultiPointZ.
@ MultiPolygon25D
MultiPolygon25D.
@ MultiLineString25D
MultiLineString25D.
@ MultiPolygon
MultiPolygon.
@ MultiLineString
MultiLineString.
@ MultiPoint25D
MultiPoint25D.
@ MultiLineStringZ
MultiLineStringZ.
@ MultiPolygonZ
MultiPolygonZ.
@ LineStringZ
LineStringZ.
virtual void swapXy()=0
Swaps the x and y coordinates from the geometry.
Qgis::WkbType readHeader() const
readHeader
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 the axis order is inverted for the CRS compared to the order east/north (longitude/la...
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...
An 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.
QgsExpressionNode * opLeft() const
Returns the node to the left of the operator.
QgsExpressionNode * opRight() const
Returns the node to the right of the operator.
QgsExpressionNodeBinaryOperator::BinaryOperator op() const
Returns the binary operator.
QString text() const
Returns a the name of this operator without the operands.
BinaryOperator
list of binary operators
An expression node which takes its 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.
QSet< QString > referencedVariables() const override
Returns a set of all variables which are used in this expression.
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.
bool hasCachedStaticValue() const
Returns true if the node can be replaced by a static cached value.
virtual QgsExpressionNode::NodeType nodeType() const =0
Gets the type of this node.
QVariant cachedStaticValue() const
Returns the node's static cached value.
Handles 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.
A geometry is the spatial representation of a feature.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
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 Q_INVOKABLE 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.
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.).
QgsCoordinateReferenceSystem crs
@ HTTP_EPSG_DOT_XML
E.g. http://www.opengis.net/gml/srs/epsg.xml#4326 (called "OGC HTTP URL" in GeoServer WFS configurati...
@ OGC_HTTP_URI
E.g. http://www.opengis.net/def/crs/EPSG/0/4326.
@ X_OGC_URN
E.g. urn:x-ogc:def:crs:EPSG::4326.
@ UNKNOWN
Unknown/unhandled flavor.
@ OGC_URN
E.g. urn:ogc:def:crs:EPSG::4326.
@ AUTH_CODE
E.g EPSG:4326.
static CRSFlavor parseCrsName(const QString &crsName, QString &authority, QString &code)
Parse a CRS name in one of the flavors of OGC services, and decompose it as authority and code.
Internal use by QgsOgcUtils.
QgsOgcUtilsExprToFilter(QDomDocument &doc, QgsOgcUtils::GMLVersion gmlVersion, QgsOgcUtils::FilterVersion filterVersion, const QString &namespacePrefix, const QString &namespaceURI, const QString &geometryName, const QString &srsName, bool honourAxisOrientation, bool invertAxisOrientation, const QMap< QString, QString > &fieldNameToXPathMap, const QMap< QString, QString > &namespacePrefixToUriMap)
Constructor.
bool GMLNamespaceUsed() const
Returns whether the gml: namespace is used.
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 boundaries 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, const QMap< QString, QString > &fieldNameToXPathMap, const QMap< QString, QString > &namespacePrefixToUriMap)
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.
Provides various utility functions for conversion between OGC (Open Geospatial Consortium) standards ...
static QDomElement elseFilterExpression(QDomDocument &doc)
Creates an ElseFilter from doc.
static QgsRectangle rectangleFromGMLBox(const QDomNode &boxNode)
Read rectangle from GML2 Box.
static QDomElement expressionToOgcExpression(const QgsExpression &exp, QDomDocument &doc, QString *errorMessage=nullptr, bool requiresFilterElement=false)
Creates an OGC expression XML element from the exp expression with default values for the geometry na...
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, const QMap< QString, QString > &fieldNameToXPathMap=QMap< QString, QString >(), const QMap< QString, QString > &namespacePrefixToUriMap=QMap< QString, QString >())
Creates OGC filter XML element from the WHERE and JOIN clauses of a SQL statement.
static QDomElement rectangleToGMLEnvelope(const QgsRectangle *env, QDomDocument &doc, int precision=17)
Exports the rectangle to GML3 Envelope.
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 QgsExpression * expressionFromOgcFilter(const QDomElement &element, QgsVectorLayer *layer=nullptr)
Parse XML with OGC filter into QGIS expression.
static QDomElement rectangleToGMLBox(const QgsRectangle *box, QDomDocument &doc, int precision=17)
Exports the rectangle to GML2 Box.
static QgsGeometry ogrGeometryToQgsGeometry(OGRGeometryH geom)
Converts an OGR geometry representation to a QgsGeometry object.
A rectangle specified with double values.
void setYMinimum(double y)
Set the minimum y value.
void setXMinimum(double x)
Set the minimum x value.
void setYMaximum(double y)
Set the maximum y value.
void setXMaximum(double x)
Set the maximum x value.
void normalize()
Normalize the rectangle so it has non-negative width/height.
An 'X BETWEEN y and z' operator.
QgsSQLStatement::Node * node() const
Variable at the left of BETWEEN.
QgsSQLStatement::Node * minVal() const
Minimum bound.
bool isNotBetween() const
Whether this is a NOT BETWEEN operator.
QgsSQLStatement::Node * maxVal() const
Maximum bound.
Binary logical/arithmetical operator (AND, OR, =, +, ...).
QgsSQLStatement::Node * opLeft() const
Left operand.
QgsSQLStatement::BinaryOperator op() const
Operator.
QgsSQLStatement::Node * opRight() const
Right operand.
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.
An 'x IN (y, z)' operator.
bool isNotIn() const
Whether this is a NOT IN operator.
QgsSQLStatement::Node * node() const
Variable at the left of IN.
QgsSQLStatement::NodeList * list() const
Values list.
QgsSQLStatement::NodeTableDef * tableDef() const
Table definition.
QgsSQLStatement::Node * onExpr() const
On expression. Will be nullptr if usingColumns() is not empty.
QList< QString > usingColumns() const
Columns referenced by USING.
QList< QgsSQLStatement::Node * > list()
Returns list.
Literal value (integer, integer64, double, string).
QVariant value() const
The value of the literal.
QList< QgsSQLStatement::NodeJoin * > joins() const
Returns the list of joins.
QgsSQLStatement::Node * where() const
Returns the where clause.
QList< QgsSQLStatement::NodeTableDef * > tables() const
Returns the list of tables.
QString name() const
Table name.
QString alias() const
Table alias.
Unary logical/arithmetical operator ( NOT, - ).
QgsSQLStatement::UnaryOperator op() const
Operator.
QgsSQLStatement::Node * operand() const
Operand.
Abstract node class for SQL statement nodes.
virtual QgsSQLStatement::NodeType nodeType() const =0
Abstract virtual that returns the type of this node.
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.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based dataset.
Custom exception class for Wkb related exceptions.
std::unique_ptr< std::remove_pointer< OGRGeometryH >::type, OGRGeometryDeleter > ogr_geometry_unique_ptr
Scoped OGR geometry.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
QMap< QString, QString > QgsStringMap
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
QVector< QgsPolyline > QgsMultiPolyline
Multi polyline represented as a vector of polylines.
QgsPointSequence QgsPolyline
Polyline as represented as a vector of points.
#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
The Context struct stores the current layer and coordinate transform context.
const QgsMapLayer * layer
QgsCoordinateTransformContext transformContext