|
| 1 | +#ifndef QGSWFSDATA_H |
| 2 | +#define QGSWFSDATA_H |
| 3 | + |
| 4 | +#include <QHttp> |
| 5 | +#include <expat.h> |
| 6 | +#include "qgis.h" |
| 7 | +#include "qgsapplication.h" |
| 8 | +#include "qgsdataprovider.h" |
| 9 | +#include "qgsfeature.h" |
| 10 | +#include "qgspoint.h" |
| 11 | +#include <list> |
| 12 | +#include <set> |
| 13 | +#include <stack> |
| 14 | +class QgsRect; |
| 15 | +class QgsSpatialRefSys; |
| 16 | + |
| 17 | + |
| 18 | +/**This class reads data from a WFS server or alternatively from a GML file. It uses the expat XML parser and an event based model to keep performance high. The parsing starts when the first data arrives, it does not wait until the request is finished*/ |
| 19 | +class QgsWFSData: public QObject |
| 20 | +{ |
| 21 | + Q_OBJECT |
| 22 | + public: |
| 23 | + QgsWFSData(const QString& uri, QgsRect* extent, QgsSpatialRefSys* srs, std::list<QgsFeature*>* features, const QString& geometryAttribute, const std::set<QString>& thematicAttributes, QGis::WKBTYPE* wkbType); |
| 24 | + ~QgsWFSData(); |
| 25 | + |
| 26 | + /**Does the Http GET request to the wfs server |
| 27 | + @param query string (to define the requested typename) |
| 28 | + @param extent the extent of the WFS layer |
| 29 | + @param srs the reference system of the layer |
| 30 | + @param features the features of the layer |
| 31 | + @return 0 in case of success*/ |
| 32 | + int getWFSData(); |
| 33 | + |
| 34 | + private slots: |
| 35 | + void setFinished(bool error); |
| 36 | + |
| 37 | + private: |
| 38 | + |
| 39 | + enum parseMode |
| 40 | + { |
| 41 | + boundingBox, |
| 42 | + featureMember, |
| 43 | + attribute, |
| 44 | + geometry, |
| 45 | + coordinate, |
| 46 | + point, |
| 47 | + line, |
| 48 | + polygon, |
| 49 | + multiPoint, |
| 50 | + multiLine, |
| 51 | + multiPolygon |
| 52 | + }; |
| 53 | + |
| 54 | + QgsWFSData(); |
| 55 | + |
| 56 | + /**XML handler methods*/ |
| 57 | + void startElement(const XML_Char* el, const XML_Char** attr); |
| 58 | + void endElement(const XML_Char* el); |
| 59 | + void characters(const XML_Char* chars, int len); |
| 60 | + static void start(void* data, const XML_Char* el, const XML_Char** attr) |
| 61 | + { |
| 62 | + static_cast<QgsWFSData*>(data)->startElement(el, attr); |
| 63 | + } |
| 64 | + static void end(void* data, const XML_Char* el) |
| 65 | + { |
| 66 | + static_cast<QgsWFSData*>(data)->endElement(el); |
| 67 | + } |
| 68 | + static void chars(void* data, const XML_Char* chars, int len) |
| 69 | + { |
| 70 | + static_cast<QgsWFSData*>(data)->characters(chars, len); |
| 71 | + } |
| 72 | + |
| 73 | + //helper routines |
| 74 | + /**Reads attribute srsName="EPSG:..." |
| 75 | + @param epsgNr result |
| 76 | + @param attr attribute strings |
| 77 | + @return 0 in case of success*/ |
| 78 | + int readEpsgFromAttribute(int& epsgNr, const XML_Char** attr) const; |
| 79 | + /**Creates a rectangle from a coordinate string. |
| 80 | + @return 0 in case of success*/ |
| 81 | + int createBBoxFromCoordinateString(QgsRect* bb, const QString& coordString) const; |
| 82 | + /**Creates a set of points from a coordinate string. |
| 83 | + @return 0 in case of success*/ |
| 84 | + int pointsFromCoordinateString(std::list<QgsPoint>& points, const QString& coordString) const; |
| 85 | + int getPointWKB(unsigned char** wkb, int* size, const QgsPoint&) const; |
| 86 | + int getLineWKB(unsigned char** wkb, int* size, const std::list<QgsPoint>& lineCoordinates) const; |
| 87 | + int getRingWKB(unsigned char** wkb, int* size, const std::list<QgsPoint>& ringCoordinates) const; |
| 88 | + /**Creates a multiline from the information in mCurrentWKBFragments and mCurrentWKBFragmentSizes. Assign the result. The multiline is in mCurrentWKB and mCurrentWKBSize. The function deletes the memory in mCurrentWKBFragments. Returns 0 in case of success.*/ |
| 89 | + int createMultiLineFromFragments(); |
| 90 | + int createMultiPointFromFragments(); |
| 91 | + int createPolygonFromFragments(); |
| 92 | + int createMultiPolygonFromFragments(); |
| 93 | + /**Adds all the integers contained in mCurrentWKBFragmentSizes*/ |
| 94 | + int totalWKBFragmentSize() const; |
| 95 | + |
| 96 | + QString mUri; |
| 97 | + //results are members such that handler routines are able to manipulate them |
| 98 | + /**Bounding box of the layer*/ |
| 99 | + QgsRect* mExtent; |
| 100 | + /**Source srs of the layer*/ |
| 101 | + QgsSpatialRefSys* mSrs; |
| 102 | + /**The features of the layer*/ |
| 103 | + std::list<QgsFeature*>* mFeatures; |
| 104 | + /**Name of geometry attribute*/ |
| 105 | + QString mGeometryAttribute; |
| 106 | + std::set<QString> mThematicAttributes; |
| 107 | + QGis::WKBTYPE* mWkbType; |
| 108 | + /**True if the request is finished*/ |
| 109 | + bool mFinished; |
| 110 | + /**The HTTP client object*/ |
| 111 | + QHttp mHttp; |
| 112 | + /**Keep track about the most important nested elements*/ |
| 113 | + std::stack<parseMode> mParseModeStack; |
| 114 | + /**This contains the character data if an important element has been encountered*/ |
| 115 | + QString mStringCash; |
| 116 | + QgsFeature* mCurrentFeature; |
| 117 | + int mFeatureCount; |
| 118 | + /**The total WKB for a feature*/ |
| 119 | + unsigned char* mCurrentWKB; |
| 120 | + /**The total WKB size for a feature*/ |
| 121 | + int mCurrentWKBSize; |
| 122 | + /**WKB intermediate storage during parsing. For points and lines, no intermediate WKB is stored at all. For multipoins and multilines and polygons, only one nested list is used. For multipolygons, both nested lists are used*/ |
| 123 | + std::list< std::list<unsigned char*> > mCurrentWKBFragments; |
| 124 | + /**Similar to mCurrentWKB, but only the size*/ |
| 125 | + std::list< std::list<int> > mCurrentWKBFragmentSizes; |
| 126 | + QString mAttributeName; |
| 127 | + /**Index where the current attribute should be inserted*/ |
| 128 | + int mAttributeIndex; |
| 129 | + QString mTypeName; |
| 130 | + QgsApplication::endian_t mEndian; |
| 131 | +}; |
| 132 | + |
| 133 | +#endif |
0 commit comments