Skip to content

Commit 33b74e6

Browse files
author
mhugent
committedNov 23, 2006
Changed the structure of the wfs provider such that it can now also read gml data from file
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@6119 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 9884183 commit 33b74e6

File tree

2 files changed

+221
-74
lines changed

2 files changed

+221
-74
lines changed
 

‎src/providers/wfs/qgswfsprovider.cpp

Lines changed: 202 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "qgslogger.h"
2323
#include <QDomDocument>
2424
#include <QDomNodeList>
25+
#include <QFile>
2526
#include <cfloat>
2627

2728
#ifdef WIN32
@@ -248,59 +249,57 @@ void QgsWFSProvider::select(QgsRect *mbr, bool useIntersect)
248249

249250
int QgsWFSProvider::getFeature(const QString& uri)
250251
{
251-
//GET or SOAP?
252-
if(uri.startsWith("SOAP://"))
252+
QString geometryAttribute;
253+
254+
//Local url or HTTP?
255+
if(uri.startsWith("http://"))
253256
{
254-
mEncoding = QgsWFSProvider::SOAP;
257+
mEncoding = QgsWFSProvider::GET;
255258
}
256259
else
257260
{
258-
mEncoding = QgsWFSProvider::GET;
261+
mEncoding = QgsWFSProvider::FILE;
259262
}
260263

261-
QString describeFeatureUri = uri;
262-
describeFeatureUri.replace(QString("GetFeature"), QString("DescribeFeatureType"));
263-
if(describeFeatureType(describeFeatureUri, mFields) != 0)
264-
{
265-
return 1;
266-
}
267-
268-
//find out the name of the attribute containing the geometry
269-
QString geometryAttribute;
270-
QString currentAttribute;
271-
for(std::vector<QgsField>::iterator iter = mFields.begin(); iter != mFields.end(); ++iter)
264+
if(mEncoding == QgsWFSProvider::FILE)
272265
{
273-
currentAttribute = iter->type();
274-
if(currentAttribute.startsWith("gml:") && currentAttribute.endsWith("PropertyType"))
275-
{
276-
geometryAttribute = iter->name();
277-
//erase the geometry attribute from mFields (QGIS distinguishes between geometry and thematic attributes)
278-
mFields.erase(iter);
279-
break;
280-
}
266+
//guess geometry attribute and other attributes from schema or from .gml file
267+
if(describeFeatureTypeFile(uri, geometryAttribute, mFields) != 0)
268+
{
269+
return 1;
270+
}
281271
}
282-
283-
if(mEncoding == QgsWFSProvider::SOAP)
272+
else //take schema with describeFeatureType request
284273
{
285-
return getFeatureSOAP(uri, geometryAttribute);
274+
QString describeFeatureUri = uri;
275+
describeFeatureUri.replace(QString("GetFeature"), QString("DescribeFeatureType"));
276+
if(describeFeatureType(describeFeatureUri, geometryAttribute, mFields) != 0)
277+
{
278+
return 1;
279+
}
286280
}
287-
else
281+
282+
if(mEncoding == QgsWFSProvider::GET)
288283
{
289284
return getFeatureGET(uri, geometryAttribute);
290285
}
286+
else//local file
287+
{
288+
return getFeatureFILE(uri, geometryAttribute); //read the features from disk
289+
}
291290
return 2;
292291
}
293292

294-
int QgsWFSProvider::describeFeatureType(const QString& uri, std::vector<QgsField>& fields)
293+
int QgsWFSProvider::describeFeatureType(const QString& uri, QString& geometryAttribute, std::vector<QgsField>& fields)
295294
{
296295
switch(mEncoding)
297296
{
298297
case QgsWFSProvider::GET:
299-
return describeFeatureTypeGET(uri, fields);
298+
return describeFeatureTypeGET(uri, geometryAttribute, fields);
300299
case QgsWFSProvider::POST:
301-
return describeFeatureTypePOST(uri, fields);
300+
return describeFeatureTypePOST(uri, geometryAttribute, fields);
302301
case QgsWFSProvider::SOAP:
303-
return describeFeatureTypeSOAP(uri, fields);
302+
return describeFeatureTypeSOAP(uri, geometryAttribute, fields);
304303
}
305304
return 1;
306305
}
@@ -347,57 +346,128 @@ int QgsWFSProvider::getFeatureSOAP(const QString& uri, const QString& geometryAt
347346
return 1; //soon...
348347
}
349348

