Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[WFS provider] Improve handling of NAMESPACE(S) (github #9849)
Modified by E. Rouault
  • Loading branch information
klavspc authored and rouault committed May 25, 2019
1 parent cd64b97 commit 465e6f0
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 27 deletions.
35 changes: 35 additions & 0 deletions src/providers/wfs/qgswfscapabilities.cpp
Expand Up @@ -87,6 +87,32 @@ QString QgsWfsCapabilities::Capabilities::addPrefixIfNeeded( const QString &name
return mapUnprefixedTypenameToPrefixedTypename[name];
}

QString QgsWfsCapabilities::Capabilities::getNamespaceForTypename( const QString &name ) const
{
Q_FOREACH ( const QgsWfsCapabilities::FeatureType &f, featureTypes )
{
if ( f.name == name )
{
return f.nameSpace;
}
}
return "";
}

QString QgsWfsCapabilities::Capabilities::getNamespaceParameterValue( const QString &WFSVersion, const QString &typeName ) const
{
QString namespaces = getNamespaceForTypename( typeName );
bool tryNameSpacing = ( !namespaces.isEmpty() && typeName.contains( ':' ) );
if ( tryNameSpacing )
{
QString prefixOfTypename = typeName.section( ':', 0, 0 );
return "xmlns(" + prefixOfTypename +
( WFSVersion.startsWith( QLatin1String( "2.0" ) ) ? "," : "=" ) +
namespaces + ")";
}
return QString();
}

class CPLXMLTreeUniquePointer
{
public:
Expand Down Expand Up @@ -404,6 +430,14 @@ void QgsWfsCapabilities::capabilitiesReplyFinished()
if ( psFeatureTypeIter )
{
featureType.nameSpace = CPLGetXMLValue( psFeatureTypeIter, ( "xmlns:" + prefixOfTypename ).toUtf8().constData(), "" );
if ( featureType.nameSpace.isEmpty() )
{
//Try to look for namespace in Name tag (Seen in GO Publisher)
//<wfs:FeatureType>
// <wfs:Name xmlns:dagi="http://data.gov.dk/schemas/dagi/2/gml3sfp">dagi:Menighedsraadsafstemningsomraade</wfs:Name>
// <wfs:Title>Menighedsraadsafstemningsomraade</wfs:Title>
featureType.nameSpace = CPLGetXMLValue( psFeatureTypeIter, ( "wfs:Name.xmlns:" + prefixOfTypename ).toUtf8().constData(), "" );
}
}
}
}
Expand Down Expand Up @@ -810,3 +844,4 @@ QString QgsWfsCapabilities::errorMessageWithReason( const QString &reason )
{
return tr( "Download of capabilities failed: %1" ).arg( reason );
}

2 changes: 2 additions & 0 deletions src/providers/wfs/qgswfscapabilities.h
Expand Up @@ -107,6 +107,8 @@ class QgsWfsCapabilities : public QgsWfsRequest

void clear();
QString addPrefixIfNeeded( const QString &name ) const;
QString getNamespaceForTypename( const QString &name ) const;
QString getNamespaceParameterValue( const QString &WFSVersion, const QString &typeName ) const;
};

//! Returns parsed capabilities - requestCapabilities() must be called before
Expand Down
10 changes: 9 additions & 1 deletion src/providers/wfs/qgswfsdescribefeaturetype.cpp
Expand Up @@ -14,19 +14,27 @@
***************************************************************************/

#include "qgswfsdescribefeaturetype.h"
#include "qgsmessagelog.h"

QgsWFSDescribeFeatureType::QgsWFSDescribeFeatureType( QgsWFSDataSourceURI &uri )
: QgsWfsRequest( uri )
{
}

bool QgsWFSDescribeFeatureType::requestFeatureType( const QString &WFSVersion,
const QString &typeName, bool bUsePlural )
const QString &typeName, const QgsWfsCapabilities::Capabilities &caps, bool bUsePlural )
{
QUrl url( mUri.requestUrl( QStringLiteral( "DescribeFeatureType" ) ) );
url.addQueryItem( QStringLiteral( "VERSION" ), WFSVersion );

url.addQueryItem( bUsePlural ?
QStringLiteral( "TYPENAMES" ) : QStringLiteral( "TYPENAME" ), typeName );
QString namespaceValue( caps.getNamespaceParameterValue( WFSVersion, typeName ) );
if ( !namespaceValue.isEmpty() )
{
url.addQueryItem( bUsePlural ?
QStringLiteral( "NAMESPACES" ) : QStringLiteral( "NAMESPACE" ), namespaceValue );
}

return sendGET( url, true, false );
}
Expand Down
6 changes: 5 additions & 1 deletion src/providers/wfs/qgswfsdescribefeaturetype.h
Expand Up @@ -16,6 +16,7 @@
#define QGSWFSDESCRIBEFEATURETYPE_H

