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