ol2 icon indicating copy to clipboard operation
ol2 copied to clipboard

viewparams missing for getFeatureInfo WMS request

Open emoen opened this issue 11 years ago • 19 comments

When querying an sql view WMS layer for getFeatureInfo the viewparams is missing.

An example of this: http://maps.imr.no/geoserver/wms?LAYERS=measurements_last_30_days&QUERY_LAYERS=measurements_last_30_days&STYLES=arcticroos_gtsbathy&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&BBOX=-10707220.5,-2714812.5,10707220.5,2714812.5&FEATURE_COUNT=10&HEIGHT=375&WIDTH=1479&FORMAT=image/png&INFO_FORMAT=application/vnd.ogc.gml&SRS=EPSG:3575&X=665&Y=365

which has been generated by OpenLayers.Control.WMSGetFeatureInfo.buildWMSOptions() and the response is:

<wfs:FeatureCollection xmlns="http://www.opengis.net/wfs" xmlns:wfs="http://www.opengis.net/wfs" xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://maps.imr.no:80/geoserver/schemas/wfs/1.0.0/WFS-basic.xsd"> gml:boundedBy gml:nullunknown/gml:null /gml:boundedBy /wfs:FeatureCollection

adding viewparams:type=BA returns the expected result: http://maps.imr.no/geoserver/wms?LAYERS=measurements_last_30_days&QUERY_LAYERS=measurements_last_30_days&STYLES=arcticroos_gtsbathy&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&BBOX=-10707220.5,-2714812.5,10707220.5,2714812.5&FEATURE_COUNT=10&HEIGHT=375&WIDTH=1479&FORMAT=image/png&INFO_FORMAT=application/vnd.ogc.gml&SRS=EPSG:3575&X=665&Y=365&viewparams=type:BA

emoen avatar Nov 04 '14 14:11 emoen

IMHO this should be up to the application to manage through the use of vendorParams:

https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Control/WMSGetFeatureInfo.js#L109:L119

bartvde avatar Nov 04 '14 14:11 bartvde

Is there not a better way of adding custom properties?

If vendorParams isnt an obscure and hidden variable enough - you get code like this when creating a WMS layer: https://gist.github.com/emoen/febc90cb67f3b2a0e7bb

Would it not be better to add any parameter to the url - openlayers can provide an error-message based on vendor specific parameters anyway. So then the programmer/user is responsible for adding the correct vendor specific parameters.

emoen avatar Nov 04 '14 14:11 emoen

unfortunately there are servers out there that break with extra params that they don't know of

bartvde avatar Nov 04 '14 15:11 bartvde

but is it still not the user/programmers responsibility to format urls that will be parsed by the servers?

emoen avatar Nov 04 '14 15:11 emoen

If you define a WMS layer:

var felayer = new OpenLayers.Layer.WMS(
  'layer name',
  WMS_SERVER_URL,
  {
    layers: "measurements_last_30_days",
    transparent: true,
    styles: style,
    viewparams : 'type:BA'
  },
  {
    isBaseLayer: false
  }
);

Then all the parameters are automagically added to getMap requests (also viewparams), but viewparams is not added to getFeatureInfo requests. This is strange as they are both part of the WMS specification.

You have to add

gxp.plugins.WMSGetFeatureInfo.prototype.layerParams = ["viewparams"];
to also have that parameter added to getFeatureInfo requests. Which means defining viewparams twice.

Why cant viewparams be added to getFeatuerInfo in the same way it is added to getMap requests?

emoen avatar Nov 05 '14 08:11 emoen

Hei everybody!

Just found this thread. :-) I have the same problem. I have several layers which result in SQL queries to geoserver. The only difference is a 'viewparams' parameter. When displaying the layer the viewparams are added, but getFeatureInfo does not add these params, so the features returned are usually too many. Is there any way to tell getFeatureInfo to append the viewparams from the layer definitions? I tried gxp.plugins.WMSGetFeatureInfo.prototype.layerParams = ["viewparams"]; but got the error that gxp is not defined.

Regards Christian

chris58 avatar Mar 02 '15 23:03 chris58

If your not using gxp - and you have added viewparams to your OpenLayers.layer.WMS configuration then you probably need to set vendorParams=viewparams in WMSGetFeatureInfo as Bart mentioned above.

I dont think vendorParams should be in WMSGetFeatureInfo as it should be the user/programmers responsibility to format urls correctly for the given WMS server. If the given WMS server doesnt support viewparams then it makes no sense to query that server for a postgis layer.

emoen avatar Mar 03 '15 08:03 emoen