#include "qgswfsrequest.h"
#include "qgswfscapabilities.h"

//! Manages the DescribeFeatureType request
class QgsWFSDescribeFeatureType : public QgsWfsRequest
Expand All @@ -25,7 +26,10 @@ class QgsWFSDescribeFeatureType : public QgsWfsRequest
explicit QgsWFSDescribeFeatureType( QgsWFSDataSourceURI &uri );

//! Issue the request
bool requestFeatureType( const QString &WFSVersion, const QString &typeName, bool bUsePlural );
bool requestFeatureType( const QString &WFSVersion,
const QString &typeName,
const QgsWfsCapabilities::Capabilities &caps,
bool bUsePlural );

protected:
QString errorMessageWithReason( const QString &reason ) override;
Expand Down
17 changes: 1 addition & 16 deletions src/providers/wfs/qgswfsfeatureiterator.cpp
Expand Up @@ -222,22 +222,7 @@ QUrl QgsWFSFeatureDownloader::buildURL( qint64 startIndex, int maxFeatures, bool
if ( mShared->mLayerPropertiesList.isEmpty() )
{
typenames = mShared->mURI.typeName();

// Add NAMESPACES parameter for server that declare a namespace in the FeatureType of GetCapabilities response
// See https://issues.qgis.org/issues/14685
Q_FOREACH ( const QgsWfsCapabilities::FeatureType &f, mShared->mCaps.featureTypes )
{
if ( f.name == typenames )
{
if ( !f.nameSpace.isEmpty() && f.name.contains( ':' ) )
{
QString prefixOfTypename = f.name.section( ':', 0, 0 );
namespaces = "xmlns(" + prefixOfTypename + "," + f.nameSpace + ")";
}
break;
}
}

namespaces = mShared->mCaps.getNamespaceParameterValue( mShared->mWFSVersion, typenames );
}
else
{
Expand Down
6 changes: 4 additions & 2 deletions src/providers/wfs/qgswfsprovider.cpp
Expand Up @@ -425,7 +425,7 @@ bool QgsWFSProvider::processSQL( const QString &sqlString, QString &errorMsg, QS
for ( int i = 0; i < 2; i++ )
{
if ( !describeFeatureType.requestFeatureType( mShared->mWFSVersion,
concatenatedTypenames, bUsePlural ) )
concatenatedTypenames, mShared->mCaps, bUsePlural ) )
{
errorMsg = tr( "DescribeFeatureType failed for url %1: %2" ).
arg( dataSourceUri(), describeFeatureType.errorMessage() );
Expand Down Expand Up @@ -1277,12 +1277,14 @@ bool QgsWFSProvider::describeFeatureType( QString &geometryAttribute, QgsFields
fields.clear();

QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI );

bool bUsePlural = false;
QByteArray response;

for ( int i = 0; i < 2; i++ )
{
if ( !describeFeatureType.requestFeatureType( mShared->mWFSVersion,
mShared->mURI.typeName(), bUsePlural ) )
mShared->mURI.typeName(), mShared->mCaps, bUsePlural ) )
{
QgsMessageLog::logMessage( tr( "DescribeFeatureType network request failed for url %1: %2" ).
arg( dataSourceUri(), describeFeatureType.errorMessage() ), tr( "WFS" ) );
Expand Down
31 changes: 26 additions & 5 deletions src/providers/wfs/qgswfsshareddata.cpp
Expand Up @@ -1271,8 +1271,7 @@ int QgsWFSSharedData::getFeatureCount( bool issueRequestIfNeeded )
{
mGetFeatureHitsIssued = true;
QgsWFSFeatureHitsRequest request( mURI );
int featureCount = request.getFeatureCount( mWFSVersion, mWFSFilter );

int featureCount = request.getFeatureCount( mWFSVersion, mWFSFilter, mCaps );
{
QMutexLocker locker( &mMutex );
// Check the return value. Might be -1 in case of error, or might be
Expand Down Expand Up @@ -1343,14 +1342,28 @@ QgsWFSFeatureHitsRequest::QgsWFSFeatureHitsRequest( QgsWFSDataSourceURI &uri )
}

int QgsWFSFeatureHitsRequest::getFeatureCount( const QString &WFSVersion,
const QString &filter )
const QString &filter, const QgsWfsCapabilities::Capabilities &caps )
{
QString typeName = mUri.typeName();

QUrl getFeatureUrl( mUri.requestUrl( QStringLiteral( "GetFeature" ) ) );
getFeatureUrl.addQueryItem( QStringLiteral( "VERSION" ), WFSVersion );
if ( WFSVersion.startsWith( QLatin1String( "2.0" ) ) )
getFeatureUrl.addQueryItem( QStringLiteral( "TYPENAMES" ), mUri.typeName() );
{
getFeatureUrl.addQueryItem( QStringLiteral( "TYPENAMES" ), typeName );
}
else
getFeatureUrl.addQueryItem( QStringLiteral( "TYPENAME" ), mUri.typeName() );
{
getFeatureUrl.addQueryItem( QStringLiteral( "TYPENAME" ), typeName );
}

QString namespaceValue( caps.getNamespaceParameterValue( WFSVersion, typeName ) );
if ( !namespaceValue.isEmpty() )
{
getFeatureUrl.addQueryItem( WFSVersion.startsWith( QLatin1String( "2.0" ) ) ?
QStringLiteral( "NAMESPACES" ) : QStringLiteral( "NAMESPACE" ), namespaceValue );
}

if ( !filter.isEmpty() )
{
getFeatureUrl.addQueryItem( QStringLiteral( "FILTER" ), filter );
Expand Down Expand Up @@ -1411,6 +1424,14 @@ QgsRectangle QgsWFSSingleFeatureRequest::getExtent()
getFeatureUrl.addQueryItem( QStringLiteral( "TYPENAMES" ), mUri.typeName() );
else
getFeatureUrl.addQueryItem( QStringLiteral( "TYPENAME" ), mUri.typeName() );

QString namespaceValue( mShared->mCaps.getNamespaceParameterValue( mShared->mWFSVersion, mUri.typeName() ) );
if ( !namespaceValue.isEmpty() )
{
getFeatureUrl.addQueryItem( mShared->mWFSVersion.startsWith( QLatin1String( "2.0" ) ) ?
QStringLiteral( "NAMESPACES" ) : QStringLiteral( "NAMESPACE" ), namespaceValue );
}

if ( mShared->mWFSVersion .startsWith( QLatin1String( "2.0" ) ) )
getFeatureUrl.addQueryItem( QStringLiteral( "COUNT" ), QString::number( 1 ) );
else
Expand Down
2 changes: 1 addition & 1 deletion src/providers/wfs/qgswfsshareddata.h
Expand Up @@ -289,7 +289,7 @@ class QgsWFSFeatureHitsRequest: public QgsWfsRequest
explicit QgsWFSFeatureHitsRequest( QgsWFSDataSourceURI &uri );

//! Returns the feature count, or -1 in case of error
int getFeatureCount( const QString &WFSVersion, const QString &filter );
int getFeatureCount( const QString &WFSVersion, const QString &filter, const QgsWfsCapabilities::Capabilities &caps );

protected:
QString errorMessageWithReason( const QString &reason ) override;
Expand Down
2 changes: 1 addition & 1 deletion tests/src/python/test_provider_wfs.py
Expand Up @@ -2986,7 +2986,7 @@ def testGetFeatureWithNamespaces(self):
</wfs:FeatureTypeList>
</wfs:WFS_Capabilities>""".encode('UTF-8'))

with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=my:typename'), 'wb') as f:
with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=my:typename&NAMESPACE=xmlns(my,http://my)'), 'wb') as f:
f.write("""
<xsd:schema xmlns:my="http://my" xmlns:gml="http://www.opengis.net/gml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://my">
<xsd:import namespace="http://www.opengis.net/gml"/>
Expand Down

0 comments on commit 465e6f0

Please sign in to comment.