350-
int QgsWFSProvider::describeFeatureTypeGET(const QString& uri, std::vector<QgsField>& fields)
349+
int QgsWFSProvider::getFeatureFILE(const QString& uri, const QString& geometryAttribute)
350+
{
351+
QFile gmlFile(uri);
352+
if(!gmlFile.open(QIODevice::ReadOnly))
353+
{
354+
mValid = false;
355+
return 1;
356+
}
357+
358+
QDomDocument gmlDoc;
359+
QString errorMsg;
360+
int errorLine, errorColumn;
361+
if(!gmlDoc.setContent(&gmlFile, true, &errorMsg, &errorLine, &errorColumn))
362+
{
363+
mValid = false;
364+
return 2;
365+
}
366+
367+
QDomElement featureCollectionElement = gmlDoc.documentElement();
368+
//get and set Extent
369+
if(getExtentFromGML2(&mExtent, featureCollectionElement) != 0)
370+
{
371+
return 3;
372+
}
373+
374+
setSRSFromGML2(featureCollectionElement);
375+
376+
if(getFeaturesFromGML2(featureCollectionElement, geometryAttribute) != 0)
377+
{
378+
return 4;
379+
}
380+
381+
return 0;
382+
}
383+
384+
int QgsWFSProvider::describeFeatureTypeGET(const QString& uri, QString& geometryAttribute, std::vector<QgsField>& fields)
351385
{
352386
QByteArray result;
353387
QgsHttpTransaction http(uri);
354-
http.getSynchronously(result);
388+
if(!http.getSynchronously(result))
389+
{
390+
return 1;
391+
}
392+
QDomDocument describeFeatureDocument;
393+
394+
if(!describeFeatureDocument.setContent(result, true))
395+
{
396+
return 2;
397+
}
398+
399+
if(readAttributesFromSchema(describeFeatureDocument, geometryAttribute, fields) != 0)
400+
{
401+
return 3;
402+
}
403+
404+
return 0;
405+
}
406+
407+
int QgsWFSProvider::describeFeatureTypePOST(const QString& uri, QString& geometryAttribute, std::vector<QgsField>& fields)
408+
{
409+
return 1; //soon...
410+
}
355411

356-
//find out the typename
357-
QString tname;
358-
QStringList tnamelist = uri.split("&");
359-
for(int i = 0; i < tnamelist.size(); ++i)
412+
int QgsWFSProvider::describeFeatureTypeSOAP(const QString& uri, QString& geometryAttribute, std::vector<QgsField>& fields)
413+
{
414+
return 1; //soon...
415+
}
416+
417+
int QgsWFSProvider::describeFeatureTypeFile(const QString& uri, QString& geometryAttribute, std::vector<QgsField>& fields)
418+
{
419+
//first look in the schema file
420+
QString noExtension = uri;
421+
noExtension.chop(3);
422+
QString schemaUri = noExtension.append("xsd");
423+
QFile schemaFile(schemaUri);
424+
425+
if(schemaFile.open(QIODevice::ReadOnly))
360426
{
361-
if(tnamelist.at(i).startsWith("typename", Qt::CaseInsensitive))
427+
QDomDocument schemaDoc;
428+
if(!schemaDoc.setContent(&schemaFile, true))
362429
{
363-
QStringList tlist = tnamelist.at(i).split("=");
364-
tname = tlist.at(1);
430+
return 1; //xml file not readable or not valid
365431
}
432+
433+
if(readAttributesFromSchema(schemaDoc, geometryAttribute, fields) != 0)
434+
{
435+
return 2;
436+
}
437+
return 0;
366438
}
439+
440+
std::list<QString> thematicAttributes;
367441

368-
//remove the namespace from tname
369-
if(tname.contains(":"))
442+
//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
443+
if(guessAttributesFromFile(uri, geometryAttribute, thematicAttributes) != 0)
370444
{
371-
tname = tname.section(":", 1, 1);
445+
return 1;
372446
}
373447

374-
QDomDocument describeFeatureDocument;
375-
if(!describeFeatureDocument.setContent(result, true))
448+
fields.clear();
449+
for(std::list<QString>::const_iterator it = thematicAttributes.begin(); it != thematicAttributes.end(); ++it)
376450
{
377-
return 1; //error
451+
fields.push_back(QgsField(*it, "unknown"));
378452
}
453+
return 0;
454+
}
379455

380-
qWarning(describeFeatureDocument.toString());
381-
456+
int QgsWFSProvider::readAttributesFromSchema(QDomDocument& schemaDoc, QString& geometryAttribute, std::vector<QgsField>& fields) const
457+
{
382458
//get the <schema> root element
383-
QDomNodeList schemaNodeList = describeFeatureDocument.elementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "schema");
459+
QDomNodeList schemaNodeList = schemaDoc.elementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "schema");
384460
if(schemaNodeList.length() < 1)
385461
{
386-
return 2;
462+
return 1;
387463
}
388464
QDomElement schemaElement = schemaNodeList.at(0).toElement();
389465

390466
//find <element name="tname" type = ...>
391467
QString complexTypeType;
392468
QDomNodeList typeElementNodeList = schemaElement.elementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "element");
393-
for(int i = 0; i < typeElementNodeList.length(); ++i)
394-
{
395-
QDomElement typeElement = typeElementNodeList.at(i).toElement();
396-
if(typeElement.attribute("name") == tname)
397-
{
398-
complexTypeType = typeElement.attribute("type");
399-
}
400-
}
469+
QDomElement typeElement = typeElementNodeList.at(0).toElement();
470+
complexTypeType = typeElement.attribute("type");
401471