Hei and thank you for your reply. When adding viewparams to a WMS layer definition they are added to the query, but when clicking on a feature and then requesting feature info the parameters are not added. In case of GeoServer the default viewparams for that layer are then used, which is not what I want in my case. But how can I add viewparams to specific layers. in WMSGetFeatureInfo? Adapting your example case, I would like features of type:BA and type BB, but not features of type:BC? Not doing anything will return the features of the default type (in case of GeoServer). Will adding type:BA;type:BB return features for layers of both types?

I was thinking of addapting the following code http://lin-ear-th-inking.blogspot.no/2013/06/how-to-get-openlayers-wmsgetfeatureinfo.html to viewParams instead of CQLfilter. Would that be the right direction to go?

   Hilsen 
         Christian

chris58 avatar Mar 04 '15 11:03 chris58

you will need to make use of vendorParams on OpenLayers.Control.WMSGetFeatureInfo

bartvde avatar Mar 04 '15 11:03 bartvde

That works well when only having ONE layer and adding some parameters to it. But when you have 2 layers which have different viewparams it doesn't. If you specify vendorparams like {viewparams: 'type:A;type:B'} both viewparams are appended but only the last is recognized by geoserver and then applied to both layers, thus returning the same feature info twice. It doesn't help either to change vendorparams to {viewparams:'type: Ä́', viewparams:'type: B'}. It results in only appending the second viewparam to the url with the same result of returning a feature twice. Maybe it's a geoserver issue?

chris58 avatar Mar 04 '15 15:03 chris58

How does the code for configuring the layer look like?

emoen avatar Mar 06 '15 08:03 emoen

I see your point @chris58 you would need vendorParams to be a lookup per layer name or something similar

Maybe we should add an extra event here where you could intercept the url and add the params yourself?

bartvde avatar Mar 06 '15 09:03 bartvde

@bartvde, that's the problem. ;-) I haven't figured out how to associate one set of viewParams/vendorParms with layer ONE and another set of params with layer TWO where the layers ONE and TWO have the same basic definition, i.e. @emoen the code looks like

var one = new OpenLayers.Layer.WMS(
                "Accidents 1: Tank", url,
                {
                    LAYERS: 'marenor:VesselAccident',
                    transparent: "TRUE",
        viewparams: 'fartoeystype:1\%'
                },
                  {
        visibility: false,
                    isBaseLayer: false
                }
          );

var two = new OpenLayers.Layer.WMS(
                "Accidents 2: Bulk/Tank", url,
                {
                    LAYERS: 'marenor:VesselAccident',
                    transparent: "TRUE",
        viewparams: 'fartoeystype:2\%'
                },
                  {
        visibility: false,
                    isBaseLayer: false
                }
          );

But, maybe it's really a geoserver problem of how to pick up and use the vendorParams in a query. I could add the parameters myself by using beforeGetFeatureInfo() but it's still one call with a list of all layers and all viewParams.

chris58 avatar Mar 06 '15 12:03 chris58

Hi again,

found the solution. Just to round up... ;-)

