📄 qgswfsprovider.cpp
字号:
/*************************************************************************** qgswfsprovider.cpp ------------------- begin : July 25, 2006 copyright : (C) 2006 by Marco Hugentobler email : marco dot hugentobler at karto dot baug dot ethz dot ch ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/#include "qgsapplication.h"#include "qgsfeature.h"#include "qgsfield.h"#include "qgsgeometry.h"#include "qgshttptransaction.h"#include "qgsspatialrefsys.h"#include "qgswfsdata.h"#include "qgswfsprovider.h"#include "qgslogger.h"#include <QDomDocument>#include <QDomNodeList>#include <QFile>#include <cfloat>static const QString TEXT_PROVIDER_KEY = "WFS";static const QString TEXT_PROVIDER_DESCRIPTION = "WFS data provider";static const QString WFS_NAMESPACE = "http://www.opengis.net/wfs";static const QString GML_NAMESPACE = "http://www.opengis.net/gml";QgsWFSProvider::QgsWFSProvider(const QString& uri) : QgsVectorDataProvider(uri), mUseIntersect(false), mSelectedFeatures(0), mSourceSRS(0), mFeatureCount(0), mValid(true){ if(getFeature(uri) == 0) { mValid = true; //set spatial filter to the whole extent //select(mExtent, false); //MH TODO: fix this in provider0_9-branch } else { mValid = false; }}QgsWFSProvider::~QgsWFSProvider(){ delete mSelectedFeatures; for(std::list<std::pair<GEOS_GEOM::Envelope*, QgsFeature*> >::iterator it = mEnvelopesAndFeatures.begin();\ it != mEnvelopesAndFeatures.end(); ++it) { delete it->first; delete it->second; }}bool QgsWFSProvider::getNextFeature(QgsFeature& feature){ while(true) //go through the loop until we find a feature in the filter { if(!mSelectedFeatures || mFeatureIterator == mSelectedFeatures->end()) { return 0; } feature.setFeatureId(((QgsFeature*)(*mFeatureIterator))->featureId()); if(mFetchGeom) { QgsGeometry* geometry = ((QgsFeature*)(*mFeatureIterator))->geometry(); unsigned char* geom = geometry->wkbBuffer(); int geomSize = geometry->wkbSize(); unsigned char* copiedGeom = new unsigned char[geomSize]; memcpy(copiedGeom, geom, geomSize); feature.setGeometryAndOwnership(copiedGeom, geomSize); } const QgsAttributeMap& attributes = ((QgsFeature*)(*mFeatureIterator))->attributeMap(); for(QgsAttributeList::const_iterator it = mAttributesToFetch.begin(); it != mAttributesToFetch.end(); ++it) { feature.addAttribute(*it, attributes[*it]); } ++mFeatureIterator; if(mUseIntersect) { if(feature.geometry()->intersects(mSpatialFilter)) { return true; } else { continue; //go for the next feature } } else { return true; } }}QGis::WKBTYPE QgsWFSProvider::geometryType() const{ return mWKBType;}long QgsWFSProvider::featureCount() const{ return mFeatureCount;}uint QgsWFSProvider::fieldCount() const{ return mFields.size();}const QgsFieldMap & QgsWFSProvider::fields() const{ return mFields;}void QgsWFSProvider::reset(){ if(mSelectedFeatures) { mFeatureIterator = mSelectedFeatures->begin(); }}QgsSpatialRefSys QgsWFSProvider::getSRS(){ return mSourceSRS;}QgsRect QgsWFSProvider::extent(){ return mExtent;}bool QgsWFSProvider::isValid(){ return mValid;}void QgsWFSProvider::select(QgsAttributeList fetchAttributes, QgsRect rect, bool fetchGeometry, bool useIntersect){ mUseIntersect = useIntersect; mAttributesToFetch = fetchAttributes; mFetchGeom = fetchGeometry; delete mSelectedFeatures; if(rect.isEmpty()) { mSpatialFilter = mExtent; } else { mSpatialFilter = rect; } GEOS_GEOM::Envelope filter(mSpatialFilter.xMin(), mSpatialFilter.xMax(), mSpatialFilter.yMin(), mSpatialFilter.yMax());#if GEOS_VERSION_MAJOR < 3 mSelectedFeatures = mSpatialIndex.query(&filter);#else mSelectedFeatures = new std::vector<void*>; mSpatialIndex.query(&filter, *mSelectedFeatures);#endif mFeatureIterator = mSelectedFeatures->begin();}int QgsWFSProvider::getFeature(const QString& uri){ QString geometryAttribute; //Local url or HTTP? if(uri.startsWith("http://")) { mEncoding = QgsWFSProvider::GET; } else { mEncoding = QgsWFSProvider::FILE; } if(mEncoding == QgsWFSProvider::FILE) { //guess geometry attribute and other attributes from schema or from .gml file if(describeFeatureTypeFile(uri, geometryAttribute, mFields) != 0) { return 1; } } else //take schema with describeFeatureType request { QString describeFeatureUri = uri; describeFeatureUri.replace(QString("GetFeature"), QString("DescribeFeatureType")); if(describeFeatureType(describeFeatureUri, geometryAttribute, mFields) != 0) { return 1; } } if(mEncoding == QgsWFSProvider::GET) { return getFeatureGET(uri, geometryAttribute); } else//local file { return getFeatureFILE(uri, geometryAttribute); //read the features from disk } return 2;}int QgsWFSProvider::describeFeatureType(const QString& uri, QString& geometryAttribute, QgsFieldMap& fields){ switch(mEncoding) { case QgsWFSProvider::GET: return describeFeatureTypeGET(uri, geometryAttribute, fields); case QgsWFSProvider::POST: return describeFeatureTypePOST(uri, geometryAttribute, fields); case QgsWFSProvider::SOAP: return describeFeatureTypeSOAP(uri, geometryAttribute, fields); case QgsWFSProvider::FILE: return describeFeatureTypeFile(uri, geometryAttribute, fields); } return 1;}int QgsWFSProvider::getFeatureGET(const QString& uri, const QString& geometryAttribute){#if 0 //assemble request string QString request = uri /*+ "&OUTPUTFORMAT=gml3"*/; //use gml2 as it is supported by most wfs servers QByteArray result; QgsHttpTransaction http(request); http.getSynchronously(result); QDomDocument getFeatureDocument; if(!getFeatureDocument.setContent(result, true)) { return 1; //error } QDomElement featureCollectionElement = getFeatureDocument.documentElement(); //get and set Extent if(getExtentFromGML2(&mExtent, featureCollectionElement) != 0) { return 3; } setSRSFromGML2(featureCollectionElement); if(getFeaturesFromGML2(featureCollectionElement, geometryAttribute) != 0) { return 4; } return 0;#endif //the new and faster method with the expat parser std::list<QgsFeature*> dataFeatures; std::set<QString> thematicAttributes; for(QgsFieldMap::const_iterator it = mFields.begin(); it != mFields.end(); ++it) { thematicAttributes.insert(it->name()); } QgsWFSData dataReader(uri, &mExtent, &mSourceSRS, &dataFeatures, geometryAttribute, thematicAttributes, &mWKBType); QObject::connect(dataReader.http(), SIGNAL(dataReadProgress(int, int)), this, SLOT(handleWFSProgressMessage(int, int))); //also connect to setStatus signal of qgisapp (if it exists) QWidget* mainWindow = 0; QWidgetList topLevelWidgets = qApp->topLevelWidgets(); QWidgetList::iterator it = topLevelWidgets.begin(); for(; it != topLevelWidgets.end(); ++it) { if((*it)->objectName() == "QgisApp") { mainWindow = *it; break; } } if(mainWindow) { QObject::connect(this, SIGNAL(dataReadProgressMessage(QString)), mainWindow, SLOT(showStatusMessage(QString))); } if(dataReader.getWFSData() != 0) { qWarning("getWFSData returned with error"); return 1; } qWarning("feature count after request is:"); qWarning(QString::number(dataFeatures.size()).toLocal8Bit().data()); qWarning("mExtent after request is:"); qWarning(mExtent.stringRep().toLocal8Bit().data()); mFeatureCount = 0; QgsRect featureBBox; GEOS_GEOM::Envelope* geosBBox; for(std::list<QgsFeature*>::const_iterator it = dataFeatures.begin(); it != dataFeatures.end(); ++it) { featureBBox = (*it)->geometry()->boundingBox(); geosBBox = new GEOS_GEOM::Envelope(featureBBox.xMin(), featureBBox.xMax(), featureBBox.yMin(), featureBBox.yMax()); mSpatialIndex.insert(geosBBox, (void*)(*it)); mEnvelopesAndFeatures.push_back(std::make_pair(geosBBox, (*it))); ++mFeatureCount; } return 0;}int QgsWFSProvider::getFeaturePOST(const QString& uri, const QString& geometryAttribute){ return 1; //soon...}int QgsWFSProvider::getFeatureSOAP(const QString& uri, const QString& geometryAttribute){ return 1; //soon...}int QgsWFSProvider::getFeatureFILE(const QString& uri, const QString& geometryAttribute){ QFile gmlFile(uri); if(!gmlFile.open(QIODevice::ReadOnly)) { mValid = false; return 1; } QDomDocument gmlDoc; QString errorMsg; int errorLine, errorColumn; if(!gmlDoc.setContent(&gmlFile, true, &errorMsg, &errorLine, &errorColumn)) { mValid = false; return 2; } QDomElement featureCollectionElement = gmlDoc.documentElement(); //get and set Extent if(getExtentFromGML2(&mExtent, featureCollectionElement) != 0) { return 3; } setSRSFromGML2(featureCollectionElement); if(getFeaturesFromGML2(featureCollectionElement, geometryAttribute) != 0) { return 4; } return 0;}int QgsWFSProvider::describeFeatureTypeGET(const QString& uri, QString& geometryAttribute, QgsFieldMap& fields){ QByteArray result; QgsHttpTransaction http(uri); if(!http.getSynchronously(result)) { return 1; } QDomDocument describeFeatureDocument; if(!describeFeatureDocument.setContent(result, true)) { return 2; } if(readAttributesFromSchema(describeFeatureDocument, geometryAttribute, fields) != 0) { return 3; } return 0;}int QgsWFSProvider::describeFeatureTypePOST(const QString& uri, QString& geometryAttribute, QgsFieldMap& fields){ return 1; //soon...}int QgsWFSProvider::describeFeatureTypeSOAP(const QString& uri, QString& geometryAttribute, QgsFieldMap& fields){ return 1; //soon...}int QgsWFSProvider::describeFeatureTypeFile(const QString& uri, QString& geometryAttribute, QgsFieldMap& fields){ //first look in the schema file QString noExtension = uri; noExtension.chop(3); QString schemaUri = noExtension.append("xsd"); QFile schemaFile(schemaUri); if(schemaFile.open(QIODevice::ReadOnly)) { QDomDocument schemaDoc; if(!schemaDoc.setContent(&schemaFile, true)) { return 1; //xml file not readable or not valid } if(readAttributesFromSchema(schemaDoc, geometryAttribute, fields) != 0) { return 2; } return 0; } std::list<QString> thematicAttributes; //if this fails (e.g. no schema file), try to guess the geometry attribute and the names of the thematic attributes from the .gml file if(guessAttributesFromFile(uri, geometryAttribute, thematicAttributes) != 0) { return 1; } fields.clear(); int i = 0; for(std::list<QString>::const_iterator it = thematicAttributes.begin(); it != thematicAttributes.end(); ++it, ++i) { // TODO: is this correct? fields[i] = QgsField(*it, QVariant::String, "unknown"); } return 0;}int QgsWFSProvider::readAttributesFromSchema(QDomDocument& schemaDoc, QString& geometryAttribute, QgsFieldMap& fields) const{ //get the <schema> root element QDomNodeList schemaNodeList = schemaDoc.elementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "schema"); if(schemaNodeList.length() < 1) { return 1; } QDomElement schemaElement = schemaNodeList.at(0).toElement(); QDomElement complexTypeElement; //the <complexType> element corresponding to the feature type //find out, on which lines the first <element> or the first <complexType> occur. If <element> occurs first (mapserver), read the type of the relevant <complexType> tag. If <complexType> occurs first (geoserver), search for information about the feature type directly under this first complexType element int firstElementTagPos = schemaElement.elementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "element").at(0).toElement().columnNumber(); int firstComplexTypeTagPos = schemaElement.elementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "complexType").at(0).toElement().columnNumber(); if(firstComplexTypeTagPos < firstElementTagPos) { //geoserver complexTypeElement = schemaElement.elementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "complexType").at(0).toElement(); } else { //UMN mapserver QString complexTypeType; QDomNodeList typeElementNodeList = schemaElement.elementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "element"); QDomElement typeElement = typeElementNodeList.at(0).toElement();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -