-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Server][FEATURE][needs-docs] Support WFS 1.1.0 #5297
Conversation
c113d48
to
fd1a4c4
Compare
// Supports WFS 1.0.0 | ||
if ( QSTR_COMPARE( versionString, "1.0.0" ) ) | ||
{ | ||
v1_0_0::writeGetCapabilities( mServerIface, project, versionString, request, response ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a big fan of this notation : v1_0_0::
.
Moreover, I've the feeling that most of the code is duplicated between qgswfsgetcapabilities.cpp
and qgswfsgetcapabilities_1_0_0.cpp
. And it's not homogeneous with other services (for example, we don't have a qgswmsrenderer.cpp
and a qgswmsrenderer_1_3_0.cpp
).
No? Or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The WFS capabilities documents are not the same at all and it will be easiest to enhance or maintain with separate files. For the other request like DescribeFeature or GetFeature, we reused the same code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's true that it's not as similar as I thought... However, I think we could factor a little more.
For example, writeGetCapabilities
is identical and there's some redundant content in createGetCapabilitiesDocument
(WFS_Capabilities, ogc:SpatialOperators) or getFeatureTypeListElement
.
That being said, your comment about maintainability is justified...
@nyalldawson @m-kuhn What do you think about adding files for specific service versions (like those introduced in this PR : qgswfsgetcapabilities.cpp
and qgswfsgetcapabilities_1_0_0.cpp
) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, owslib made the same thing as you (separate versions in files) : https://github.com/geopython/OWSLib/tree/master/owslib/feature
So why not, but in this case, maybe we should have a qgswfsgetcapabilities_common.x
, qgswfsgetcapabilities_100.x
and qgswfsgetcapabilities_110.x
files to be more explicit?
Otherwise (I'm just thinking out loud, so it may probably be a bad idea...), maybe a composite/visitor pattern could be used:
- 1 node of the tree for 1 node of the document
- one or several validity versions for each node (the same node may be valid for 1.0.0 or 1.1.0)
- a visitor collects only nodes for a specific version
- when we want to add a new version, we just have to add some node and retrieve existing nodes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @pblottiere
There is several ways to add new versions:
- Handle several versions in one module (all in one, only one default version registred but assumed to handle everything, or register multiple versions in the same module.)
- Add new versions with different modules python or c++ (register them with there proper versions)
In the present the case we use a different namespace juste to separates units specific to a given version: I do not care about the name of the namespace as long it is meaningful in the context - IMO, the advantage of using namespace over is that you don't have to rename all your fonctions/objects.
IMHO, we should consider the current implementation as a easy way to implement quickly the 1_1_0 without taking the chance to break actual implementation with more or less heavy refactoring: we will have time to factorize things when all the stuff will be stabilized a little more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @dmarteau
I don't have a strong opinion against the use of a namespaces here as long as it does not introduce redundancy in the code.
And I would also explicit versions: it is a bit strange to have qgswfsgetcapabilities_1_0_0 and qgswfsgetcapabilities without suffix (which version ?), no ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mhugo it's because 1.1.0 will be the default version instead of 1.0.0 which become a special version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/server/qgsrequesthandler.cpp
Outdated
continue; | ||
|
||
QDomNode attrNode = map.item( i ); | ||
QDomAttr attr = attrNode.toAttr(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think attrNode
is not used directly. Maybe const QDomAttr attr = map.item( i ).toAttr();
is enough?
src/server/qgsrequesthandler.cpp
Outdated
if ( attr.isNull() ) | ||
continue; | ||
|
||
QString attrName = attr.name(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const
@@ -71,7 +72,15 @@ namespace QgsWfs | |||
|
|||
if ( QSTR_COMPARE( req, "GetCapabilities" ) ) | |||
{ | |||
writeGetCapabilities( mServerIface, project, versionString, request, response ); | |||
// Supports WFS 1.0.0 | |||
if ( QSTR_COMPARE( versionString, "1.0.0" ) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now there's only 2 versions to manage. But something like QgsProjectVersion
(for minor versions and so on) could be used instead of comparing string. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not need to use a QgsProjectVersion, here the versionSTring has to be "1.0.0", if it's not the default version has to be returned.
QDomText keywordsText = doc.createTextNode( keywords.join( QStringLiteral( ", " ) ) ); | ||
keywordsElem.appendChild( keywordsText ); | ||
QDomElement keywordsElem = doc.createElement( QStringLiteral( "ows:Keywords" ) ); | ||
for ( QString keyword : keywords ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const ref?
requestElement.appendChild( getCapabilitiesElement ); | ||
QString contactMail = QgsServerProjectUtils::owsServiceContactMail( *project ); | ||
QString contactPhone = QgsServerProjectUtils::owsServiceContactPhone( *project ); | ||
QString onlineResource = QgsServerProjectUtils::owsServiceOnlineResource( *project ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const
QDomElement srsElem = doc.createElement( QStringLiteral( "SRS" ) ); | ||
QDomText srsText = doc.createTextNode( layer->crs().authid() ); | ||
//create DefaultSRS element | ||
QString defaultSrs = layer->crs().authid(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const
QStringList wfstUpdateLayersId = QgsServerProjectUtils::wfstUpdateLayerIds( *project ); | ||
QStringList wfstInsertLayersId = QgsServerProjectUtils::wfstInsertLayerIds( *project ); | ||
QStringList wfstDeleteLayersId = QgsServerProjectUtils::wfstDeleteLayerIds( *project ); | ||
for ( int i = 0; i < wfsLayerIds.size(); ++i ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for ( const QString &wfsLayerId : wfsLayerIds ) {}
QStringList wfsLayerIds = QgsServerProjectUtils::wfsLayerIds( *project ); | ||
QStringList wfstUpdateLayersId = QgsServerProjectUtils::wfstUpdateLayerIds( *project ); | ||
QStringList wfstInsertLayersId = QgsServerProjectUtils::wfstInsertLayerIds( *project ); | ||
QStringList wfstDeleteLayersId = QgsServerProjectUtils::wfstDeleteLayerIds( *project ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const
geom = transformed; | ||
crs = params.outputCrs; | ||
if ( crs.isGeographic() && !params.crs.isGeographic() ) | ||
prec = std::min( params.precision + 3, 6 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it standard to manage precision this way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the ISO GeoJSON standard, the max precision has been fixed to 6 for EPSG:4326, so I think I can homogenize the precision to 6 for all the Geographic requested outputCrs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mm, after checking the standard, 6 digit is only a recommandation to avoid heavy files with 15 digits.
As there is a per layer precision configuration windows, I would reuse the precision used for GML output. If really you need a different precision between GML an GeoJSON, we could add another column there, but I don't think it's worth it.
Also we could discuss if setting by default 6 digits there woudn't be a better behavior than the current digit default
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, last sentence was "the current 8 digit default"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@haubourg the problem is not between GML or GeoJSON, is between meters and degrees. In WFS 1.1.0, the GML can be requested in an other CRS than the source. So if the features ares requested in a Geographic CRS, I can't used directly the precision, for exemple 1 for a CRS in meters. The test here is only for this type of transform.
The other point is that I have updated the current default precision to 6 digits to avoid heavy files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add the inverse, from Geographic to Planar, I can limit to 3 digits.
#include "qgsserverrequest.h" | ||
#include "qgsprojectversion.h" | ||
|
||
/** QgsWmsParameters provides an interface to retrieve and manipulate WFS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which one ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
QgsWmsParameters
-> QgsWfsParameters
@rldhont Thank you for this PR, it's good to see WFS 1.1.0 landing in server! Just some comments:
|
I think that |
f5e42b6
to
1d38203
Compare
@pblottiere have you some comment on tests/src/python/test_qgsserver.py changes ? |
@pblottiere I'd like to merge it, we can enhance the code after the feature freeze. |
Description
QGIS Server already supports WMS 1.3.0 and 1.1.1, WFS 1.0.0 and WCS 1.0.0
WFS 1.1.0 adds parameters like: SrsName, to transform GML geometry and SortBy to order features.
Funded by Ifremer
Checklist
[FEATURE]
in the commit message[needs-docs]
in the commit message and containt sufficient information in the commit message to be documentedscripts/prepare-commit.sh
script before each commit