view parameters (geoserver) have to be separated by commas (,) when applying different parameters to several layers (http://docs.geoserver.org/stable/en/user/data/database/sqlview.html?highlight=viewparams). Number of comma separated viewParams must equal number of queried layers.

layersToBeQueried = [layerA, layerB, layerC];

controls.push(new OpenLayers.Control.WMSGetFeatureInfo({ autoActivate: true, infoFormat: "application/vnd.ogc.gml", maxFeatures: 5, queryVisible: true, eventListeners: { beforegetfeatureinfo: function(event) { var retArray = new Array(); var vParams = new Array(); var layer; for(var i = 0; i < layersToBeQueried.length; i++) { if(layersToBeQueried[i].visibility == true){ layer = layersToBeQueried[i]; // check for eventual viewParams if (layer.params.VIEWPARAMS != null){ vParams.push(layer.params.VIEWPARAMS); } else vParams.push('x:0'); // just to have something. Number of params must equal number of layers retArray.push(layer); } } // put view parameters into a string var viewparams = ''; for (i=vParams.length-1; i>=0; i--){ viewparams += vParams[i]; viewparams += (i>0)? ',' : ''; } // alert(viewparams); // add a buffer of 20 pixels around 'click' pluss the viewParams this.vendorParams = (vParams.length > 0)? {'buffer':20, 'viewParams': viewparams} : {buffer:20}; // set the layers to be queried this.layers = retArray; }, "getfeatureinfo": function(e) { // show the info in a popup... } } }));

Regards Christian

chris58 avatar Mar 09 '15 15:03 chris58

How does the url that is sent to geoserver look like? Do you send viewparams: 'fartoeystype:1, 2'? So it is creating a list? I worked around the problem of sending a list of values for one viewparams to geoserver;e.g. &VIEWPARAMS=periodname:'M200405 M200505', by creating a stored procedure tokenizes the elements and returns a select.

emoen avatar Mar 11 '15 08:03 emoen

In your case the generated viewparams in the getfeatureinfo URL should look like: &VIEWPARAMS=periodname:M200405,periodname:M200505

In my case the generated query to geoserver looks like this

http://some.host.com/geoserver/marenor/wms?LAYERS=marenor%3AVesselAccident,marenor%3AVesselAccident&QUERY_LAYERS=marenor%3AVesselAccident,marenor%3AVesselAccident&STYLES=,&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&BBOX=125573.169586%2C-2128225.949283%2C1227600.259337%2C-1731099.070094&FEATURE_COUNT=5&HEIGHT=360&WIDTH=999&FORMAT=image%2Fpng&INFO_FORMAT=application%2Fvnd.ogc.gml&SRS=EPSG%3A3575&X=442&Y=234&BUFFER=20&VIEWPARAMS=fartoeystype%3A9%25%2Cfartoeystype%3A7%25

or, a bit more readable like this http://some.host.com/geoserver/marenor/wms?LAYERS=marenor:VesselAccident,marenor:VesselAccident&QUERY_LAYERS=marenor:VesselAccident,marenor:VesselAccident&STYLES=,&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&BBOX=125573.169586,-2128225.949283,1227600.259337,-1731099.070094&FEATURE_COUNT=5&HEIGHT=360&WIDTH=999&FORMAT=image/png&INFO_FORMAT=application/vnd.ogc.gml&SRS=EPSG:3575&X=442&Y=234&BUFFER=20&VIEWPARAMS=fartoeystype:9%,fartoeystype:7%

The query starts with the two LAYERS which are identical ?LAYERS=marenor:VesselAccident,marenor:VesselAccident

The only difference is the view parameter at the end of the URL &VIEWPARAMS=fartoeystype:9%,fartoeystype:7%

The view parameter sets must be separated by commas and equal the number of layers. If a layer needs more than one view parameter the parameters for that layer must be separated by semi colons. Example: &VIEWPARAMS=fartoeystype:9%;accidenttype:gounding,fartoeystype:7% fartoeystype:9% and accidenttype:grounding are applied to the first layer, fartoeystype,:7% is applied to the second layer.

The percentage symbol is sent directly to the underlying database, it's an SQL wild card character, in this case 9% means look for everything which starts with a 9.

What you have to build up as vendorParams in Control.WMSGetFeatureInfo (for two layers, one view parameter each) looks like this.vendorParams = {buffer:20, viewParams: 'fartoeystype:9%,fartoeystype:7%'}

The buffer is another vendor parameter special to geoserver, in this case defining a 20 pixel buffer around the click position when searching for features.

Regards Christian


From: Endre Moen [[email protected]] Sent: Wednesday, March 11, 2015 9:35 AM To: openlayers/openlayers Cc: Christian Steinebach Subject: Re: [openlayers] viewparams missing for getFeatureInfo WMS request (#1404)

How does the url that is sent to geoserver look like? Do you send viewparams: 'fartoeystype:1, 2'? So it is creating a list? I worked around the problem of sending a list of values for one viewparams to geoserver;e.g. &VIEWPARAMS=periodname:'M200405 M200505', by creating a stored procedure tokenizes the elements and returns a select.

� Reply to this email directly or view it on GitHubhttps://github.com/openlayers/openlayers/issues/1404#issuecomment-78223256.

chris58 avatar Mar 11 '15 09:03 chris58

So does geoserver generates a query where you have SELECT * FROM ... WHERE ... AND fartoeystype=9% AND fartoeystype=7% AND ...?

I needed to generate an SQL that uses OR which is why I did it with a stored procedure: SELECT * FROM ... WHERE ... AND periodname=M200405 OR periodname=M200505 AND ...

emoen avatar Mar 11 '15 11:03 emoen

Sorry @emoen for late reply. Saw it first now. :-(

Geoserver doesn't generate any AND or OR in an SQL query. It just replaces the text between two percentage signs with the value of the paramter. You could fake it by using a query like

Select ... from ... where periodname='%period_1%' or periodname='%period_2%' or periodname='%period_3%'

Then your viewparams would be called period_1, period_2, period_3. If you set the default parameter values to something which will never exist in the table, e.g. -1, the query will work with one, two or all three period_X mentioned in the query.

If you want to build more complicated selections it could be an idea to use CQL filters instead.

Christian

chris58 avatar Mar 16 '15 21:03 chris58

hi @chris58 , we have probably hijacked this issue...

If your using geoserver-sql-view each key,value pair of VIEWPARAMS is matched to a column in a table or view and geoserver generates an sql like this:https://gist.github.com/emoen/8a6e2c2554ba177a26ae give a request with: VIEWPARAMS=parameter_name:Test_febr2014;grid:NorMar;...

Your right, CQL is the way to do it rather than a stored procedure.

emoen avatar Mar 24 '15 12:03 emoen