注册 登录
编程论坛 VFP论坛

发现json类的一个bug

sam_jiang 发布于 2024-12-28 12:54, 298 次点击
上次在《跟我一起学微信公众平台开发(二)》里提供了json类,今天发现有个bug,当属性值里有“:”“,”时,解析程序会出错,这两个符号是我们解析程序里字符串的起始判定符号,所以必须替换掉才可以进行解析。

用上次的类,运行下面的代码将会报错!
程序代码:

CLEAR
RELEASE ALL
PUBLIC ojson
*script=[{  "errcode": 0,  "errmsg": "ok",  "quota":{    "daily_limit": 0,    "used": 0,    "remain": 0}}]
script=[{"errcode":40164,"errmsg":"invalid ip 112.10.181.255 ipv6 ::ffff:112.10.181.255, not in whitelist rid: 676ee36c-33ea19f9-5885a393"}]
ojson=NEWOBJECT("json","myclass")
ojson.parse(script)
?ojson.getvalue("errmsg")


解决方案很简单,就是判断每对“”的里面文字是否有“:”“,”,如果有就用“& # 58”“& # 44”替换,最后再复原就可以了。
主要代码如下:
json.parse
程序代码:

LPARAMETERS jsonscript
*!* 12/28发现bug,当json属性的值里有“:”“,”符号时,解析程序出错
*!* 解决方案,解析前搜索每对引号对,把这两个字符替换掉,最后再复原。
LOCAL ckey,cstr,i,j,n,ccontent,ckey,cvalue,atemp,nleft,nright,jsarray,ncount,m
jsonscript=STRTRAN(jsonscript,CHR(9),"") &&清除tab键
jsonscript=STRTRAN(jsonscript,CHR(10),"") &&清除ctrl+enter
jsonscript=STRTRAN(jsonscript,CHR(13),"") &&清除换行符
jsonscript=allt(jsonscript) &&清除首尾空格
*!*    ************最基本的json结构检查************
IF OCCURS("{",jsonscript)<>OCCURS("}",jsonscript) OR OCCURS("[",jsonscript)<>+OCCURS("]",jsonscript) OR MOD(OCCURS(["],jsonscript),2)<>0
    MESSAGEBOX('{,[" 未成对!')
    RETURN .f.
ENDIF
*!* 12/28修改,加入代码完成对“:”(:)“,”(,)字符的判断并替换
ncount=0
n=OCCURS(["],jsonscript)
FOR i=1 TO n/2
    ccontent=STREXTRACT(jsonscript,["],["],2*i-1)
    *!* 替换“:”
    ncount=OCCURS([:],ccontent)
    IF ncount<>0
        ctemp=STRTRAN(ccontent,[:],"& # 58")
        jsonscript=STRTRAN(jsonscript,ccontent,ctemp)
    ENDIF
    *!*
    *!* 替换“,”
    ccontent=STREXTRACT(jsonscript,["],["],2*i-1)
    ncount=OCCURS([,],ccontent)
    IF ncount<>0
        ctemp=STRTRAN(ccontent,[,],"& # 44")
        jsonscript=STRTRAN(jsonscript,ccontent,ctemp)
    ENDIF   
    *!*        
ENDFOR
*!*

this.jsscript=jsonscript
*****
*!* 先检查是不是包含json数组的复合结构
*!* 提取所有json数组,并以AJSON+编号予以替换,保存于jsonarraylist中
n=0
DO WHILE .t.
    IF OCCURS("[",jsonscript)>0 &&说明json结构里有数组
        DIMENSION jsonarraylist[n+1
] &&用以保存json数组的内容
        nleft =AT("[",jsonscript) &&确定第一个 "[" 的位置
        i=0
        *!*  下面这段代码确定与第一个 "[" 匹配的 "
]" 的位置
        DO WHILE .t.
            i=i+1
            nright=AT("]",jsonscript,i)
            ccontent=SUBSTR(jsonscript,nleft,nright-nleft+1)
            IF OCCURS("[",ccontent)<>OCCURS("]",ccontent)
                LOOP
            ELSE
                EXIT
            ENDIF
        ENDDO
        *!*
*!*            ccontent=SUBSTR(jsonscript,nleft,nright-nleft+1) &&提取json数组的整体内容
        n=n+1
        jsarray="AJSON_"+TRANSFORM(n) &&准备替换掉数组的内容
        jsonscript=STRTRAN(jsonscript,ccontent,jsarray)
        jsonarraylist(n)=ccontent
        LOOP
    ELSE
        *!* 2024/12.22 漏掉一种可能,没有数组,但是有json嵌套
        IF OCCURS("{",jsonscript)>1
            DIMENSION jsonarraylist[n+1]
            nleft=AT("{",jsonscript,2)
            nright=AT("}",jsonscript,1)
            ccontent=SUBSTR(jsonscript,nleft,nright-nleft+1)
            n=n+1
            jsarray="OJSON_"+TRANSFORM(n)
            jsonscript=STRTRAN(jsonscript,ccontent,jsarray)
            jsonarraylist(n)=ccontent
            loop
        ELSE
            EXIT
        ENDIF
        *!*
    ENDIF
ENDDO
*!*

*!* 对替换所有数组后的json结构进行解析
DIMENSION atemp[1]
ncount=ALINES(atemp,jsonscript,9,",")
FOR i=1 TO ncount
    ckey  =ALLTRIM(STREXTRACT(STREXTRACT(atemp[i],"",":"),["],["]))
    cvalue=STRtr(STREXTRACT(atemp[i],":",""),["],[])
    cvalue=ALLTRIM(STRTRAN(cvalue,"}",""))
    *!* 12/28加入,复原可能存在的“:”,“,”
    cvalue=STRTRAN(cvalue,"& # 44",[,])
    cvalue=STRTRAN(cvalue,"& # 58",[:])
    *!*
    this.Add(cvalue,ckey)
ENDFOR   
*!*

*!*    *!* 如果是复合结构,则复原json数组内容
*!*    IF VARTYPE(jsonarraylist)!="U"
*!*        FOR i=1 TO ALEN(jsonarraylist)
*!*            cvalue="AJSON_"+TRANSFORM(i)
*!*            FOR j=1 TO this.count
*!*                IF TRANSFORM(this.Item(j))=cvalue
*!*                    ckey=this.GetKey(j)
*!*                    this.Remove(ckey)
*!*                    this.add(jsonarraylist[i],ckey)               
*!*                ENDIF
*!*            ENDFOR

*!*        ENDFOR
*!*    ENDIF   
*!*    *!*
*!* 如果是复合结构,则复原json数组内容
IF VARTYPE(jsonarraylist)!="U"
    FOR i=1 TO ALEN(jsonarraylist)
        cvalue="AJSON_"+TRANSFORM(i)
        m=this.count
        FOR j=1 TO m
            IF TRANSFORM(this.Item(j))=cvalue
                ckey=this.GetKey(j)
                this.Remove(ckey)
                &ckey=NEWOBJECT([jsonarray],[myclass])
                &ckey..name=ckey
                &ckey..parse(jsonarraylist[i])
                IF j=m
                    this.add(&ckey,ckey)
                ELSE
                    this.Add(&ckey,ckey,j)
                ENDIF                    
            ENDIF
        ENDFOR
    ENDFOR

    FOR i=1 TO ALEN(jsonarraylist)
        cvalue="OJSON_"+TRANSFORM(i)
        m=this.count
        FOR j=1 TO m
            IF TRANSFORM(this.Item(j))=cvalue
                ckey=this.GetKey(j)
                this.Remove(ckey)
                &ckey=NEWOBJECT([json],[myclass])
                &ckey..name=ckey
                &ckey..parse(jsonarraylist[i])
                IF j=m
                    this.add(&ckey,ckey)
                ELSE
                    this.Add(&ckey,ckey,j)
                ENDIF                    
            ENDIF
        ENDFOR
    ENDFOR

ENDIF   
*!*


json.getvalue代码也要稍作修改
程序代码:

PARAMETERS ckey,noccurrence
LOCAL i,j,nleft,nright,cchar,cvalue,n
cvalue=""

IF PARAMETERS()=1
    noccurrence=1
ENDIF
   
n=AT(ckey,this.jsscript,noccurrence)
IF n>0
    *!* 确定指定json属性的值的起始位置
    nleft=n+LEN(ckey)
    DO WHILE .t.
        nleft=nleft+1
        cchar=SUBSTR(this.jsscript,nleft,1)
        IF cchar=":"
            nleft=nleft+1 &&从":"后面一个字符开始
            EXIT
        ELSE
            LOOP
        ENDIF
    ENDDO            
    *!*
    DO WHILE .t.
        cchar=ALLTRIM(SUBSTR(this.jsscript,nleft,1))
        IF cchar=" " &&空格,冒号后面可能不小心输入了空格,剔除它
            nleft=nleft+1
            LOOP
        ELSE
            EXIT
        ENDIF
    ENDDO

    IF cchar="[" &&说明是数组
        *!*确定与"["匹配的"
]"的位置
        i=0
        DO WHILE .t.
            i=i+1
            nright=AT("]",this.jsscript,i)
            IF nright<nleft
                LOOP
            ELSE
                cvalue=SUBSTR(this.jsscript,nleft,nright-nleft+1)
                IF OCCURS("[",cvalue)=OCCURS("]",cvalue)
                    EXIT
                ELSE
                    LOOP
                ENDIF        
            ENDIF        
        ENDDO   
    ELSE &&否则就是普通数值
        *!* 亦有可能是json嵌套,2024/12/22 加入json嵌套解读代码
        IF cchar="{" &&说明值是一个json结构,然后找出“}”的位置
            nright=nleft
            DO WHILE .t.
                nright=nright+1
                cchar=SUBSTR(this.jsscript,nright,1)
                IF cchar="}"
                    cvalue=SUBSTR(this.jsscript,nleft,nright-nleft+1)
                    EXIT
                ELSE
                    LOOP
                ENDIF

            ENDDO            
        ELSE &&然后才是普通数值
            cscript=this.jsscript+","
            j=0
            DO WHILE .t.
                j=j+1
                nright=AT(",",cscript,j)
                IF nright<nleft
                    LOOP
                ELSE
                    cvalue=SUBSTR(cscript,nleft,nright-nleft)
                    cvalue=STRTRAN(cvalue,["],"")
                    cvalue=STRTRAN(cvalue,[}],"")
                    cvalue=ALLTRIM(cvalue)
                    *!* 12/28加入,复原可能的“:”“,”
                    cvalue=STRTRAN(cvalue,"& # 44",",")
                    cvalue=STRTRAN(cvalue,"& # 58",":")
                    *!*
                    EXIT
                ENDIF
            ENDDO
        ENDIF
        *!*   
    ENDIF
ENDIF

RETURN cvalue   


运行结果:
只有本站会员才能查看附件,请 登录


[此贴子已经被作者于2024-12-28 13:04编辑过]

1 回复
#2
schtg2024-12-28 20:29
谢谢!
1