• 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

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

  • 相关阅读:
    django ---解决跨域的问题
    python-isinstance函数
    python每日一学-os模块常用函数
    调用父类方法super
    fiddler小运用-断点
    劝告
    Django model字段
    Jenkins自动化部署前端
    解决react使用antd table组件固定表头后,表头和表体列不对齐以及配置fixed固定左右侧后行高度不对齐
    高德地图判断点的位置是否在浏览器可视区域内
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6314044.html
Copyright © 2020-2023  润新知