34#include <QRegularExpression>
37#include <netinet/in.h>
43#define GML_NAMESPACE QStringLiteral( "http://www.opengis.net/gml" )
44#define GML32_NAMESPACE QStringLiteral( "http://www.opengis.net/gml/3.2" )
45#define OGC_NAMESPACE QStringLiteral( "http://www.opengis.net/ogc" )
46#define FES_NAMESPACE QStringLiteral( "http://www.opengis.net/fes/2.0" )
47#define SE_NAMESPACE QStringLiteral( "http://www.opengis.net/se" )
52 const QString &namespacePrefix,
53 const QString &namespaceURI,
56 bool honourAxisOrientation,
57 bool invertAxisOrientation,
58 const QMap<QString, QString> &fieldNameToXPathMap,
59 const QMap<QString, QString> &namespacePrefixToUriMap )
62 , mGMLVersion( gmlVersion )
63 , mFilterVersion( filterVersion )
64 , mNamespacePrefix( namespacePrefix )
65 , mNamespaceURI( namespaceURI )
68 , mInvertAxisOrientation( invertAxisOrientation )
69 , mFieldNameToXPathMap( fieldNameToXPathMap )
70 , mNamespacePrefixToUriMap( namespacePrefixToUriMap )
71 , mFilterPrefix( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"fes" :
"ogc" )
72 , mPropertyName( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"ValueReference" :
"PropertyName" )
76 if ( !mSrsName.isEmpty() )
82 mInvertAxisOrientation = !mInvertAxisOrientation;
89 QDomElement geometryTypeElement = geometryNode.toElement();
90 QString geomType = geometryTypeElement.tagName();
93 if ( !( geomType == QLatin1String(
"Point" ) || geomType == QLatin1String(
"LineString" ) || geomType == QLatin1String(
"Polygon" ) ||
94 geomType == QLatin1String(
"MultiPoint" ) || geomType == QLatin1String(
"MultiLineString" ) || geomType == QLatin1String(
"MultiPolygon" ) ||
95 geomType == QLatin1String(
"Box" ) || geomType == QLatin1String(
"Envelope" ) ) )
97 const QDomNode geometryChild = geometryNode.firstChild();
98 if ( geometryChild.isNull() )
102 geometryTypeElement = geometryChild.toElement();
103 geomType = geometryTypeElement.tagName();
106 if ( !( geomType == QLatin1String(
"Point" ) || geomType == QLatin1String(
"LineString" ) || geomType == QLatin1String(
"Polygon" ) ||
107 geomType == QLatin1String(
"MultiPoint" ) || geomType == QLatin1String(
"MultiLineString" ) || geomType == QLatin1String(
"MultiPolygon" ) ||
108 geomType == QLatin1String(
"Box" ) || geomType == QLatin1String(
"Envelope" ) ) )
111 if ( geomType == QLatin1String(
"Point" ) )
113 geometry = geometryFromGMLPoint( geometryTypeElement );
115 else if ( geomType == QLatin1String(
"LineString" ) )
117 geometry = geometryFromGMLLineString( geometryTypeElement );
119 else if ( geomType == QLatin1String(
"Polygon" ) )
121 geometry = geometryFromGMLPolygon( geometryTypeElement );
123 else if ( geomType == QLatin1String(
"MultiPoint" ) )
125 geometry = geometryFromGMLMultiPoint( geometryTypeElement );
127 else if ( geomType == QLatin1String(
"MultiLineString" ) )
129 geometry = geometryFromGMLMultiLineString( geometryTypeElement );
131 else if ( geomType == QLatin1String(
"MultiPolygon" ) )
133 geometry = geometryFromGMLMultiPolygon( geometryTypeElement );
135 else if ( geomType == QLatin1String(
"Box" ) )
139 else if ( geomType == QLatin1String(
"Envelope" ) )
153 if ( geometryTypeElement.hasAttribute( QStringLiteral(
"srsName" ) ) )
155 QString
srsName { geometryTypeElement.attribute( QStringLiteral(
"srsName" ) ) };
158 const bool ignoreAxisOrientation {
srsName.startsWith( QLatin1String(
"http://www.opengis.net/gml/srs/" ) ) ||
srsName.startsWith( QLatin1String(
"EPSG:" ) ) };
162 if (
srsName.startsWith( QLatin1String(
"http://www.opengis.net/gml/srs/" ) ) )
164 const auto parts {
srsName.split( QRegularExpression( QStringLiteral( R
"raw(/|#|\.)raw" ) ) ) };
165 if ( parts.length() == 10 )
167 srsName = QStringLiteral(
"http://www.opengis.net/def/crs/%1/0/%2" ).arg( parts[ 7 ].toUpper(), parts[ 9 ] );
200 const QString xml = QStringLiteral(
"<tmp xmlns=\"%1\" xmlns:gml=\"%1\">%2</tmp>" ).arg(
GML_NAMESPACE, xmlString );
202 if ( !doc.setContent( xml,
true ) )
205 return geometryFromGML( doc.documentElement().firstChildElement(), context );
209QgsGeometry QgsOgcUtils::geometryFromGMLPoint(
const QDomElement &geometryElement )
213 const QDomNodeList coordList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
214 if ( !coordList.isEmpty() )
216 const QDomElement coordElement = coordList.at( 0 ).toElement();
217 if ( readGMLCoordinates( pointCoordinate, coordElement ) != 0 )
224 const QDomNodeList posList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"pos" ) );
225 if ( posList.size() < 1 )
229 const QDomElement posElement = posList.at( 0 ).toElement();
230 if ( readGMLPositions( pointCoordinate, posElement ) != 0 )
236 if ( pointCoordinate.empty() )
241 QgsPolylineXY::const_iterator point_it = pointCoordinate.constBegin();
242 char e = htonl( 1 ) != 1;
243 double x = point_it->x();
244 double y = point_it->y();
245 const int size = 1 +
sizeof( int ) + 2 *
sizeof(
double );
248 unsigned char *wkb =
new unsigned char[size];
251 memcpy( &( wkb )[wkbPosition], &e, 1 );
253 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
254 wkbPosition +=
sizeof( int );
255 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
256 wkbPosition +=
sizeof( double );
257 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
264QgsGeometry QgsOgcUtils::geometryFromGMLLineString(
const QDomElement &geometryElement )
268 const QDomNodeList coordList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
269 if ( !coordList.isEmpty() )
271 const QDomElement coordElement = coordList.at( 0 ).toElement();
272 if ( readGMLCoordinates( lineCoordinates, coordElement ) != 0 )
279 const QDomNodeList posList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
280 if ( posList.size() < 1 )
284 const QDomElement posElement = posList.at( 0 ).toElement();
285 if ( readGMLPositions( lineCoordinates, posElement ) != 0 )
291 char e = htonl( 1 ) != 1;
292 const int size = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
295 unsigned char *wkb =
new unsigned char[size];
299 int nPoints = lineCoordinates.size();
302 memcpy( &( wkb )[wkbPosition], &e, 1 );
304 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
305 wkbPosition +=
sizeof( int );
306 memcpy( &( wkb )[wkbPosition], &nPoints,
sizeof(
int ) );
307 wkbPosition +=
sizeof( int );
309 QgsPolylineXY::const_iterator iter;
310 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
314 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
315 wkbPosition +=
sizeof( double );
316 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
317 wkbPosition +=
sizeof( double );
325QgsGeometry QgsOgcUtils::geometryFromGMLPolygon(
const QDomElement &geometryElement )
332 const QDomNodeList outerBoundaryList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"outerBoundaryIs" ) );
333 if ( !outerBoundaryList.isEmpty() )
335 QDomElement coordinatesElement = outerBoundaryList.at( 0 ).firstChild().firstChild().toElement();
336 if ( coordinatesElement.isNull() )
340 if ( readGMLCoordinates( exteriorPointList, coordinatesElement ) != 0 )
344 ringCoordinates.push_back( exteriorPointList );
347 const QDomNodeList innerBoundaryList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"innerBoundaryIs" ) );
348 for (
int i = 0; i < innerBoundaryList.size(); ++i )
351 coordinatesElement = innerBoundaryList.at( i ).firstChild().firstChild().toElement();
352 if ( coordinatesElement.isNull() )
356 if ( readGMLCoordinates( interiorPointList, coordinatesElement ) != 0 )
360 ringCoordinates.push_back( interiorPointList );
366 const QDomNodeList exteriorList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"exterior" ) );
367 if ( exteriorList.size() < 1 )
371 const QDomElement posElement = exteriorList.at( 0 ).firstChild().firstChild().toElement();
372 if ( posElement.isNull() )
376 if ( readGMLPositions( exteriorPointList, posElement ) != 0 )
380 ringCoordinates.push_back( exteriorPointList );
383 const QDomNodeList interiorList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"interior" ) );
384 for (
int i = 0; i < interiorList.size(); ++i )
387 const QDomElement posElement = interiorList.at( i ).firstChild().firstChild().toElement();
388 if ( posElement.isNull() )
393 if ( readGMLPositions( interiorPointList, posElement ) )
397 ringCoordinates.push_back( interiorPointList );
402 int nrings = ringCoordinates.size();
407 for ( QgsMultiPolylineXY::const_iterator it = ringCoordinates.constBegin(); it != ringCoordinates.constEnd(); ++it )
409 npoints += it->size();
411 const int size = 1 + 2 *
sizeof( int ) + nrings *
sizeof(
int ) + 2 * npoints *
sizeof( double );
414 unsigned char *wkb =
new unsigned char[size];
417 char e = htonl( 1 ) != 1;
419 int nPointsInRing = 0;
423 memcpy( &( wkb )[wkbPosition], &e, 1 );
425 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
426 wkbPosition +=
sizeof( int );
427 memcpy( &( wkb )[wkbPosition], &nrings,
sizeof(
int ) );
428 wkbPosition +=
sizeof( int );
429 for ( QgsMultiPolylineXY::const_iterator it = ringCoordinates.constBegin(); it != ringCoordinates.constEnd(); ++it )
431 nPointsInRing = it->size();
432 memcpy( &( wkb )[wkbPosition], &nPointsInRing,
sizeof(
int ) );
433 wkbPosition +=
sizeof( int );
435 QgsPolylineXY::const_iterator iter;
436 for ( iter = it->begin(); iter != it->end(); ++iter )
441 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
442 wkbPosition +=
sizeof( double );
443 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
444 wkbPosition +=
sizeof( double );
453QgsGeometry QgsOgcUtils::geometryFromGMLMultiPoint(
const QDomElement &geometryElement )
457 const QDomNodeList pointMemberList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"pointMember" ) );
458 if ( pointMemberList.size() < 1 )
462 QDomNodeList pointNodeList;
464 QDomNodeList coordinatesList;
465 QDomNodeList posList;
466 for (
int i = 0; i < pointMemberList.size(); ++i )
469 pointNodeList = pointMemberList.at( i ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"Point" ) );
470 if ( pointNodeList.size() < 1 )
475 coordinatesList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
476 if ( !coordinatesList.isEmpty() )
478 currentPoint.clear();
479 if ( readGMLCoordinates( currentPoint, coordinatesList.at( 0 ).toElement() ) != 0 )
483 if ( currentPoint.empty() )
487 pointList.push_back( ( *currentPoint.begin() ) );
493 posList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"pos" ) );
494 if ( posList.size() < 1 )
498 currentPoint.clear();
499 if ( readGMLPositions( currentPoint, posList.at( 0 ).toElement() ) != 0 )
503 if ( currentPoint.empty() )
507 pointList.push_back( ( *currentPoint.begin() ) );
511 int nPoints = pointList.size();
516 const int size = 1 + 2 *
sizeof( int ) + pointList.size() * ( 2 *
sizeof( double ) + 1 +
sizeof(
int ) );
519 unsigned char *wkb =
new unsigned char[size];
522 char e = htonl( 1 ) != 1;
525 memcpy( &( wkb )[wkbPosition], &e, 1 );
527 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
528 wkbPosition +=
sizeof( int );
529 memcpy( &( wkb )[wkbPosition], &nPoints,
sizeof(
int ) );
530 wkbPosition +=
sizeof( int );
532 for ( QgsPolylineXY::const_iterator it = pointList.constBegin(); it != pointList.constEnd(); ++it )
534 memcpy( &( wkb )[wkbPosition], &e, 1 );
536 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
537 wkbPosition +=
sizeof( int );
539 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
540 wkbPosition +=
sizeof( double );
542 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
543 wkbPosition +=
sizeof( double );
551QgsGeometry QgsOgcUtils::geometryFromGMLMultiLineString(
const QDomElement &geometryElement )
562 QList< QgsPolylineXY > lineCoordinates;
563 QDomElement currentLineStringElement;
564 QDomNodeList currentCoordList;
565 QDomNodeList currentPosList;
567 const QDomNodeList lineStringMemberList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"lineStringMember" ) );
568 if ( !lineStringMemberList.isEmpty() )
570 for (
int i = 0; i < lineStringMemberList.size(); ++i )
572 const QDomNodeList lineStringNodeList = lineStringMemberList.at( i ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LineString" ) );
573 if ( lineStringNodeList.size() < 1 )
577 currentLineStringElement = lineStringNodeList.at( 0 ).toElement();
578 currentCoordList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
579 if ( !currentCoordList.isEmpty() )
582 if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 )
586 lineCoordinates.push_back( currentPointList );
590 currentPosList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
591 if ( currentPosList.size() < 1 )
596 if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 )
600 lineCoordinates.push_back( currentPointList );
606 const QDomNodeList lineStringList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LineString" ) );
607 if ( !lineStringList.isEmpty() )
609 for (
int i = 0; i < lineStringList.size(); ++i )
611 currentLineStringElement = lineStringList.at( i ).toElement();
612 currentCoordList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
613 if ( !currentCoordList.isEmpty() )
616 if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 )
620 lineCoordinates.push_back( currentPointList );
625 currentPosList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
626 if ( currentPosList.size() < 1 )
631 if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 )
635 lineCoordinates.push_back( currentPointList );
645 int nLines = lineCoordinates.size();
650 int size = ( lineCoordinates.size() + 1 ) * ( 1 + 2 *
sizeof(
int ) );
651 for ( QList< QgsPolylineXY >::const_iterator it = lineCoordinates.constBegin(); it != lineCoordinates.constEnd(); ++it )
653 size += it->size() * 2 *
sizeof( double );
657 unsigned char *wkb =
new unsigned char[size];
660 char e = htonl( 1 ) != 1;
664 memcpy( &( wkb )[wkbPosition], &e, 1 );
666 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
667 wkbPosition +=
sizeof( int );
668 memcpy( &( wkb )[wkbPosition], &nLines,
sizeof(
int ) );
669 wkbPosition +=
sizeof( int );
671 for ( QList< QgsPolylineXY >::const_iterator it = lineCoordinates.constBegin(); it != lineCoordinates.constEnd(); ++it )
673 memcpy( &( wkb )[wkbPosition], &e, 1 );
675 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
676 wkbPosition +=
sizeof( int );
677 nPoints = it->size();
678 memcpy( &( wkb )[wkbPosition], &nPoints,
sizeof(
int ) );
679 wkbPosition +=
sizeof( int );
680 for ( QgsPolylineXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
685 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
686 wkbPosition +=
sizeof( double );
687 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
688 wkbPosition +=
sizeof( double );
697QgsGeometry QgsOgcUtils::geometryFromGMLMultiPolygon(
const QDomElement &geometryElement )
701 QDomElement currentPolygonMemberElement;
702 QDomNodeList polygonList;
703 QDomElement currentPolygonElement;
705 QDomNodeList outerBoundaryList;
706 QDomElement currentOuterBoundaryElement;
707 const QDomNodeList innerBoundaryList;
708 QDomElement currentInnerBoundaryElement;
710 QDomNodeList exteriorList;
711 QDomElement currentExteriorElement;
712 QDomElement currentInteriorElement;
713 const QDomNodeList interiorList;
715 QDomNodeList linearRingNodeList;
716 QDomElement currentLinearRingElement;
718 QDomNodeList currentCoordinateList;
719 QDomNodeList currentPosList;
721 const QDomNodeList polygonMemberList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"polygonMember" ) );
723 for (
int i = 0; i < polygonMemberList.size(); ++i )
725 currentPolygonList.resize( 0 );
726 currentPolygonMemberElement = polygonMemberList.at( i ).toElement();
727 polygonList = currentPolygonMemberElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"Polygon" ) );
728 if ( polygonList.size() < 1 )
732 currentPolygonElement = polygonList.at( 0 ).toElement();
735 outerBoundaryList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"outerBoundaryIs" ) );
736 if ( !outerBoundaryList.isEmpty() )
738 currentOuterBoundaryElement = outerBoundaryList.at( 0 ).toElement();
741 linearRingNodeList = currentOuterBoundaryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
742 if ( linearRingNodeList.size() < 1 )
746 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
747 currentCoordinateList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
748 if ( currentCoordinateList.size() < 1 )
752 if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 )
756 currentPolygonList.push_back( ringCoordinates );
759 const QDomNodeList innerBoundaryList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"innerBoundaryIs" ) );
760 for (
int j = 0; j < innerBoundaryList.size(); ++j )
763 currentInnerBoundaryElement = innerBoundaryList.at( j ).toElement();
764 linearRingNodeList = currentInnerBoundaryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
765 if ( linearRingNodeList.size() < 1 )
769 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
770 currentCoordinateList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
771 if ( currentCoordinateList.size() < 1 )
775 if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 )
779 currentPolygonList.push_back( ringCoordinates );
785 exteriorList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"exterior" ) );
786 if ( exteriorList.size() < 1 )
791 currentExteriorElement = exteriorList.at( 0 ).toElement();
794 linearRingNodeList = currentExteriorElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
795 if ( linearRingNodeList.size() < 1 )
799 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
800 currentPosList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
801 if ( currentPosList.size() < 1 )
805 if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 )
809 currentPolygonList.push_back( ringPositions );
812 const QDomNodeList interiorList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"interior" ) );
813 for (
int j = 0; j < interiorList.size(); ++j )
816 currentInteriorElement = interiorList.at( j ).toElement();
817 linearRingNodeList = currentInteriorElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
818 if ( linearRingNodeList.size() < 1 )
822 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
823 currentPosList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
824 if ( currentPosList.size() < 1 )
828 if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 )
832 currentPolygonList.push_back( ringPositions );
835 multiPolygonPoints.push_back( currentPolygonList );
838 int nPolygons = multiPolygonPoints.size();
842 int size = 1 + 2 *
sizeof( int );
844 for ( QgsMultiPolygonXY::const_iterator it = multiPolygonPoints.constBegin(); it != multiPolygonPoints.constEnd(); ++it )
846 size += 1 + 2 *
sizeof( int );
847 for ( QgsPolygonXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
849 size +=
sizeof( int ) + 2 * iter->size() *
sizeof( double );
854 unsigned char *wkb =
new unsigned char[size];
856 char e = htonl( 1 ) != 1;
863 memcpy( &( wkb )[wkbPosition], &e, 1 );
865 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
866 wkbPosition +=
sizeof( int );
867 memcpy( &( wkb )[wkbPosition], &nPolygons,
sizeof(
int ) );
868 wkbPosition +=
sizeof( int );
872 for ( QgsMultiPolygonXY::const_iterator it = multiPolygonPoints.constBegin(); it != multiPolygonPoints.constEnd(); ++it )
874 memcpy( &( wkb )[wkbPosition], &e, 1 );
876 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
877 wkbPosition +=
sizeof( int );
879 memcpy( &( wkb )[wkbPosition], &nRings,
sizeof(
int ) );
880 wkbPosition +=
sizeof( int );
881 for ( QgsPolygonXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
883 nPointsInRing = iter->size();
884 memcpy( &( wkb )[wkbPosition], &nPointsInRing,
sizeof(
int ) );
885 wkbPosition +=
sizeof( int );
886 for ( QgsPolylineXY::const_iterator iterator = iter->begin(); iterator != iter->end(); ++iterator )
890 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
891 wkbPosition +=
sizeof( double );
892 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
893 wkbPosition +=
sizeof( double );
903QDomElement QgsOgcUtils::filterElement( QDomDocument &doc, GMLVersion gmlVersion, FilterVersion filterVersion,
bool GMLUsed )
905 QDomElement filterElem =
907 doc.createElementNS(
FES_NAMESPACE, QStringLiteral(
"fes:Filter" ) ) :
908 doc.createElementNS(
OGC_NAMESPACE, QStringLiteral(
"ogc:Filter" ) );
912 QDomAttr attr = doc.createAttribute( QStringLiteral(
"xmlns:gml" ) );
917 filterElem.setAttributeNode( attr );
923bool QgsOgcUtils::readGMLCoordinates(
QgsPolylineXY &coords,
const QDomElement &elem )
925 QString coordSeparator = QStringLiteral(
"," );
926 QString tupleSeparator = QStringLiteral(
" " );
931 if ( elem.hasAttribute( QStringLiteral(
"cs" ) ) )
933 coordSeparator = elem.attribute( QStringLiteral(
"cs" ) );
935 if ( elem.hasAttribute( QStringLiteral(
"ts" ) ) )
937 tupleSeparator = elem.attribute( QStringLiteral(
"ts" ) );
940 const QStringList tupels = elem.text().split( tupleSeparator, Qt::SkipEmptyParts );
941 QStringList tuple_coords;
943 bool conversionSuccess;
945 QStringList::const_iterator it;
946 for ( it = tupels.constBegin(); it != tupels.constEnd(); ++it )
948 tuple_coords = ( *it ).split( coordSeparator, Qt::SkipEmptyParts );
949 if ( tuple_coords.size() < 2 )
953 x = tuple_coords.at( 0 ).toDouble( &conversionSuccess );
954 if ( !conversionSuccess )
958 y = tuple_coords.at( 1 ).toDouble( &conversionSuccess );
959 if ( !conversionSuccess )
972 const QDomElement boxElem = boxNode.toElement();
973 if ( boxElem.tagName() != QLatin1String(
"Box" ) )
976 const QDomElement bElem = boxElem.firstChild().toElement();
977 QString coordSeparator = QStringLiteral(
"," );
978 QString tupleSeparator = QStringLiteral(
" " );
979 if ( bElem.hasAttribute( QStringLiteral(
"cs" ) ) )
981 coordSeparator = bElem.attribute( QStringLiteral(
"cs" ) );
983 if ( bElem.hasAttribute( QStringLiteral(
"ts" ) ) )
985 tupleSeparator = bElem.attribute( QStringLiteral(
"ts" ) );
988 const QString bString = bElem.text();
989 bool ok1, ok2, ok3, ok4;
990 const double xmin = bString.section( tupleSeparator, 0, 0 ).section( coordSeparator, 0, 0 ).toDouble( &ok1 );
991 const double ymin = bString.section( tupleSeparator, 0, 0 ).section( coordSeparator, 1, 1 ).toDouble( &ok2 );
992 const double xmax = bString.section( tupleSeparator, 1, 1 ).section( coordSeparator, 0, 0 ).toDouble( &ok3 );
993 const double ymax = bString.section( tupleSeparator, 1, 1 ).section( coordSeparator, 1, 1 ).toDouble( &ok4 );
995 if ( ok1 && ok2 && ok3 && ok4 )
1004bool QgsOgcUtils::readGMLPositions(
QgsPolylineXY &coords,
const QDomElement &elem )
1008 const QStringList pos = elem.text().split(
' ', Qt::SkipEmptyParts );
1010 bool conversionSuccess;
1011 const int posSize = pos.size();
1013 int srsDimension = 2;
1014 if ( elem.hasAttribute( QStringLiteral(
"srsDimension" ) ) )
1016 srsDimension = elem.attribute( QStringLiteral(
"srsDimension" ) ).toInt( &conversionSuccess );
1017 if ( !conversionSuccess )
1022 else if ( elem.hasAttribute( QStringLiteral(
"dimension" ) ) )
1024 srsDimension = elem.attribute( QStringLiteral(
"dimension" ) ).toInt( &conversionSuccess );
1025 if ( !conversionSuccess )
1031 for (
int i = 0; i < posSize / srsDimension; i++ )
1033 x = pos.at( i * srsDimension ).toDouble( &conversionSuccess );
1034 if ( !conversionSuccess )
1038 y = pos.at( i * srsDimension + 1 ).toDouble( &conversionSuccess );
1039 if ( !conversionSuccess )
1053 const QDomElement envelopeElem = envelopeNode.toElement();
1054 if ( envelopeElem.tagName() != QLatin1String(
"Envelope" ) )
1057 const QDomNodeList lowerCornerList = envelopeElem.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"lowerCorner" ) );
1058 if ( lowerCornerList.size() < 1 )
1061 const QDomNodeList upperCornerList = envelopeElem.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"upperCorner" ) );
1062 if ( upperCornerList.size() < 1 )
1065 bool conversionSuccess;
1066 int srsDimension = 2;
1068 QDomElement elem = lowerCornerList.at( 0 ).toElement();
1069 if ( elem.hasAttribute( QStringLiteral(
"srsDimension" ) ) )
1071 srsDimension = elem.attribute( QStringLiteral(
"srsDimension" ) ).toInt( &conversionSuccess );
1072 if ( !conversionSuccess )
1077 else if ( elem.hasAttribute( QStringLiteral(
"dimension" ) ) )
1079 srsDimension = elem.attribute( QStringLiteral(
"dimension" ) ).toInt( &conversionSuccess );
1080 if ( !conversionSuccess )
1085 QString bString = elem.text();
1087 const double xmin = bString.section(
' ', 0, 0 ).toDouble( &conversionSuccess );
1088 if ( !conversionSuccess )
1090 const double ymin = bString.section(
' ', 1, 1 ).toDouble( &conversionSuccess );
1091 if ( !conversionSuccess )
1094 elem = upperCornerList.at( 0 ).toElement();
1095 if ( elem.hasAttribute( QStringLiteral(
"srsDimension" ) ) )
1097 srsDimension = elem.attribute( QStringLiteral(
"srsDimension" ) ).toInt( &conversionSuccess );
1098 if ( !conversionSuccess )
1103 else if ( elem.hasAttribute( QStringLiteral(
"dimension" ) ) )
1105 srsDimension = elem.attribute( QStringLiteral(
"dimension" ) ).toInt( &conversionSuccess );
1106 if ( !conversionSuccess )
1112 Q_UNUSED( srsDimension )
1114 bString = elem.text();
1115 const double xmax = bString.section(
' ', 0, 0 ).toDouble( &conversionSuccess );
1116 if ( !conversionSuccess )
1118 const double ymax = bString.section(
' ', 1, 1 ).toDouble( &conversionSuccess );
1119 if ( !conversionSuccess )
1135 bool invertAxisOrientation,
1140 return QDomElement();
1143 QDomElement boxElem = doc.createElement( QStringLiteral(
"gml:Box" ) );
1146 boxElem.setAttribute( QStringLiteral(
"srsName" ),
srsName );
1148 QDomElement coordElem = doc.createElement( QStringLiteral(
"gml:coordinates" ) );
1149 coordElem.setAttribute( QStringLiteral(
"cs" ), QStringLiteral(
"," ) );
1150 coordElem.setAttribute( QStringLiteral(
"ts" ), QStringLiteral(
" " ) );
1152 QString coordString;
1161 const QDomText coordText = doc.createTextNode( coordString );
1162 coordElem.appendChild( coordText );
1163 boxElem.appendChild( coordElem );
1175 bool invertAxisOrientation,
1180 return QDomElement();
1183 QDomElement envElem = doc.createElement( QStringLiteral(
"gml:Envelope" ) );
1186 envElem.setAttribute( QStringLiteral(
"srsName" ),
srsName );
1190 QDomElement lowerCornerElem = doc.createElement( QStringLiteral(
"gml:lowerCorner" ) );
1194 const QDomText lowerCornerText = doc.createTextNode( posList );
1195 lowerCornerElem.appendChild( lowerCornerText );
1196 envElem.appendChild( lowerCornerElem );
1198 QDomElement upperCornerElem = doc.createElement( QStringLiteral(
"gml:upperCorner" ) );
1202 const QDomText upperCornerText = doc.createTextNode( posList );
1203 upperCornerElem.appendChild( upperCornerText );
1204 envElem.appendChild( upperCornerElem );
1218 bool invertAxisOrientation,
1219 const QString &gmlIdBase,
1223 return QDomElement();
1226 QString cs = QStringLiteral(
"," );
1228 const QString ts = QStringLiteral(
" " );
1230 QDomElement baseCoordElem;
1232 bool hasZValue =
false;
1234 const QByteArray wkb( geometry.
asWkb() );
1244 return QDomElement();
1255 baseCoordElem = doc.createElement( QStringLiteral(
"gml:pos" ) );
1258 baseCoordElem = doc.createElement( QStringLiteral(
"gml:posList" ) );
1261 baseCoordElem.setAttribute( QStringLiteral(
"srsDimension" ), QStringLiteral(
"2" ) );
1266 baseCoordElem = doc.createElement( QStringLiteral(
"gml:coordinates" ) );
1267 baseCoordElem.setAttribute( QStringLiteral(
"cs" ), cs );
1268 baseCoordElem.setAttribute( QStringLiteral(
"ts" ), ts );
1278 QDomElement pointElem = doc.createElement( QStringLiteral(
"gml:Point" ) );
1279 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1280 pointElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1282 pointElem.setAttribute( QStringLiteral(
"srsName" ),
srsName );
1283 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1287 if ( invertAxisOrientation )
1293 coordElem.appendChild( coordText );
1294 pointElem.appendChild( coordElem );
1303 QDomElement multiPointElem = doc.createElement( QStringLiteral(
"gml:MultiPoint" ) );
1304 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1305 multiPointElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1307 multiPointElem.setAttribute( QStringLiteral(
"srsName" ),
srsName );
1312 for (
int idx = 0; idx < nPoints; ++idx )
1314 QDomElement pointMemberElem = doc.createElement( QStringLiteral(
"gml:pointMember" ) );
1315 QDomElement pointElem = doc.createElement( QStringLiteral(
"gml:Point" ) );
1316 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1317 pointElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase + QStringLiteral(
".%1" ).arg( idx + 1 ) );
1318 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1324 if ( invertAxisOrientation )
1330 coordElem.appendChild( coordText );
1331 pointElem.appendChild( coordElem );
1335 wkbPtr +=
sizeof( double );
1337 pointMemberElem.appendChild( pointElem );
1338 multiPointElem.appendChild( pointMemberElem );
1340 return multiPointElem;
1348 QDomElement lineStringElem = doc.createElement( QStringLiteral(
"gml:LineString" ) );
1349 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1350 lineStringElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1352 lineStringElem.setAttribute( QStringLiteral(
"srsName" ),
srsName );
1358 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1359 QString coordString;
1360 for (
int idx = 0; idx < nPoints; ++idx )
1369 if ( invertAxisOrientation )
1377 wkbPtr +=
sizeof( double );
1380 const QDomText coordText = doc.createTextNode( coordString );
1381 coordElem.appendChild( coordText );
1382 lineStringElem.appendChild( coordElem );
1383 return lineStringElem;
1391 QDomElement multiLineStringElem = doc.createElement( QStringLiteral(
"gml:MultiLineString" ) );
1392 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1393 multiLineStringElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1395 multiLineStringElem.setAttribute( QStringLiteral(
"srsName" ),
srsName );
1400 for (
int jdx = 0; jdx < nLines; jdx++ )
1402 QDomElement lineStringMemberElem = doc.createElement( QStringLiteral(
"gml:lineStringMember" ) );
1403 QDomElement lineStringElem = doc.createElement( QStringLiteral(
"gml:LineString" ) );
1404 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1405 lineStringElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase + QStringLiteral(
".%1" ).arg( jdx + 1 ) );
1412 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1413 QString coordString;
1414 for (
int idx = 0; idx < nPoints; idx++ )
1423 if ( invertAxisOrientation )
1432 wkbPtr +=
sizeof( double );
1435 const QDomText coordText = doc.createTextNode( coordString );
1436 coordElem.appendChild( coordText );
1437 lineStringElem.appendChild( coordElem );
1438 lineStringMemberElem.appendChild( lineStringElem );
1439 multiLineStringElem.appendChild( lineStringMemberElem );
1441 return multiLineStringElem;
1449 QDomElement polygonElem = doc.createElement( QStringLiteral(
"gml:Polygon" ) );
1450 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1451 polygonElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1453 polygonElem.setAttribute( QStringLiteral(
"srsName" ),
srsName );
1459 if ( numRings == 0 )
1460 return QDomElement();
1462 for (
int idx = 0; idx < numRings; idx++ )
1464 QString boundaryName = ( gmlVersion ==
GML_2_1_2 ) ?
"gml:outerBoundaryIs" :
"gml:exterior";
1467 boundaryName = ( gmlVersion ==
GML_2_1_2 ) ?
"gml:innerBoundaryIs" :
"gml:interior";
1469 QDomElement boundaryElem = doc.createElement( boundaryName );
1470 QDomElement ringElem = doc.createElement( QStringLiteral(
"gml:LinearRing" ) );
1475 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1476 QString coordString;
1477 for (
int jdx = 0; jdx < nPoints; jdx++ )
1486 if ( invertAxisOrientation )
1494 wkbPtr +=
sizeof( double );
1497 const QDomText coordText = doc.createTextNode( coordString );
1498 coordElem.appendChild( coordText );
1499 ringElem.appendChild( coordElem );
1500 boundaryElem.appendChild( ringElem );
1501 polygonElem.appendChild( boundaryElem );
1511 QDomElement multiPolygonElem = doc.createElement( QStringLiteral(
"gml:MultiPolygon" ) );
1512 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1513 multiPolygonElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1515 multiPolygonElem.setAttribute( QStringLiteral(
"srsName" ),
srsName );
1518 wkbPtr >> numPolygons;
1520 for (
int kdx = 0; kdx < numPolygons; kdx++ )
1522 QDomElement polygonMemberElem = doc.createElement( QStringLiteral(
"gml:polygonMember" ) );
1523 QDomElement polygonElem = doc.createElement( QStringLiteral(
"gml:Polygon" ) );
1524 if ( gmlVersion ==
GML_3_2_1 && !gmlIdBase.isEmpty() )
1525 polygonElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase + QStringLiteral(
".%1" ).arg( kdx + 1 ) );
1532 for (
int idx = 0; idx < numRings; idx++ )
1534 QString boundaryName = ( gmlVersion ==
GML_2_1_2 ) ?
"gml:outerBoundaryIs" :
"gml:exterior";
1537 boundaryName = ( gmlVersion ==
GML_2_1_2 ) ?
"gml:innerBoundaryIs" :
"gml:interior";
1539 QDomElement boundaryElem = doc.createElement( boundaryName );
1540 QDomElement ringElem = doc.createElement( QStringLiteral(
"gml:LinearRing" ) );
1545 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1546 QString coordString;
1547 for (
int jdx = 0; jdx < nPoints; jdx++ )
1556 if ( invertAxisOrientation )
1565 wkbPtr +=
sizeof( double );
1568 const QDomText coordText = doc.createTextNode( coordString );
1569 coordElem.appendChild( coordText );
1570 ringElem.appendChild( coordElem );
1571 boundaryElem.appendChild( ringElem );
1572 polygonElem.appendChild( boundaryElem );
1573 polygonMemberElem.appendChild( polygonElem );
1574 multiPolygonElem.appendChild( polygonMemberElem );
1577 return multiPolygonElem;
1580 return QDomElement();
1586 return QDomElement();
1595QDomElement QgsOgcUtils::createGMLCoordinates(
const QgsPolylineXY &points, QDomDocument &doc )
1597 QDomElement coordElem = doc.createElement( QStringLiteral(
"gml:coordinates" ) );
1598 coordElem.setAttribute( QStringLiteral(
"cs" ), QStringLiteral(
"," ) );
1599 coordElem.setAttribute( QStringLiteral(
"ts" ), QStringLiteral(
" " ) );
1601 QString coordString;
1602 QVector<QgsPointXY>::const_iterator pointIt = points.constBegin();
1603 for ( ; pointIt != points.constEnd(); ++pointIt )
1605 if ( pointIt != points.constBegin() )
1614 const QDomText coordText = doc.createTextNode( coordString );
1615 coordElem.appendChild( coordText );
1619QDomElement QgsOgcUtils::createGMLPositions(
const QgsPolylineXY &points, QDomDocument &doc )
1621 QDomElement posElem = doc.createElement( QStringLiteral(
"gml:pos" ) );
1622 if ( points.size() > 1 )
1623 posElem = doc.createElement( QStringLiteral(
"gml:posList" ) );
1624 posElem.setAttribute( QStringLiteral(
"srsDimension" ), QStringLiteral(
"2" ) );
1626 QString coordString;
1627 QVector<QgsPointXY>::const_iterator pointIt = points.constBegin();
1628 for ( ; pointIt != points.constEnd(); ++pointIt )
1630 if ( pointIt != points.constBegin() )
1639 const QDomText coordText = doc.createTextNode( coordString );
1640 posElem.appendChild( coordText );
1650 if ( fillElement.isNull() || !fillElement.hasChildNodes() )
1658 QDomElement cssElem = fillElement.firstChildElement( QStringLiteral(
"CssParameter" ) );
1659 while ( !cssElem.isNull() )
1661 cssName = cssElem.attribute( QStringLiteral(
"name" ), QStringLiteral(
"not_found" ) );
1662 if ( cssName != QLatin1String(
"not_found" ) )
1664 elemText = cssElem.text();
1665 if ( cssName == QLatin1String(
"fill" ) )
1667 color.setNamedColor( elemText );
1669 else if ( cssName == QLatin1String(
"fill-opacity" ) )
1672 const double opacity = elemText.toDouble( &ok );
1675 color.setAlphaF( opacity );
1680 cssElem = cssElem.nextSiblingElement( QStringLiteral(
"CssParameter" ) );
1694 if ( element.isNull() || !element.hasChildNodes() )
1701 if ( element.firstChild().nodeType() == QDomNode::TextNode )
1711 QDomElement childElem = element.firstChildElement();
1712 while ( !childElem.isNull() )
1724 if ( !expr->d->mRootNode )
1726 expr->d->mRootNode = node;
1733 childElem = childElem.nextSiblingElement();
1737 expr->d->mExp = expr->
dump();
1763static
int binaryOperatorFromTagName( const QString &tagName )
1766 return BINARY_OPERATORS_TAG_NAMES_MAP()->value( tagName, -1 );
1773 return QStringLiteral(
"PropertyIsLike" );
1775 return BINARY_OPERATORS_TAG_NAMES_MAP()->key( op, QString() );
1778static bool isBinaryOperator(
const QString &tagName )
1780 return binaryOperatorFromTagName( tagName ) >= 0;
1784static bool isSpatialOperator(
const QString &tagName )
1786 static QStringList spatialOps;
1787 if ( spatialOps.isEmpty() )
1789 spatialOps << QStringLiteral(
"BBOX" ) << QStringLiteral(
"Intersects" ) << QStringLiteral(
"Contains" ) << QStringLiteral(
"Crosses" ) << QStringLiteral(
"Equals" )
1790 << QStringLiteral(
"Disjoint" ) << QStringLiteral(
"Overlaps" ) << QStringLiteral(
"Touches" ) << QStringLiteral(
"Within" );
1793 return spatialOps.contains( tagName );
1800 errorMessage = utils.errorMessage();
1808 errorMessage = utils.errorMessage();
1816 errorMessage = utils.errorMessage();
1824 errorMessage = utils.errorMessage();
1832 errorMessage = utils.errorMessage();
1840 errorMessage = utils.errorMessage();
1848 errorMessage = utils.errorMessage();
1852QgsExpressionNode *QgsOgcUtils::nodeIsBetweenFromOgcFilter( QDomElement &element, QString &errorMessage )
1856 errorMessage = utils.errorMessage();
1864 errorMessage = utils.errorMessage();
1875 QStringLiteral(
"geometry" ), QString(),
false,
false, errorMessage );
1881 QStringLiteral(
"geometry" ), QString(),
false,
false, errorMessage, requiresFilterElement );
1886 return doc.createElementNS(
SE_NAMESPACE, QStringLiteral(
"se:ElseFilter" ) );
1894 const QString &namespacePrefix,
1895 const QString &namespaceURI,
1898 bool honourAxisOrientation,
1899 bool invertAxisOrientation,
1900 QString *errorMessage,
1901 const QMap<QString, QString> &fieldNameToXPathMap,
1902 const QMap<QString, QString> &namespacePrefixToUriMap )
1905 return QDomElement();
1911 QgsOgcUtilsExprToFilter utils( doc, gmlVersion, filterVersion, namespacePrefix, namespaceURI,
geometryName,
srsName, honourAxisOrientation, invertAxisOrientation, fieldNameToXPathMap, namespacePrefixToUriMap );
1915 if ( exprRootElem.isNull() )
1916 return QDomElement();
1918 QDomElement filterElem = filterElement( doc, gmlVersion, filterVersion, utils.
GMLNamespaceUsed() );
1920 if ( !namespacePrefix.isEmpty() && !namespaceURI.isEmpty() )
1922 QDomAttr attr = doc.createAttribute( QStringLiteral(
"xmlns:" ) + namespacePrefix );
1923 attr.setValue( namespaceURI );
1924 filterElem.setAttributeNode( attr );
1927 filterElem.appendChild( exprRootElem );
1937 bool honourAxisOrientation,
1938 bool invertAxisOrientation,
1939 QString *errorMessage,
1940 bool requiresFilterElement,
1941 const QMap<QString, QString> &fieldNameToXPathMap,
1942 const QMap<QString, QString> &namespacePrefixToUriMap )
1951 return QDomElement();
1960 QgsOgcUtilsExprToFilter utils( doc, gmlVersion, filterVersion, QString(), QString(),
geometryName,
srsName, honourAxisOrientation, invertAxisOrientation, fieldNameToXPathMap, namespacePrefixToUriMap );
1966 if ( !exprRootElem.isNull() )
1968 if ( requiresFilterElement )
1970 QDomElement filterElem = filterElement( doc, gmlVersion, filterVersion, utils.
GMLNamespaceUsed() );
1972 filterElem.appendChild( exprRootElem );
1975 return exprRootElem;
1982 *errorMessage = QObject::tr(
"Node type not supported in expression translation: %1" ).arg( node->
nodeType() );
1986 return QDomElement();
1993 const QList<LayerProperties> &layerProperties,
1994 bool honourAxisOrientation,
1995 bool invertAxisOrientation,
1996 const QMap< QString, QString> &mapUnprefixedTypenameToPrefixedTypename,
1997 QString *errorMessage,
1998 const QMap<QString, QString> &fieldNameToXPathMap,
1999 const QMap<QString, QString> &namespacePrefixToUriMap )
2002 return QDomElement();
2005 layerProperties, honourAxisOrientation, invertAxisOrientation,
2006 mapUnprefixedTypenameToPrefixedTypename, fieldNameToXPathMap, namespacePrefixToUriMap );
2010 if ( exprRootElem.isNull() )
2011 return QDomElement();
2013 QDomElement filterElem = filterElement( doc, gmlVersion, filterVersion, utils.
GMLNamespaceUsed() );
2015 QSet<QString> setNamespaceURI;
2018 if ( !props.mNamespacePrefix.isEmpty() && !props.mNamespaceURI.isEmpty() &&
2019 !setNamespaceURI.contains( props.mNamespaceURI ) )
2021 setNamespaceURI.insert( props.mNamespaceURI );
2022 QDomAttr attr = doc.createAttribute( QStringLiteral(
"xmlns:" ) + props.mNamespacePrefix );
2023 attr.setValue( props.mNamespaceURI );
2024 filterElem.setAttributeNode( attr );
2027 filterElem.appendChild( exprRootElem );
2052 mErrorMessage = QObject::tr(
"Node type not supported: %1" ).arg( node->
nodeType() );
2053 return QDomElement();
2060 if ( !mErrorMessage.isEmpty() )
2061 return QDomElement();
2064 switch ( node->
op() )
2067 uoElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2072 uoElem.appendChild( mDoc.createTextNode(
"-" + operandElem.text() ) );
2073 mDoc.removeChild( operandElem );
2077 mErrorMessage = QObject::tr(
"This use of unary operator not implemented yet" );
2078 return QDomElement();
2082 uoElem = mDoc.createElement( mFilterPrefix +
":Not" );
2083 uoElem.appendChild( operandElem );
2087 mErrorMessage = QObject::tr(
"Unary operator '%1' not implemented yet" ).arg( node->
text() );
2088 return QDomElement();
2098 if ( !mErrorMessage.isEmpty() )
2099 return QDomElement();
2112 QDomElement elem = mDoc.createElement( mFilterPrefix +
":PropertyIsNull" );
2113 elem.appendChild( leftElem );
2117 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2118 notElem.appendChild( elem );
2132 if ( !mErrorMessage.isEmpty() )
2133 return QDomElement();
2136 const QString opText = binaryOperatorToTagName( op );
2137 if ( opText.isEmpty() )
2141 mErrorMessage = QObject::tr(
"Binary operator %1 not implemented yet" ).arg( node->
text() );
2142 return QDomElement();
2145 QDomElement boElem = mDoc.createElement( mFilterPrefix +
":" + opText );
2150 boElem.setAttribute( QStringLiteral(
"matchCase" ), QStringLiteral(
"false" ) );
2153 boElem.setAttribute( QStringLiteral(
"wildCard" ), QStringLiteral(
"%" ) );
2154 boElem.setAttribute( QStringLiteral(
"singleChar" ), QStringLiteral(
"_" ) );
2156 boElem.setAttribute( QStringLiteral(
"escape" ), QStringLiteral(
"\\" ) );
2158 boElem.setAttribute( QStringLiteral(
"escapeChar" ), QStringLiteral(
"\\" ) );
2161 boElem.appendChild( leftElem );
2162 boElem.appendChild( rightElem );
2169 Q_UNUSED( expression )
2172 switch ( node->
value().userType() )
2174 case QMetaType::Type::Int:
2175 value = QString::number( node->
value().toInt() );
2177 case QMetaType::Type::Double:
2180 case QMetaType::Type::QString:
2181 value = node->
value().toString();
2183 case QMetaType::Type::QDate:
2184 value = node->
value().toDate().toString( Qt::ISODate );
2186 case QMetaType::Type::QDateTime:
2187 value = node->
value().toDateTime().toString( Qt::ISODate );
2191 mErrorMessage = QObject::tr(
"Literal type not supported: %1" ).arg(
static_cast<QMetaType::Type
>( node->
value().userType() ) );
2192 return QDomElement();
2195 QDomElement litElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2196 litElem.appendChild( mDoc.createTextNode( value ) );
2203 Q_UNUSED( expression )
2205 QDomElement propElem = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2206 if ( !mFieldNameToXPathMap.isEmpty() )
2208 const auto iterFieldName = mFieldNameToXPathMap.constFind( node->
name() );
2209 if ( iterFieldName != mFieldNameToXPathMap.constEnd() )
2211 const QString xpath( *iterFieldName );
2213 if ( !mNamespacePrefixToUriMap.isEmpty() )
2215 const QStringList parts = xpath.split(
'/' );
2216 QSet<QString> setNamespacePrefix;
2217 for (
const QString &part : std::as_const( parts ) )
2219 const QStringList subparts = part.split(
':' );
2220 if ( subparts.size() == 2 && !setNamespacePrefix.contains( subparts[0] ) )
2222 const auto iterNamespacePrefix = mNamespacePrefixToUriMap.constFind( subparts[0] );
2223 if ( iterNamespacePrefix != mNamespacePrefixToUriMap.constEnd() )
2225 setNamespacePrefix.insert( subparts[0] );
2226 QDomAttr attr = mDoc.createAttribute( QStringLiteral(
"xmlns:" ) + subparts[0] );
2227 attr.setValue( *iterNamespacePrefix );
2228 propElem.setAttributeNode( attr );
2234 propElem.appendChild( mDoc.createTextNode( xpath ) );
2239 QString columnRef( node->
name() );
2240 if ( !mNamespacePrefix.isEmpty() && !mNamespaceURI.isEmpty() )
2241 columnRef = mNamespacePrefix + QStringLiteral(
":" ) + columnRef;
2242 propElem.appendChild( mDoc.createTextNode( columnRef ) );
2250 if ( node->
list()->
list().size() == 1 )
2254 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
2255 eqElem.appendChild( leftNode );
2256 eqElem.appendChild( firstListNode );
2259 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2260 notElem.appendChild( eqElem );
2266 QDomElement orElem = mDoc.createElement( mFilterPrefix +
":Or" );
2269 const auto constList = node->
list()->
list();
2273 if ( !mErrorMessage.isEmpty() )
2274 return QDomElement();
2276 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
2277 eqElem.appendChild( leftNode.cloneNode() );
2278 eqElem.appendChild( listNode );
2280 orElem.appendChild( eqElem );
2285 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2286 notElem.appendChild( orElem );
2295 { QLatin1String(
"disjoint" ), QLatin1String(
"Disjoint" ) },
2296 { QLatin1String(
"intersects" ), QLatin1String(
"Intersects" )},
2297 { QLatin1String(
"touches" ), QLatin1String(
"Touches" ) },
2298 { QLatin1String(
"crosses" ), QLatin1String(
"Crosses" ) },
2299 { QLatin1String(
"contains" ), QLatin1String(
"Contains" ) },
2300 { QLatin1String(
"overlaps" ), QLatin1String(
"Overlaps" ) },
2301 { QLatin1String(
"within" ), QLatin1String(
"Within" ) }
2304static
bool isBinarySpatialOperator( const QString &fnName )
2306 return BINARY_SPATIAL_OPS_MAP()->contains( fnName );
2309static QString tagNameForSpatialOperator(
const QString &fnName )
2311 return BINARY_SPATIAL_OPS_MAP()->value( fnName );
2321 return fd->
name() == QLatin1String(
"$geometry" ) || ( fd->
name() == QLatin1String(
"var" ) && fn->
referencedVariables().contains( QLatin1String(
"geometry" ) ) );
2333 if ( fnDef->
name() == QLatin1String(
"geom_from_wkt" ) )
2335 const QList<QgsExpressionNode *> &args = fnNode->
args()->
list();
2351 if ( fd->
name() == QLatin1String(
"intersects_bbox" ) )
2353 QList<QgsExpressionNode *> argNodes = node->
args()->
list();
2354 Q_ASSERT( argNodes.count() == 2 );
2356 const QgsGeometry geom = geometryFromConstExpr( argNodes[1] );
2357 if ( !geom.
isNull() && isGeometryColumn( argNodes[0] ) )
2367 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":BBOX" );
2369 if ( !mGeometryName.isEmpty() )
2372 QDomElement geomProperty = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2373 QString columnRef( mGeometryName );
2374 if ( !mNamespacePrefix.isEmpty() && !mNamespaceURI.isEmpty() )
2375 columnRef = mNamespacePrefix + QStringLiteral(
":" ) + columnRef;
2376 geomProperty.appendChild( mDoc.createTextNode( columnRef ) );
2378 funcElem.appendChild( geomProperty );
2380 funcElem.appendChild( elemBox );
2385 mErrorMessage = QObject::tr(
"<BBOX> is currently supported only in form: bbox(@geometry, geomFromWKT('…'))" );
2386 return QDomElement();
2390 if ( isBinarySpatialOperator( fd->
name() ) )
2392 QList<QgsExpressionNode *> argNodes = node->
args()->
list();
2393 Q_ASSERT( argNodes.count() == 2 );
2396 if ( isGeometryColumn( argNodes[0] ) )
2397 otherNode = argNodes[1];
2398 else if ( isGeometryColumn( argNodes[1] ) )
2399 otherNode = argNodes[0];
2402 mErrorMessage = QObject::tr(
"Unable to translate spatial operator: at least one must refer to geometry." );
2403 return QDomElement();
2406 QDomElement otherGeomElem;
2411 mErrorMessage = QObject::tr(
"spatial operator: the other operator must be a geometry constructor function" );
2412 return QDomElement();
2417 if ( otherFnDef->
name() == QLatin1String(
"geom_from_wkt" ) )
2422 mErrorMessage = QObject::tr(
"geom_from_wkt: argument must be string literal" );
2423 return QDomElement();
2428 QStringLiteral(
"qgis_id_geom_%1" ).arg( mGeomId ) );
2429 if ( otherGeomElem.isNull() )
2431 mErrorMessage = QObject::tr(
"geom_from_wkt: unable to generate GML from wkt geometry" );
2432 return QDomElement();
2436 else if ( otherFnDef->
name() == QLatin1String(
"geom_from_gml" ) )
2441 mErrorMessage = QObject::tr(
"geom_from_gml: argument must be string literal" );
2442 return QDomElement();
2445 QDomDocument geomDoc;
2448 const QString xml = QStringLiteral(
"<tmp xmlns:gml=\"%1\">%2</tmp>" ).arg(
GML_NAMESPACE, gml );
2449 if ( !geomDoc.setContent( xml,
true ) )
2451 mErrorMessage = QObject::tr(
"geom_from_gml: unable to parse XML" );
2452 return QDomElement();
2455 const QDomNode geomNode = mDoc.importNode( geomDoc.documentElement().firstChildElement(),
true );
2456 otherGeomElem = geomNode.toElement();
2462 QStringLiteral(
"qgis_id_geom_%1" ).arg( mGeomId ) );
2463 if ( otherGeomElem.
isNull() )
2465 mErrorMessage = QObject::tr(
"geom from static value: unable to generate GML from static variable" );
2466 return QDomElement();
2472 mErrorMessage = QObject::tr(
"spatial operator: unknown geometry constructor function" );
2473 return QDomElement();
2478 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":" + tagNameForSpatialOperator( fd->
name() ) );
2479 QDomElement geomProperty = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2480 QString columnRef( mGeometryName );
2481 if ( !mNamespacePrefix.isEmpty() && !mNamespaceURI.isEmpty() )
2482 columnRef = mNamespacePrefix + QStringLiteral(
":" ) + columnRef;
2483 geomProperty.appendChild( mDoc.createTextNode( columnRef ) );
2484 funcElem.appendChild( geomProperty );
2485 funcElem.appendChild( otherGeomElem );
2489 if ( fd->
isStatic( node, expression, context ) )
2491 const QVariant result = fd->
run( node->
args(), context, expression, node );
2493 return expressionLiteralToOgcFilter( &literal, expression, context );
2498 mErrorMessage = QObject::tr(
"Special columns/constants are not supported." );
2499 return QDomElement();
2503 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":Function" );
2504 funcElem.setAttribute( QStringLiteral(
"name" ), fd->
name() );
2505 const auto constList = node->
args()->
list();
2509 if ( !mErrorMessage.isEmpty() )
2510 return QDomElement();
2512 funcElem.appendChild( childElem );
2523 const QList<QgsOgcUtils::LayerProperties> &layerProperties,
2524 bool honourAxisOrientation,
2525 bool invertAxisOrientation,
2526 const QMap< QString, QString> &mapUnprefixedTypenameToPrefixedTypename,
2527 const QMap<QString, QString> &fieldNameToXPathMap,
2528 const QMap<QString, QString> &namespacePrefixToUriMap )
2531 , mGMLVersion( gmlVersion )
2532 , mFilterVersion( filterVersion )
2533 , mLayerProperties( layerProperties )
2534 , mHonourAxisOrientation( honourAxisOrientation )
2535 , mInvertAxisOrientation( invertAxisOrientation )
2536 , mFilterPrefix( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"fes" :
"ogc" )
2537 , mPropertyName( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"ValueReference" :
"PropertyName" )
2539 , mMapUnprefixedTypenameToPrefixedTypename( mapUnprefixedTypenameToPrefixedTypename )
2540 , mFieldNameToXPathMap( fieldNameToXPathMap )
2541 , mNamespacePrefixToUriMap( namespacePrefixToUriMap )
2567 mErrorMessage = QObject::tr(
"Node type not supported: %1" ).arg( node->
nodeType() );
2568 return QDomElement();
2577 if ( !mErrorMessage.isEmpty() )
2578 return QDomElement();
2581 switch ( node->
op() )
2584 uoElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2589 uoElem.appendChild( mDoc.createTextNode(
"-" + operandElem.text() ) );
2590 mDoc.removeChild( operandElem );
2594 mErrorMessage = QObject::tr(
"This use of unary operator not implemented yet" );
2595 return QDomElement();
2599 uoElem = mDoc.createElement( mFilterPrefix +
":Not" );
2600 uoElem.appendChild( operandElem );
2605 return QDomElement();
2615 if ( !mErrorMessage.isEmpty() )
2616 return QDomElement();
2629 QDomElement elem = mDoc.createElement( mFilterPrefix +
":PropertyIsNull" );
2630 elem.appendChild( leftElem );
2634 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2635 notElem.appendChild( elem );
2649 if ( !mErrorMessage.isEmpty() )
2650 return QDomElement();
2655 opText = QStringLiteral(
"Or" );
2657 opText = QStringLiteral(
"And" );
2659 opText = QStringLiteral(
"PropertyIsEqualTo" );
2661 opText = QStringLiteral(
"PropertyIsNotEqualTo" );
2663 opText = QStringLiteral(
"PropertyIsLessThanOrEqualTo" );
2665 opText = QStringLiteral(
"PropertyIsGreaterThanOrEqualTo" );
2667 opText = QStringLiteral(
"PropertyIsLessThan" );
2669 opText = QStringLiteral(
"PropertyIsGreaterThan" );
2671 opText = QStringLiteral(
"PropertyIsLike" );
2673 opText = QStringLiteral(
"PropertyIsLike" );
2675 if ( opText.isEmpty() )
2679 return QDomElement();
2682 QDomElement boElem = mDoc.createElement( mFilterPrefix +
":" + opText );
2687 boElem.setAttribute( QStringLiteral(
"matchCase" ), QStringLiteral(
"false" ) );
2690 boElem.setAttribute( QStringLiteral(
"wildCard" ), QStringLiteral(
"%" ) );
2691 boElem.setAttribute( QStringLiteral(
"singleChar" ), QStringLiteral(
"_" ) );
2693 boElem.setAttribute( QStringLiteral(
"escape" ), QStringLiteral(
"\\" ) );
2695 boElem.setAttribute( QStringLiteral(
"escapeChar" ), QStringLiteral(
"\\" ) );
2698 boElem.appendChild( leftElem );
2699 boElem.appendChild( rightElem );
2707 switch ( node->
value().userType() )
2709 case QMetaType::Type::Int:
2710 value = QString::number( node->
value().toInt() );
2712 case QMetaType::Type::LongLong:
2713 value = QString::number( node->
value().toLongLong() );
2715 case QMetaType::Type::Double:
2718 case QMetaType::Type::QString:
2719 value = node->
value().toString();
2723 mErrorMessage = QObject::tr(
"Literal type not supported: %1" ).arg(
static_cast<QMetaType::Type
>( node->
value().userType() ) );
2724 return QDomElement();
2727 QDomElement litElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2728 litElem.appendChild( mDoc.createTextNode( value ) );
2735 QDomElement propElem = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2736 if ( node->
tableName().isEmpty() || mLayerProperties.size() == 1 )
2738 if ( !mFieldNameToXPathMap.isEmpty() )
2740 const auto iterFieldName = mFieldNameToXPathMap.constFind( node->
name() );
2741 if ( iterFieldName != mFieldNameToXPathMap.constEnd() )
2743 const QString xpath( *iterFieldName );
2745 if ( !mNamespacePrefixToUriMap.isEmpty() )
2747 const QStringList parts = xpath.split(
'/' );
2748 QSet<QString> setNamespacePrefix;
2749 for (
const QString &part : std::as_const( parts ) )
2751 const QStringList subparts = part.split(
':' );
2752 if ( subparts.size() == 2 && !setNamespacePrefix.contains( subparts[0] ) )
2754 const auto iterNamespacePrefix = mNamespacePrefixToUriMap.constFind( subparts[0] );
2755 if ( iterNamespacePrefix != mNamespacePrefixToUriMap.constEnd() )
2757 setNamespacePrefix.insert( subparts[0] );
2758 QDomAttr attr = mDoc.createAttribute( QStringLiteral(
"xmlns:" ) + subparts[0] );
2759 attr.setValue( *iterNamespacePrefix );
2760 propElem.setAttributeNode( attr );
2766 propElem.appendChild( mDoc.createTextNode( xpath ) );
2771 if ( mLayerProperties.size() == 1 && !mLayerProperties[0].mNamespacePrefix.isEmpty() && !mLayerProperties[0].mNamespaceURI.isEmpty() )
2772 propElem.appendChild( mDoc.createTextNode(
2773 mLayerProperties[0].mNamespacePrefix + QStringLiteral(
":" ) + node->
name() ) );
2775 propElem.appendChild( mDoc.createTextNode( node->
name() ) );
2779 QString tableName( mMapTableAliasToNames[node->
tableName()] );
2780 if ( mMapUnprefixedTypenameToPrefixedTypename.contains( tableName ) )
2781 tableName = mMapUnprefixedTypenameToPrefixedTypename[tableName];
2782 propElem.appendChild( mDoc.createTextNode( tableName +
"/" + node->
name() ) );
2789 if ( node->
list()->
list().size() == 1 )
2793 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
2794 eqElem.appendChild( leftNode );
2795 eqElem.appendChild( firstListNode );
2798 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2799 notElem.appendChild( eqElem );
2805 QDomElement orElem = mDoc.createElement( mFilterPrefix +
":Or" );
2808 const auto constList = node->
list()->
list();
2812 if ( !mErrorMessage.isEmpty() )
2813 return QDomElement();
2815 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
2816 eqElem.appendChild( leftNode.cloneNode() );
2817 eqElem.appendChild( listNode );
2819 orElem.appendChild( eqElem );
2824 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2825 notElem.appendChild( orElem );
2834 QDomElement elem = mDoc.createElement( mFilterPrefix +
":PropertyIsBetween" );
2836 QDomElement lowerBoundary = mDoc.createElement( mFilterPrefix +
":LowerBoundary" );
2838 elem.appendChild( lowerBoundary );
2839 QDomElement upperBoundary = mDoc.createElement( mFilterPrefix +
":UpperBoundary" );
2841 elem.appendChild( upperBoundary );
2845 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2846 notElem.appendChild( elem );
2853static QString mapBinarySpatialToOgc(
const QString &name )
2855 QString nameCompare( name );
2856 if ( name.size() > 3 && QStringView {name} .mid( 0, 3 ).toString().compare( QLatin1String(
"ST_" ), Qt::CaseInsensitive ) == 0 )
2857 nameCompare = name.mid( 3 );
2858 QStringList spatialOps;
2859 spatialOps << QStringLiteral(
"BBOX" ) << QStringLiteral(
"Intersects" ) << QStringLiteral(
"Contains" ) << QStringLiteral(
"Crosses" ) << QStringLiteral(
"Equals" )
2860 << QStringLiteral(
"Disjoint" ) << QStringLiteral(
"Overlaps" ) << QStringLiteral(
"Touches" ) << QStringLiteral(
"Within" );
2861 const auto constSpatialOps = spatialOps;
2862 for ( QString op : constSpatialOps )
2864 if ( nameCompare.compare( op, Qt::CaseInsensitive ) == 0 )
2870static QString mapTernarySpatialToOgc(
const QString &name )
2872 QString nameCompare( name );
2873 if ( name.size() > 3 && QStringView {name} .mid( 0, 3 ).compare( QLatin1String(
"ST_" ), Qt::CaseInsensitive ) == 0 )
2874 nameCompare = name.mid( 3 );
2875 if ( nameCompare.compare( QLatin1String(
"DWithin" ), Qt::CaseInsensitive ) == 0 )
2876 return QStringLiteral(
"DWithin" );
2877 if ( nameCompare.compare( QLatin1String(
"Beyond" ), Qt::CaseInsensitive ) == 0 )
2878 return QStringLiteral(
"Beyond" );
2882QString QgsOgcUtilsSQLStatementToFilter::getGeometryColumnSRSName(
const QgsSQLStatement::Node *node )
2890 const auto constMLayerProperties = mLayerProperties;
2893 if ( prop.mName.compare( mMapTableAliasToNames[col->
tableName()], Qt::CaseInsensitive ) == 0 &&
2894 prop.mGeometryAttribute.compare( col->
name(), Qt::CaseInsensitive ) == 0 )
2896 return prop.mSRSName;
2900 if ( !mLayerProperties.empty() &&
2901 mLayerProperties.at( 0 ).mGeometryAttribute.compare( col->
name(), Qt::CaseInsensitive ) == 0 )
2903 return mLayerProperties.at( 0 ).mSRSName;
2909 QList<QgsSQLStatement::Node *> args,
2910 bool lastArgIsSRSName,
2912 bool &axisInversion )
2915 axisInversion = mInvertAxisOrientation;
2917 if ( lastArgIsSRSName )
2922 mErrorMessage = QObject::tr(
"%1: Last argument must be string or integer literal" ).arg( mainNode->
name() );
2926 if ( lit->
value().userType() == QMetaType::Type::Int )
2930 srsName =
"EPSG:" + QString::number( lit->
value().toInt() );
2934 srsName =
"urn:ogc:def:crs:EPSG::" + QString::number( lit->
value().toInt() );
2940 if (
srsName.startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
2952 axisInversion = !axisInversion;
2962 if ( node->
name().compare( QLatin1String(
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 )
2964 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
2965 if ( args.size() != 1 && args.size() != 2 )
2967 mErrorMessage = QObject::tr(
"Function %1 should have 1 or 2 arguments" ).arg( node->
name() );
2968 return QDomElement();
2974 mErrorMessage = QObject::tr(
"%1: First argument must be string literal" ).arg( node->
name() );
2975 return QDomElement();
2980 if ( ! processSRSName( node, args, args.size() == 2,
srsName, axisInversion ) )
2982 return QDomElement();
2988 QStringLiteral(
"qgis_id_geom_%1" ).arg( mGeomId ) );
2990 if ( geomElem.isNull() )
2992 mErrorMessage = QObject::tr(
"%1: invalid WKT" ).arg( node->
name() );
2993 return QDomElement();
3000 if ( node->
name().compare( QLatin1String(
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 )
3002 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3003 if ( args.size() != 4 && args.size() != 5 )
3005 mErrorMessage = QObject::tr(
"Function %1 should have 4 or 5 arguments" ).arg( node->
name() );
3006 return QDomElement();
3011 for (
int i = 0; i < 4; i++ )
3016 mErrorMessage = QObject::tr(
"%1: Argument %2 must be numeric literal" ).arg( node->
name() ).arg( i + 1 );
3017 return QDomElement();
3021 if ( lit->
value().userType() == QMetaType::Type::Int )
3022 val = lit->
value().toInt();
3023 else if ( lit->
value().userType() == QMetaType::Type::LongLong )
3024 val = lit->
value().toLongLong();
3025 else if ( lit->
value().userType() == QMetaType::Type::Double )
3026 val = lit->
value().toDouble();
3029 mErrorMessage = QObject::tr(
"%1 Argument %2 must be numeric literal" ).arg( node->
name() ).arg( i + 1 );
3030 return QDomElement();
3044 if ( ! processSRSName( node, args, args.size() == 5,
srsName, axisInversion ) )
3046 return QDomElement();
3057 if ( node->
name().compare( QLatin1String(
"ST_GeomFromGML" ), Qt::CaseInsensitive ) == 0 )
3059 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3060 if ( args.size() != 1 )
3062 mErrorMessage = QObject::tr(
"Function %1 should have 1 argument" ).arg( node->
name() );
3063 return QDomElement();
3069 mErrorMessage = QObject::tr(
"%1: Argument must be string literal" ).arg( node->
name() );
3070 return QDomElement();
3073 QDomDocument geomDoc;
3076 const QString xml = QStringLiteral(
"<tmp xmlns:gml=\"%1\">%2</tmp>" ).arg(
GML_NAMESPACE, gml );
3077 if ( !geomDoc.setContent( xml,
true ) )
3079 mErrorMessage = QObject::tr(
"ST_GeomFromGML: unable to parse XML" );
3080 return QDomElement();
3083 const QDomNode geomNode = mDoc.importNode( geomDoc.documentElement().firstChildElement(),
true );
3085 return geomNode.toElement();
3089 QString ogcName( mapBinarySpatialToOgc( node->
name() ) );
3090 if ( !ogcName.isEmpty() )
3092 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3093 if ( args.size() != 2 )
3095 mErrorMessage = QObject::tr(
"Function %1 should have 2 arguments" ).arg( node->
name() );
3096 return QDomElement();
3099 for (
int i = 0; i < 2; i ++ )
3102 (
static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String(
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 ||
3103 static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String(
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 ) )
3105 mCurrentSRSName = getGeometryColumnSRSName( args[1 - i] );
3112 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":" + ogcName );
3113 const auto constArgs = args;
3117 if ( !mErrorMessage.isEmpty() )
3119 mCurrentSRSName.clear();
3120 return QDomElement();
3123 funcElem.appendChild( childElem );
3126 mCurrentSRSName.clear();
3130 ogcName = mapTernarySpatialToOgc( node->
name() );
3131 if ( !ogcName.isEmpty() )
3133 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3134 if ( args.size() != 3 )
3136 mErrorMessage = QObject::tr(
"Function %1 should have 3 arguments" ).arg( node->
name() );
3137 return QDomElement();
3140 for (
int i = 0; i < 2; i ++ )
3143 (
static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String(
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 ||
3144 static_cast<const QgsSQLStatement::NodeFunction *
>( args[i] )->name().compare( QLatin1String(
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 ) )
3146 mCurrentSRSName = getGeometryColumnSRSName( args[1 - i] );
3151 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":" + node->
name().mid( 3 ) );
3152 for (
int i = 0; i < 2; i++ )
3154 const QDomElement childElem =
toOgcFilter( args[i] );
3155 if ( !mErrorMessage.isEmpty() )
3157 mCurrentSRSName.clear();
3158 return QDomElement();
3161 funcElem.appendChild( childElem );
3163 mCurrentSRSName.clear();
3168 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() );
3169 return QDomElement();
3174 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() );
3175 return QDomElement();
3178 QString unit( QStringLiteral(
"m" ) );
3179 switch ( lit->
value().userType() )
3181 case QMetaType::Type::Int:
3182 distance = QString::number( lit->
value().toInt() );
3184 case QMetaType::Type::LongLong:
3185 distance = QString::number( lit->
value().toLongLong() );
3187 case QMetaType::Type::Double:
3190 case QMetaType::Type::QString:
3192 distance = lit->
value().toString();
3193 for (
int i = 0; i < distance.size(); i++ )
3195 if ( !( ( distance[i] >=
'0' && distance[i] <=
'9' ) || distance[i] ==
'-' || distance[i] ==
'.' || distance[i] ==
'e' || distance[i] ==
'E' ) )
3197 unit = distance.mid( i ).trimmed();
3198 distance = distance.mid( 0, i );
3206 mErrorMessage = QObject::tr(
"Literal type not supported: %1" ).arg(
static_cast<QMetaType::Type
>( lit->
value().userType() ) );
3207 return QDomElement();
3210 QDomElement distanceElem = mDoc.createElement( mFilterPrefix +
":Distance" );
3212 distanceElem.setAttribute( QStringLiteral(
"uom" ), unit );
3214 distanceElem.setAttribute( QStringLiteral(
"unit" ), unit );
3215 distanceElem.appendChild( mDoc.createTextNode( distance ) );
3216 funcElem.appendChild( distanceElem );
3221 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":Function" );
3222 funcElem.setAttribute( QStringLiteral(
"name" ), node->
name() );
3223 const auto constList = node->
args()->
list();
3227 if ( !mErrorMessage.isEmpty() )
3228 return QDomElement();
3230 funcElem.appendChild( childElem );
3236 const QString &leftTable )
3244 QList<QDomElement> listElem;
3246 for (
const QString &columnName : constUsingColumns )
3248 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
3249 QDomElement propElem1 = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
3250 propElem1.appendChild( mDoc.createTextNode( leftTable +
"/" + columnName ) );
3251 eqElem.appendChild( propElem1 );
3252 QDomElement propElem2 = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
3253 propElem2.appendChild( mDoc.createTextNode( node->
tableDef()->
name() +
"/" + columnName ) );
3254 eqElem.appendChild( propElem2 );
3255 listElem.append( eqElem );
3258 if ( listElem.size() == 1 )
3262 else if ( listElem.size() > 1 )
3264 QDomElement andElem = mDoc.createElement( mFilterPrefix +
":And" );
3265 const auto constListElem = listElem;
3266 for (
const QDomElement &elem : constListElem )
3268 andElem.appendChild( elem );
3273 return QDomElement();
3278 if ( node->
alias().isEmpty() )
3280 mMapTableAliasToNames[ node->
name()] = node->
name();
3284 mMapTableAliasToNames[ node->
alias()] = node->
name();
3290 QList<QDomElement> listElem;
3293 ( node->
tables().size() != 1 || !node->
joins().empty() ) )
3295 mErrorMessage = QObject::tr(
"Joins are only supported with WFS 2.0" );
3296 return QDomElement();
3300 const auto constTables = node->
tables();
3305 const auto constJoins = node->
joins();
3308 visit( join->tableDef() );
3312 const QList< QgsSQLStatement::NodeTableDef *> nodeTables = node->
tables();
3313 QString leftTable = nodeTables.at( nodeTables.length() - 1 )->name();
3316 const QDomElement joinElem =
toOgcFilter( join, leftTable );
3317 if ( !mErrorMessage.isEmpty() )
3318 return QDomElement();
3319 listElem.append( joinElem );
3320 leftTable = join->tableDef()->name();
3324 if ( node->
where() )
3327 if ( !mErrorMessage.isEmpty() )
3328 return QDomElement();
3329 listElem.append( whereElem );
3333 if ( listElem.size() == 1 )
3337 else if ( listElem.size() > 1 )
3339 QDomElement andElem = mDoc.createElement( mFilterPrefix +
":And" );
3340 const auto constListElem = listElem;
3341 for (
const QDomElement &elem : constListElem )
3343 andElem.appendChild( elem );
3348 return QDomElement();
3354 mPropertyName = QStringLiteral(
"PropertyName" );
3355 mPrefix = QStringLiteral(
"ogc" );
3359 mPropertyName = QStringLiteral(
"ValueReference" );
3360 mPrefix = QStringLiteral(
"fes" );
3366 if ( element.isNull() )
3370 if ( isBinaryOperator( element.tagName() ) )
3376 if ( isSpatialOperator( element.tagName() ) )
3382 if ( element.tagName() == QLatin1String(
"Not" ) )
3386 else if ( element.tagName() == QLatin1String(
"PropertyIsNull" ) )
3390 else if ( element.tagName() == QLatin1String(
"Literal" ) )
3394 else if ( element.tagName() == QLatin1String(
"Function" ) )
3398 else if ( element.tagName() == mPropertyName )
3402 else if ( element.tagName() == QLatin1String(
"PropertyIsBetween" ) )
3407 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() );
3413 if ( element.isNull() )
3416 int op = binaryOperatorFromTagName( element.tagName() );
3419 mErrorMessage = QObject::tr(
"'%1' binary operator not supported." ).arg( element.tagName() );
3423 if ( op ==
QgsExpressionNodeBinaryOperator::boLike && element.hasAttribute( QStringLiteral(
"matchCase" ) ) && element.attribute( QStringLiteral(
"matchCase" ) ) == QLatin1String(
"false" ) )
3428 QDomElement operandElem = element.firstChildElement();
3433 mErrorMessage = QObject::tr(
"invalid left operand for '%1' binary operator" ).arg( element.tagName() );
3437 const std::unique_ptr<QgsExpressionNode> leftOp( expr->clone() );
3438 for ( operandElem = operandElem.nextSiblingElement(); !operandElem.isNull(); operandElem = operandElem.nextSiblingElement() )
3443 mErrorMessage = QObject::tr(
"invalid right operand for '%1' binary operator" ).arg( element.tagName() );
3450 if ( element.hasAttribute( QStringLiteral(
"wildCard" ) ) )
3452 wildCard = element.attribute( QStringLiteral(
"wildCard" ) );
3455 if ( element.hasAttribute( QStringLiteral(
"singleChar" ) ) )
3457 singleChar = element.attribute( QStringLiteral(
"singleChar" ) );
3459 QString escape = QStringLiteral(
"\\" );
3460 if ( element.hasAttribute( QStringLiteral(
"escape" ) ) )
3462 escape = element.attribute( QStringLiteral(
"escape" ) );
3464 if ( element.hasAttribute( QStringLiteral(
"escapeChar" ) ) )
3466 escape = element.attribute( QStringLiteral(
"escapeChar" ) );
3470 if ( !wildCard.isEmpty() && wildCard != QLatin1String(
"%" ) )
3472 oprValue.replace(
'%', QLatin1String(
"\\%" ) );
3473 if ( oprValue.startsWith( wildCard ) )
3475 oprValue.replace( 0, 1, QStringLiteral(
"%" ) );
3478 QRegularExpressionMatch match = rx.match( oprValue );
3480 while ( match.hasMatch() )
3482 pos = match.capturedStart();
3483 oprValue.replace( pos + 1, 1, QStringLiteral(
"%" ) );
3485 match = rx.match( oprValue, pos );
3487 oprValue.replace( escape + wildCard, wildCard );
3489 if ( !singleChar.isEmpty() && singleChar != QLatin1String(
"_" ) )
3491 oprValue.replace(
'_', QLatin1String(
"\\_" ) );
3492 if ( oprValue.startsWith( singleChar ) )
3494 oprValue.replace( 0, 1, QStringLiteral(
"_" ) );
3497 QRegularExpressionMatch match = rx.match( oprValue );
3499 while ( match.hasMatch() )
3501 pos = match.capturedStart();
3502 oprValue.replace( pos + 1, 1, QStringLiteral(
"_" ) );
3504 match = rx.match( oprValue, pos );
3506 oprValue.replace( escape + singleChar, singleChar );
3508 if ( !escape.isEmpty() && escape != QLatin1String(
"\\" ) )
3510 oprValue.replace( escape + escape, escape );
3518 if ( expr == leftOp )
3520 mErrorMessage = QObject::tr(
"only one operand for '%1' binary operator" ).arg( element.tagName() );
3533 auto gml2Args = std::make_unique<QgsExpressionNode::NodeList>();
3534 QDomElement childElem = element.firstChildElement();
3536 while ( !childElem.isNull() && gml2Str.isEmpty() )
3538 if ( childElem.tagName() != mPropertyName )
3540 QTextStream gml2Stream( &gml2Str );
3541 childElem.save( gml2Stream, 0 );
3543 childElem = childElem.nextSiblingElement();
3545 if ( !gml2Str.isEmpty() )
3551 mErrorMessage = QObject::tr(
"No OGC Geometry found" );
3555 auto opArgs = std::make_unique<QgsExpressionNode::NodeList>();
3564 if ( element.isNull() || element.tagName() != mPropertyName )
3566 mErrorMessage = QObject::tr(
"%1:PropertyName expected, got %2" ).arg( mPrefix, element.tagName() );
3575 if ( element.isNull() || element.tagName() != QLatin1String(
"Literal" ) )
3577 mErrorMessage = QObject::tr(
"%1:Literal expected, got %2" ).arg( mPrefix, element.tagName() );
3581 std::unique_ptr<QgsExpressionNode> root;
3582 if ( !element.hasChildNodes() )
3585 return root.release();
3589 QDomNode childNode = element.firstChild();
3590 while ( !childNode.isNull() )
3592 std::unique_ptr<QgsExpressionNode> operand;
3594 if ( childNode.nodeType() == QDomNode::ElementNode )
3597 const QDomElement operandElem = childNode.toElement();
3601 mErrorMessage = QObject::tr(
"'%1' is an invalid or not supported content for %2:Literal" ).arg( operandElem.tagName(), mPrefix );
3608 QVariant value = childNode.nodeValue();
3610 bool converted =
false;
3615 QDomElement propertyNameElement = element.previousSiblingElement( mPropertyName );
3616 if ( propertyNameElement.isNull() || propertyNameElement.tagName() != mPropertyName )
3618 propertyNameElement = element.nextSiblingElement( mPropertyName );
3620 if ( !propertyNameElement.isNull() || propertyNameElement.tagName() == mPropertyName )
3622 const int fieldIndex = mLayer->
fields().
indexOf( propertyNameElement.firstChild().nodeValue() );
3623 if ( fieldIndex != -1 )
3625 const QgsField field = mLayer->
fields().
field( propertyNameElement.firstChild().nodeValue() );
3636 const double d = value.toDouble( &ok );
3649 root = std::move( operand );
3656 childNode = childNode.nextSibling();
3660 return root.release();
3667 if ( element.tagName() != QLatin1String(
"Not" ) )
3670 const QDomElement operandElem = element.firstChildElement();
3674 mErrorMessage = QObject::tr(
"invalid operand for '%1' unary operator" ).arg( element.tagName() );
3684 if ( element.tagName() != QLatin1String(
"PropertyIsNull" ) )
3689 const QDomElement operandElem = element.firstChildElement();
3700 if ( element.isNull() || element.tagName() != QLatin1String(
"Function" ) )
3702 mErrorMessage = QObject::tr(
"%1:Function expected, got %2" ).arg( mPrefix, element.tagName() );
3710 if ( element.attribute( QStringLiteral(
"name" ) ) != funcDef->
name() )
3713 auto args = std::make_unique<QgsExpressionNode::NodeList>();
3715 QDomElement operandElem = element.firstChildElement();
3716 while ( !operandElem.isNull() )
3723 args->append( op.release() );
3725 operandElem = operandElem.nextSiblingElement();
3737 std::unique_ptr<QgsExpressionNode> operand;
3738 std::unique_ptr<QgsExpressionNode> lowerBound;
3739 std::unique_ptr<QgsExpressionNode> upperBound;
3741 QDomElement operandElem = element.firstChildElement();
3742 while ( !operandElem.isNull() )
3744 if ( operandElem.tagName() == QLatin1String(
"LowerBoundary" ) )
3746 const QDomElement lowerBoundElem = operandElem.firstChildElement();
3749 else if ( operandElem.tagName() == QLatin1String(
"UpperBoundary" ) )
3751 const QDomElement upperBoundElem = operandElem.firstChildElement();
3760 if ( operand && lowerBound && upperBound )
3763 operandElem = operandElem.nextSiblingElement();
3766 if ( !operand || !lowerBound || !upperBound )
3768 mErrorMessage = QObject::tr(
"missing some required sub-elements in %1:PropertyIsBetween" ).arg( mPrefix );
3779 return mErrorMessage;
3784 const thread_local QRegularExpression re_url( QRegularExpression::anchoredPattern( QStringLiteral(
"http://www\\.opengis\\.net/gml/srs/epsg\\.xml#(.+)" ) ), QRegularExpression::CaseInsensitiveOption );
3785 if (
const QRegularExpressionMatch match = re_url.match( crsName ); match.hasMatch() )
3787 authority = QStringLiteral(
"EPSG" );
3788 code = match.captured( 1 );
3792 const thread_local QRegularExpression re_ogc_urn( QRegularExpression::anchoredPattern( QStringLiteral(
"urn:ogc:def:crs:([^:]+).+(?<=:)([^:]+)" ) ), QRegularExpression::CaseInsensitiveOption );
3793 if (
const QRegularExpressionMatch match = re_ogc_urn.match( crsName ); match.hasMatch() )
3795 authority = match.captured( 1 );
3796 code = match.captured( 2 );
3800 const thread_local QRegularExpression re_x_ogc_urn( QRegularExpression::anchoredPattern( QStringLiteral(
"urn:x-ogc:def:crs:([^:]+).+(?<=:)([^:]+)" ) ), QRegularExpression::CaseInsensitiveOption );
3801 if (
const QRegularExpressionMatch match = re_x_ogc_urn.match( crsName ); match.hasMatch() )
3803 authority = match.captured( 1 );
3804 code = match.captured( 2 );
3808 const thread_local QRegularExpression re_http_uri( QRegularExpression::anchoredPattern( QStringLiteral(
"http://www\\.opengis\\.net/def/crs/([^/]+).+/([^/]+)" ) ), QRegularExpression::CaseInsensitiveOption );
3809 if (
const QRegularExpressionMatch match = re_http_uri.match( crsName ); match.hasMatch() )
3811 authority = match.captured( 1 );
3812 code = match.captured( 2 );
3816 const thread_local QRegularExpression re_auth_code( QRegularExpression::anchoredPattern( QStringLiteral(
"([^:]+):(.+)" ) ), QRegularExpression::CaseInsensitiveOption );
3817 if (
const QRegularExpressionMatch match = re_auth_code.match( crsName ); match.hasMatch() )
3819 authority = match.captured( 1 );
3820 code = match.captured( 2 );
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.
@ MultiPolygon25D
MultiPolygon25D.
@ MultiLineString25D
MultiLineString25D.
@ MultiPolygon
MultiPolygon.
@ MultiLineString
MultiLineString.
@ MultiPoint25D
MultiPoint25D.
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.
Q_INVOKABLE int indexOf(const QString &fieldName) const
Gets the field index from the field name.
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
A geometry is the spatial representation of a feature.
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.
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.
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< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item.
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
#define QgsDebugMsgLevel(str, level)
Q_GLOBAL_STATIC_WITH_ARGS(IntMap, BINARY_OPERATORS_TAG_NAMES_MAP,({ { QLatin1String("Or"), QgsExpressionNodeBinaryOperator::boOr }, { QLatin1String("And"), QgsExpressionNodeBinaryOperator::boAnd }, { QLatin1String("PropertyIsEqualTo"), QgsExpressionNodeBinaryOperator::boEQ }, { QLatin1String("PropertyIsNotEqualTo"), QgsExpressionNodeBinaryOperator::boNE }, { QLatin1String("PropertyIsLessThanOrEqualTo"), QgsExpressionNodeBinaryOperator::boLE }, { QLatin1String("PropertyIsGreaterThanOrEqualTo"), QgsExpressionNodeBinaryOperator::boGE }, { QLatin1String("PropertyIsLessThan"), QgsExpressionNodeBinaryOperator::boLT }, { QLatin1String("PropertyIsGreaterThan"), QgsExpressionNodeBinaryOperator::boGT }, { QLatin1String("PropertyIsLike"), QgsExpressionNodeBinaryOperator::boLike }, { QLatin1String("Add"), QgsExpressionNodeBinaryOperator::boPlus }, { QLatin1String("Sub"), QgsExpressionNodeBinaryOperator::boMinus }, { QLatin1String("Mul"), QgsExpressionNodeBinaryOperator::boMul }, { QLatin1String("Div"), QgsExpressionNodeBinaryOperator::boDiv }, })) static int binaryOperatorFromTagName(const QString &tagName)
QMap< QString, int > IntMap
const QString & geometryName
const QgsCoordinateReferenceSystem & crs
The Context struct stores the current layer and coordinate transform context.
const QgsMapLayer * layer
QgsCoordinateTransformContext transformContext