Wechat: yu389741| Email: gisdqy@163.com

Shop:https://www.giserdqy.com/shop

GDAL更新至1.8.1后,通过属性查询矢量出错问题的解决方式


在将GDAL更新至1.8.1之后,发现之前写的代码有些不能用了,前几天发现不能打开带有汉字的路径文件,并将其修改,详细参见我的CSDN博客,今天又发现在使用OGR_L_SetAttributeFilter的时候,之前可以进行过滤,现在err一直返回5,并且提示“语法错误”,代码如下:

const char* pszSQL = "Name=昌平区";
OGRErr err = OGR_L_SetAttributeFilter(hLayer, pszSQL);

对GDAL代码进行调试后发现,在1.8之前的版本,源代码中,使用的是一个swq.c的文件,但是现在用的是swq.cpp的文件,发现还多了好多的文件,具体就是以swq_开头的几个文件。

函数OGR_L_SetAttributeFilter之中调用的最终函数就是swq.cpp中的588行,如下: 

/************************************************************************/
/*                         swq_expr_compile2()                          */
/************************************************************************/

CPLErr swq_expr_compile2( const char *where_clause, 
                          swq_field_list *field_list,
                          swq_expr_node **expr_out )

{

    swq_parse_context context;

    context.pszInput = where_clause;
    context.pszNext = where_clause;
    context.nStartToken = SWQT_LOGICAL_START;
    
    if( swqparse( &context ) == 0 
        && context.poRoot->Check( field_list ) != SWQ_ERROR )
    {
        *expr_out = context.poRoot;

        return CE_None;
    }
    else
    {
        delete context.poRoot;
        *expr_out = NULL;
        return CE_Failure;
    }
}
上面得代码中,核心的函数就是那个swqparse( &context ) == 0,仔细研究发现该函数在文件GDAL_HOME\ogr\swq_parser.cpp的67行定义,只不过是个宏定义,最后发现是在第1365行定义的,具体代码见下:
/* Prevent warnings from -Wmissing-prototypes.  */
#ifdef YYPARSE_PARAM
#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
#else
int yyparse ();
#endif
#else /* ! YYPARSE_PARAM */
#if defined __STDC__ || defined __cplusplus
int yyparse (swq_parse_context *context);
#else
int yyparse ();
#endif
#endif /* ! YYPARSE_PARAM */


/*-------------------------.
| yyparse or yypush_parse.  |
`-------------------------*/

#ifdef YYPARSE_PARAM
#if (defined __STDC__ || defined __C99__FUNC__ \
     || defined __cplusplus || defined _MSC_VER)
int
yyparse (void *YYPARSE_PARAM)
#else
int
yyparse (YYPARSE_PARAM)
    void *YYPARSE_PARAM;
#endif
#else /* ! YYPARSE_PARAM */
#if (defined __STDC__ || defined __C99__FUNC__ \
     || defined __cplusplus || defined _MSC_VER)
int
yyparse (swq_parse_context *context)
#else
int
yyparse (context)
    swq_parse_context *context;
#endif
#endif
{
//此处为函数体,太多,不方便贴过来
}

在上面的函数中最关键的一个函数叫yylex,一看又是一个宏定义,好吧,原来的函数叫swqlex,这个函数的位置在swq.cpp中的第一个函数就是,这个函数的重要作用就是将上面输入的过滤字符串进行分类,如果字符串第一个是““”或者”‘“,那么就把该字符串当做SWQT_STRING类型处理,如果是0~9之间的,当做SWQT_NUMBER类型处理,如果是其他的字母或者数字,这里用的函数是isalnum,该函数说明,参考这里,在这里会判断是否是SQL语句中的一些关键字,入,IN,LIKE,ILIKE,ESCAPE,NULL,IS,NOT,AND,OR,BETWEEN等。到现在我们再回到开始的问题,为什么将字符串”NAME=昌平区“传入进来后,会提示语法错误呢,通过上面的分析,这个字符串,第一个字符既不是引号也不是数字,那么久进入到第三种情况了,然后解释器开始查找NAME,找了半天,没有发现NAME这么一个关键字,起结果就是提示”语法错误“。

知道了上面的工作过程,那么就知道怎么修改了,就在NAME和昌平区两个字符串前后都加上引号,如下

“NAME”= “昌平区”

再次进行测试,程序正常通过。

PS:如果把文件swq_parser.cpp能看懂的话,那么你的C/C++水平已经非常的牛X了,我是没看懂,这个文件其实是bison中的一部分,仔细搜索,发现bison是gnu下面的一个专门负责语法解释的开源库,中文的介绍可以参考这里。在这个文件中,大量使用了goto语句,宏定义,以及我第一次见到的”#line 127 “swq_parser.cpp””之类写法,此外还有个跟变态的y文件,路径为:GDAL_HOME\ogr\swq_parser.y。这个文件是嵌入在swq_parser.cpp中的,比如第1271行中的代码,如下:

  switch (yytype)
    {
      case 3: /* "SWQT_NUMBER" */

/* Line 1000 of yacc.c  */
#line 89 "swq_parser.y"
    { delete (*yyvaluep); };

/* Line 1000 of yacc.c  */
#line 1277 "swq_parser.cpp"
    break;
      case 4: /* "SWQT_STRING" */

/* Line 1000 of yacc.c  */
#line 89 "swq_parser.y"
    { delete (*yyvaluep); };

/* Line 1000 of yacc.c  */
#line 1286 "swq_parser.cpp"
    break;
      case 5: /* "SWQT_IDENTIFIER" */

这串代码,我没看懂,大概意思可能就是将y文件对应的行数所在位置进行执行,比如y文件的89行的内容是下面这样写的:

%destructor { delete $$; } SWQT_NUMBER SWQT_STRING SWQT_IDENTIFIER

看不懂啊,如果谁看懂这是什么语法,请告诉我,在此谢过。

转载自:https://blog.csdn.net/liminlu0314/article/details/6618268