@@ -167,6 +167,12 @@ int msSLDApplySLD(mapObj *map, char *psSLDXML, int iLayer,
167
167
int bFailedExpression = 0 ;
168
168
169
169
pasLayers = msSLDParseSLD (map , psSLDXML , & nLayers );
170
+ if ( pasLayers == NULL ) {
171
+ errorObj * psError = msGetErrorObj ();
172
+ if ( psError && psError -> code != MS_NOERR )
173
+ return MS_FAILURE ;
174
+ }
175
+
170
176
/* -------------------------------------------------------------------- */
171
177
/* If the same layer is given more that once, we need to */
172
178
/* duplicate it. */
@@ -398,6 +404,74 @@ int msSLDApplySLD(mapObj *map, char *psSLDXML, int iLayer,
398
404
goto sld_cleanup ;
399
405
}
400
406
} else {
407
+ lp = GET_LAYER (map , i );
408
+
409
+ /* The SLD might have a FeatureTypeConstraint */
410
+ if ( pasLayers [j ].filter .type == MS_EXPRESSION )
411
+ {
412
+ char * pszFilter ;
413
+ if ( lp -> filter .string && lp -> filter .type == MS_EXPRESSION )
414
+ {
415
+ pszFilter = msStringConcatenate (NULL , "((" );
416
+ pszFilter = msStringConcatenate (pszBuffer , lp -> filter .string );
417
+ pszFilter = msStringConcatenate (pszBuffer , ") AND (" );
418
+ pszFilter = msStringConcatenate (pszBuffer , pasLayers [j ].filter .string );
419
+ pszFilter = msStringConcatenate (pszBuffer , "))" );
420
+ }
421
+ else
422
+ {
423
+ pszFilter = msStringConcatenate (NULL , "(" );
424
+ pszFilter = msStringConcatenate (pszFilter , pasLayers [j ].filter .string );
425
+ pszFilter = msStringConcatenate (pszFilter , ")" );
426
+ }
427
+ if (lp -> connectiontype == MS_POSTGIS || lp -> connectiontype == MS_ORACLESPATIAL ||
428
+ lp -> connectiontype == MS_SDE || lp -> connectiontype == MS_PLUGIN ) {
429
+ /* Try to make a SQL filter from the FeatureTypeConstraint. */
430
+ /*But this will only work with very simple expressions. */
431
+ int bManagedToBuildSQLFilter = FALSE;
432
+ if ( lp -> filter .string == NULL ) {
433
+ psExpressionNode = BuildExpressionTree (pszFilter ,NULL );
434
+ if (psExpressionNode ) {
435
+ pszSqlExpression = FLTGetSQLExpression (psExpressionNode ,lp );
436
+ if (pszSqlExpression ) {
437
+ bManagedToBuildSQLFilter = TRUE;
438
+ msLoadExpressionString (& lp -> filter , pszSqlExpression );
439
+ msFree (pszSqlExpression );
440
+ }
441
+ FLTFreeFilterEncodingNode (psExpressionNode );
442
+ }
443
+ }
444
+ /* Otherwise fallback to adding the FeatureTypeConstraint to each */
445
+ /* class expression. Runtime will be slow (client-side), but no */
446
+ /* other choice... */
447
+ if ( !bManagedToBuildSQLFilter ) {
448
+ for (k = 0 ; k < lp -> numclasses ; k ++ ) {
449
+ if ( lp -> class [k ]-> expression .string == NULL ) {
450
+ char * pszExpr = msStringConcatenate (NULL , "(" );
451
+ pszExpr = msStringConcatenate (pszExpr , pasLayers [j ].filter .string );
452
+ pszExpr = msStringConcatenate (pszExpr , ")" );
453
+ msLoadExpressionString (& (lp -> class [k ]-> expression ), pszExpr );
454
+ msFree (pszExpr );
455
+ }
456
+ else if (lp -> class [k ]-> expression .type == MS_EXPRESSION ) {
457
+ char * pszExpr = msStringConcatenate (NULL , "((" );
458
+ pszExpr = msStringConcatenate (pszExpr , pasLayers [j ].filter .string );
459
+ pszExpr = msStringConcatenate (pszExpr , ") AND (" );
460
+ pszExpr = msStringConcatenate (pszExpr , lp -> class [k ]-> expression .string );
461
+ pszExpr = msStringConcatenate (pszExpr , "))" );
462
+ msLoadExpressionString (& (lp -> class [k ]-> expression ), pszExpr );
463
+ msFree (pszExpr );
464
+ }
465
+ }
466
+ }
467
+ }
468
+ else {
469
+ msLoadExpressionString (& lp -> filter , pszFilter );
470
+ }
471
+
472
+ msFree (pszFilter );
473
+ }
474
+
401
475
/*in some cases it would make sense to concatenate all the class
402
476
expressions and use it to set the filter on the layer. This
403
477
could increase performace. Will do it for db types layers #2840*/
@@ -617,7 +691,15 @@ layerObj *msSLDParseSLD(mapObj *map, char *psSLDXML, int *pnLayers)
617
691
if (psName && psName -> psChild && psName -> psChild -> pszValue )
618
692
pasLayers [iLayer ].name = msStrdup (psName -> psChild -> pszValue );
619
693
620
- msSLDParseNamedLayer (psNamedLayer , & pasLayers [iLayer ]);
694
+ if ( msSLDParseNamedLayer (psNamedLayer , & pasLayers [iLayer ]) != MS_SUCCESS ) {
695
+ int i ;
696
+ for (i = 0 ; i <=iLayer ; i ++ )
697
+ freeLayer (& pasLayers [i ]);
698
+ msFree (pasLayers );
699
+ nLayers = 0 ;
700
+ pasLayers = NULL ;
701
+ break ;
702
+ }
621
703
622
704
psNamedLayer = psNamedLayer -> psNext ;
623
705
iLayer ++ ;
@@ -729,6 +811,79 @@ void _SLDApplyRuleValues(CPLXMLNode *psRule, layerObj *psLayer,
729
811
730
812
}
731
813
814
+ /************************************************************************/
815
+ /* msSLDGetCommonExpressionFromFilter */
816
+ /* */
817
+ /* Get a commomn expression valid from the filter valid for the */
818
+ /* temporary layer. */
819
+ /************************************************************************/
820
+ static char * msSLDGetCommonExpressionFromFilter (CPLXMLNode * psFilter ,
821
+ layerObj * psLayer )
822
+ {
823
+ char * pszExpression = NULL ;
824
+ CPLXMLNode * psTmpNextNode = NULL ;
825
+ CPLXMLNode * psTmpNode = NULL ;
826
+ FilterEncodingNode * psNode = NULL ;
827
+ char * pszTmpFilter = NULL ;
828
+ layerObj * psCurrentLayer = NULL ;
829
+ const char * pszWmsName = NULL ;
830
+ const char * key = NULL ;
831
+
832
+ /* clone the tree and set the next node to null */
833
+ /* so we only have the Filter node */
834
+ psTmpNode = CPLCloneXMLTree (psFilter );
835
+ psTmpNextNode = psTmpNode -> psNext ;
836
+ psTmpNode -> psNext = NULL ;
837
+ pszTmpFilter = CPLSerializeXMLTree (psTmpNode );
838
+ psTmpNode -> psNext = psTmpNextNode ;
839
+ CPLDestroyXMLNode (psTmpNode );
840
+
841
+ if (pszTmpFilter ) {
842
+ psNode = FLTParseFilterEncoding (pszTmpFilter );
843
+
844
+ CPLFree (pszTmpFilter );
845
+ }
846
+
847
+ if (psNode ) {
848
+ int j ;
849
+
850
+ /*preparse the filter for possible gml aliases set on the layer's metada:
851
+ "gml_NA3DESC_alias" "alias_name" and filter could be
852
+ <ogc:PropertyName>alias_name</ogc:PropertyName> #3079*/
853
+ for (j = 0 ; j < psLayer -> map -> numlayers ; j ++ ) {
854
+ psCurrentLayer = GET_LAYER (psLayer -> map , j );
855
+
856
+ pszWmsName = msOWSLookupMetadata (& (psCurrentLayer -> metadata ), "MO" , "name" );
857
+
858
+ if ((psCurrentLayer -> name && psLayer -> name &&
859
+ strcasecmp (psCurrentLayer -> name , psLayer -> name ) == 0 ) ||
860
+ (psCurrentLayer -> group && psLayer -> name &&
861
+ strcasecmp (psCurrentLayer -> group , psLayer -> name ) == 0 ) ||
862
+ (psLayer -> name && pszWmsName &&
863
+ strcasecmp (pszWmsName , psLayer -> name ) == 0 ))
864
+ break ;
865
+ }
866
+ if (j < psLayer -> map -> numlayers ) {
867
+ /*make sure that the tmp layer has all the metadata that
868
+ the orinal layer has, allowing to do parsing for
869
+ such things as gml_attribute_type #3052*/
870
+ while (1 ) {
871
+ key = msNextKeyFromHashTable (& psCurrentLayer -> metadata , key );
872
+ if (!key )
873
+ break ;
874
+ else
875
+ msInsertHashTable (& psLayer -> metadata , key ,
876
+ msLookupHashTable (& psCurrentLayer -> metadata , key ));
877
+ }
878
+ FLTPreParseFilterForAlias (psNode , psLayer -> map , j , "G" );
879
+ }
880
+
881
+ pszExpression = FLTGetCommonExpression (psNode , psLayer );
882
+ FLTFreeFilterEncodingNode (psNode );
883
+ }
884
+
885
+ return pszExpression ;
886
+ }
732
887
733
888
/************************************************************************/
734
889
/* msSLDParseNamedLayer */
@@ -740,15 +895,9 @@ int msSLDParseNamedLayer(CPLXMLNode *psRoot, layerObj *psLayer)
740
895
CPLXMLNode * psFeatureTypeStyle , * psRule , * psUserStyle ;
741
896
CPLXMLNode * psSLDName = NULL , * psNamedStyle = NULL ;
742
897
CPLXMLNode * psElseFilter = NULL , * psFilter = NULL ;
743
- CPLXMLNode * psTmpNode = NULL ;
744
- FilterEncodingNode * psNode = NULL ;
898
+ CPLXMLNode * psLayerFeatureConstraints = NULL ;
745
899
int nNewClasses = 0 , nClassBeforeFilter = 0 , nClassAfterFilter = 0 ;
746
900
int nClassAfterRule = 0 , nClassBeforeRule = 0 ;
747
- char * pszTmpFilter = NULL ;
748
- layerObj * psCurrentLayer = NULL ;
749
- const char * pszWmsName = NULL ;
750
- int j = 0 ;
751
- const char * key = NULL ;
752
901
753
902
if (!psRoot || !psLayer )
754
903
return MS_FAILURE ;
@@ -792,69 +941,11 @@ int msSLDParseNamedLayer(CPLXMLNode *psRoot, layerObj *psLayer)
792
941
/* NOTE : Spatial Filter is not supported. */
793
942
/* -------------------------------------------------------------------- */
794
943
psFilter = CPLGetXMLNode (psRule , "Filter" );
795
- if (psFilter && psFilter -> psChild &&
796
- psFilter -> psChild -> pszValue ) {
797
- CPLXMLNode * psTmpNextNode = NULL ;
798
- /* clone the tree and set the next node to null */
799
- /* so we only have the Filter node */
800
- psTmpNode = CPLCloneXMLTree (psFilter );
801
- psTmpNextNode = psTmpNode -> psNext ;
802
- psTmpNode -> psNext = NULL ;
803
- pszTmpFilter = CPLSerializeXMLTree (psTmpNode );
804
- psTmpNode -> psNext = psTmpNextNode ;
805
- CPLDestroyXMLNode (psTmpNode );
806
-
807
- if (pszTmpFilter ) {
808
- /* nTmp = strlen(psFilter->psChild->pszValue)+17; */
809
- /* pszTmpFilter = malloc(sizeof(char)*nTmp); */
810
- /* sprintf(pszTmpFilter,"<Filter>%s</Filter>", */
811
- /* psFilter->psChild->pszValue); */
812
- /* pszTmpFilter[nTmp-1]='\0'; */
813
- psNode = FLTParseFilterEncoding (pszTmpFilter );
814
-
815
- CPLFree (pszTmpFilter );
816
- }
817
-
818
- if (psNode ) {
819
- char * pszExpression = NULL ;
820
- int i ;
821
-
822
- /*preparse the filter for possible gml aliases set on the layer's metada:
823
- "gml_NA3DESC_alias" "alias_name" and filter could be
824
- <ogc:PropertyName>alias_name</ogc:PropertyName> #3079*/
825
- for (j = 0 ; j < psLayer -> map -> numlayers ; j ++ ) {
826
- psCurrentLayer = GET_LAYER (psLayer -> map , j );
827
-
828
- pszWmsName = msOWSLookupMetadata (& (psCurrentLayer -> metadata ), "MO" , "name" );
829
-
830
- if ((psCurrentLayer -> name && psLayer -> name &&
831
- strcasecmp (psCurrentLayer -> name , psLayer -> name ) == 0 ) ||
832
- (psCurrentLayer -> group && psLayer -> name &&
833
- strcasecmp (psCurrentLayer -> group , psLayer -> name ) == 0 ) ||
834
- (psLayer -> name && pszWmsName &&
835
- strcasecmp (pszWmsName , psLayer -> name ) == 0 ))
836
- break ;
837
- }
838
- if (j < psLayer -> map -> numlayers ) {
839
- /*make sure that the tmp layer has all the metadata that
840
- the orinal layer has, allowing to do parsing for
841
- such things as gml_attribute_type #3052*/
842
- while (1 ) {
843
- key = msNextKeyFromHashTable (& psCurrentLayer -> metadata , key );
844
- if (!key )
845
- break ;
846
- else
847
- msInsertHashTable (& psLayer -> metadata , key ,
848
- msLookupHashTable (& psCurrentLayer -> metadata , key ));
849
- }
850
- FLTPreParseFilterForAlias (psNode , psLayer -> map , j , "G" );
851
- }
852
-
853
- pszExpression = FLTGetCommonExpression (psNode , psLayer );
854
- FLTFreeFilterEncodingNode (psNode );
855
- psNode = NULL ;
856
-
857
- if (pszExpression ) {
944
+ if (psFilter && psFilter -> psChild && psFilter -> psChild -> pszValue ) {
945
+ char * pszExpression = msSLDGetCommonExpressionFromFilter (psFilter ,
946
+ psLayer );
947
+ if (pszExpression ) {
948
+ int i ;
858
949
nNewClasses =
859
950
nClassAfterFilter - nClassBeforeFilter ;
860
951
for (i = 0 ; i < nNewClasses ; i ++ ) {
@@ -864,8 +955,6 @@ int msSLDParseNamedLayer(CPLXMLNode *psRoot, layerObj *psLayer)
864
955
}
865
956
msFree (pszExpression );
866
957
pszExpression = NULL ;
867
- }
868
-
869
958
}
870
959
}
871
960
nClassAfterRule = psLayer -> numclasses ;
@@ -917,6 +1006,46 @@ int msSLDParseNamedLayer(CPLXMLNode *psRoot, layerObj *psLayer)
917
1006
}
918
1007
}
919
1008
1009
+ /* Deal with LayerFeatureConstraints */
1010
+ psLayerFeatureConstraints = CPLGetXMLNode (psRoot , "LayerFeatureConstraints" );
1011
+ if ( psLayerFeatureConstraints != NULL ) {
1012
+ CPLXMLNode * psIter = psLayerFeatureConstraints -> psChild ;
1013
+ CPLXMLNode * psFeatureTypeConstraint = NULL ;
1014
+ for (; psIter != NULL ; psIter = psIter -> psNext ) {
1015
+ if ( psIter -> eType == CXT_Element &&
1016
+ strcmp (psIter -> pszValue , "FeatureTypeConstraint" ) == 0 ) {
1017
+ if ( psFeatureTypeConstraint == NULL ) {
1018
+ psFeatureTypeConstraint = psIter ;
1019
+ } else {
1020
+ msSetError (MS_WMSERR , "Only one single FeatureTypeConstraint element "
1021
+ "per LayerFeatureConstraints is supported" , "" );
1022
+ return MS_FAILURE ;
1023
+ }
1024
+ }
1025
+ }
1026
+ if ( psFeatureTypeConstraint != NULL ) {
1027
+ if ( CPLGetXMLNode (psFeatureTypeConstraint , "FeatureTypeName" ) != NULL ) {
1028
+ msSetError (MS_WMSERR , "FeatureTypeName element is not "
1029
+ "supported in FeatureTypeConstraint" , "" );
1030
+ return MS_FAILURE ;
1031
+ }
1032
+ if ( CPLGetXMLNode (psFeatureTypeConstraint , "Extent" ) != NULL ) {
1033
+ msSetError (MS_WMSERR , "Extent element is not "
1034
+ "supported in FeatureTypeConstraint" , "" );
1035
+ return MS_FAILURE ;
1036
+ }
1037
+ psFilter = CPLGetXMLNode (psFeatureTypeConstraint , "Filter" );
1038
+ if (psFilter && psFilter -> psChild && psFilter -> psChild -> pszValue ) {
1039
+ char * pszExpression = msSLDGetCommonExpressionFromFilter (psFilter ,
1040
+ psLayer );
1041
+ if (pszExpression ) {
1042
+ msLoadExpressionString (& psLayer -> filter , pszExpression );
1043
+ msFree (pszExpression );
1044
+ }
1045
+ }
1046
+ }
1047
+ }
1048
+
920
1049
return MS_SUCCESS ;
921
1050
}
922
1051
@@ -4736,17 +4865,13 @@ FilterEncodingNode *BuildExpressionTree(char *pszExpression,
4736
4865
{
4737
4866
int nLength = 0 ;
4738
4867
int nOperators = 0 ;
4739
- char * pszFinalExpression = NULL ;
4740
4868
char * pszComparionValue = NULL , * pszAttibuteName = NULL ;
4741
4869
char * pszAttibuteValue = NULL ;
4742
4870
char * pszLeftExpression = NULL , * pszRightExpression = NULL , * pszOperator = NULL ;
4743
4871
4744
4872
if (!pszExpression || (nLength = strlen (pszExpression )) <=0 )
4745
4873
return NULL ;
4746
4874
4747
- pszFinalExpression = (char * )malloc (sizeof (char )* (nLength + 1 ));
4748
- pszFinalExpression [0 ] = '\0' ;
4749
-
4750
4875
/* -------------------------------------------------------------------- */
4751
4876
/* First we check how many logical operators are there : */
4752
4877
/* - if none : It means It is a comparision operator (like =, */
@@ -4867,7 +4992,6 @@ FilterEncodingNode *BuildExpressionTree(char *pszExpression,
4867
4992
4868
4993
return psNode ;
4869
4994
} else {
4870
- msFree (pszFinalExpression );
4871
4995
return NULL ;
4872
4996
}
4873
4997
}
0 commit comments