402472
if(complexTypeType.isEmpty())
403473
{
@@ -418,6 +488,7 @@ int QgsWFSProvider::describeFeatureTypeGET(const QString& uri, std::vector<QgsFi
418488
if(complexTypeNodeList.at(i).toElement().attribute("name") == complexTypeType)
419489
{
420490
complexTypeElement = complexTypeNodeList.at(i).toElement();
491+
break;
421492
}
422493
}
423494

@@ -428,31 +499,94 @@ int QgsWFSProvider::describeFeatureTypeGET(const QString& uri, std::vector<QgsFi
428499

429500
//now create the attributes
430501
QDomNodeList attributeNodeList = complexTypeElement.elementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "element");
502+
if(attributeNodeList.size() < 1)
503+
{
504+
return 5;
505+
}
506+
431507
for(int i = 0; i < attributeNodeList.length(); ++i)
432508
{
433509
QDomElement attributeElement = attributeNodeList.at(i).toElement();
434510
//attribute name
435511
QString name = attributeElement.attribute("name");
436512
//attribute type
437513
QString type = attributeElement.attribute("type");
438-
if(type.isEmpty())
514+
515+
//is it a geometry attribute?
516+
if(type.startsWith("gml:") && type.endsWith("PropertyType"))
517+
{
518+
geometryAttribute = name;
519+
}
520+
else //todo: distinguish between numerical and non-numerical types
439521
{
440-
//todo: is the type name inside a <simpleType> element?
522+
fields.push_back(QgsField(name, type));
441523
}
442-
//todo: distinguish between numerical and non-numerical types
443-
fields.push_back(QgsField(name, type));
444524
}
445525
return 0;
446526
}
447527

448-
int QgsWFSProvider::describeFeatureTypePOST(const QString& uri, std::vector<QgsField>& fields)
528+
int QgsWFSProvider::guessAttributesFromFile(const QString& uri, QString& geometryAttribute, std::list<QString>& thematicAttributes) const
449529
{
450-
return 1; //soon...
451-
}
530+
QFile gmlFile(uri);
531+
if(!gmlFile.open(QIODevice::ReadOnly))
532+
{
533+
return 1;
534+
}
452535

453-
int QgsWFSProvider::describeFeatureTypeSOAP(const QString& uri, std::vector<QgsField>& fields)
454-
{
455-
return 1; //soon...
536+
QDomDocument gmlDoc;
537+
if(!gmlDoc.setContent(&gmlFile, true))
538+
{
539+
return 2; //xml file not readable or not valid
540+
}
541+
542+
543+
//find gmlCollection element
544+
QDomElement featureCollectionElement = gmlDoc.documentElement();
545+
546+
//get the first feature to guess attributes
547+
QDomNodeList featureList = featureCollectionElement.elementsByTagNameNS(GML_NAMESPACE, "featureMember");
548+
if(featureList.size() < 1)
549+
{
550+
return 3; //we need at least one attribute
551+
}
552+
553+
QDomElement featureElement = featureList.at(0).toElement();
554+
QDomNode attributeNode = featureElement.firstChild().firstChild();
555+
if(attributeNode.isNull())
556+
{
557+
return 4;
558+
}
559+
QString attributeText;
560+
QDomElement attributeChildElement;
561+
QString attributeChildLocalName;
562+
563+
while(!attributeNode.isNull())//loop over attributes
564+
{
565+
QString attributeNodeName = attributeNode.toElement().localName();
566+
attributeChildElement = attributeNode.firstChild().toElement();
567+
if(attributeChildElement.isNull())//no child element means it is a thematic attribute for sure
568+
{
569+
thematicAttributes.push_back(attributeNode.toElement().localName());
570+
attributeNode = attributeNode.nextSibling();
571+
continue;
572+
}
573+
574+
attributeChildLocalName = attributeChildElement.localName();
575+
if(attributeChildLocalName == "Point" || attributeChildLocalName == "LineString" || \
576+
attributeChildLocalName == "Polygon" || attributeChildLocalName == "MultiPoint" || \
577+
attributeChildLocalName == "MultiLineString" || attributeChildLocalName == "MultiPolygon" || \
578+
attributeChildLocalName == "Surface" || attributeChildLocalName == "MultiSurface")
579+
{
580+
geometryAttribute = attributeNode.toElement().localName(); //a geometry attribute
581+
}
582+
else
583+
{
584+
thematicAttributes.push_back(attributeNode.toElement().localName()); //a thematic attribute
585+
}
586+
attributeNode = attributeNode.nextSibling();
587+
}
588+
589+
return 0;
456590
}
457591

458592
int QgsWFSProvider::getExtentFromGML2(QgsRect* extent, const QDomElement& wfsCollectionElement) const

0 commit comments

Comments
 (0)