跟我一起学微信公众平台开发(二)
不好意思,因为不是全职程序员,没有及时更新,这篇虽是第二篇,但是跟微信公众号没有关系,只能算是番外篇。。。这篇主要是讲如何用foxpro写json解析程序,纯vfp代码,没有dll,fll库~
由于对于你的请求微信公众号返回的是json格式的,所以了解json格式是必须的。
主要思路:
1,把json结构看做一个collection,ckey就是json的属性;cvalue就是json的属性值,json的属性不可重复。
2,构建一个数组类jsonarray,对应于json的数组,数组的元素可以是任意值,也可以是json本身。
3,json类有3个重要的方法,
a),json.parse 解析json
b),json.generate 生成json脚本
c),json.getvalue 根据给定的属性名返回属性值,如果值是数组,则返回整个数组的脚本。
4,使用add方法,添加属性及属性值
5,使用remove方法,删除属性及属性值
类代码如下:
程序代码:
************************************************** *-- 类: json (d:\documents\visual foxpro 项目\myclass.vcx) *-- 父类: collection *-- 基类: collection *-- 时间戳: 12/21/24 09:19:08 PM * DEFINE CLASS json AS collection Height = 23 Width = 23 *-- 生成的json脚本 jsscript = "" Name = "json" *-- 返回json结构中指定属性的值。 PROCEDURE getvalue PARAMETERS ckey,noccurrence 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 &&否则就是普通数值 j=0 DO WHILE .t. j=j+1 nright=AT(",",this.jsscript,j) IF nright<nleft LOOP ELSE cvalue=SUBSTR(this.jsscript,nleft,nright-nleft) cvalue=STRTRAN(cvalue,["],"") cvalue=STRTRAN(cvalue,[}],"") cvalue=ALLTRIM(cvalue) EXIT ENDIF ENDDO ENDIF ENDIF RETURN cvalue ENDPROC *-- 解析json结构。 PROCEDURE parse LPARAMETERS jsonscript 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 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 EXIT 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,"}","")) 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 ENDIF *!* ENDPROC *-- 生成json脚本 PROCEDURE generate LOCAL cscript,ckey,cvalue,oref,i cscript="" IF this.Count>0 FOR i=1 TO this.Count ckey=this.GetKey(i) IF VARTYPE(this.Item(i))="O" oref=this.Item(i) cvalue=oref.generate() ELSE cvalue=this.Item(i) ENDIF cscript=cscript+["]+ckey+[":]+IIF(LEFT(TRANSFORM(cvalue),1)="[",TRANSFORM(cvalue),["]+TRANSFORM(cvalue)+["])+"," ENDFOR cscript=[{]+SUBSTR(cscript,1,LEN(cscript)-1)+[}] ENDIF this.jsscript=cscript RETURN this.jsscript ENDPROC PROCEDURE Init ENDPROC ENDDEFINE * *-- EndDefine: json **************************************************
6,由于vfp不支持数组嵌套,所以就设计了一个数组类jsonarray,以便做到嵌套数组。
7,提供2两个重要的方法,
a),jsonarray.parse 解析json数组
b),jsonarray.generate 生成json数组脚本
另外提供了一组操作数组的函数,add,remove,copy,item,clear,set
类代码如下:
程序代码:
************************************************** *-- 类: jsonarray (d:\documents\visual foxpro 项目\myclass.vcx) *-- 父类: custom *-- 基类: custom *-- 时间戳: 12/21/24 10:50:10 PM * DEFINE CLASS jsonarray AS custom *-- Jsonarray数组成员数量。 count = 0 *-- json数组脚本 script = "" Name = "jsonarray" *-- Jsonarray数组 DIMENSION array[1] *-- 添加数组成员。 PROCEDURE add LPARAMETERS eExpr this.count= this.count + 1 dimension this.array[this.count] this.array[this.count] = eExpr return ENDPROC *-- 访问数组成员。 PROCEDURE item LPARAMETERS n return this.array[n] ENDPROC *-- 移除数组成员。 PROCEDURE remove LPARAMETERS eExpr IF TYPE(eExpr)="N" ADEL(this.array,eExpr) DIMENSION this.array(this.count-1) this.count=this.count-1 ELSE n=ASCAN(this.array,eExpr) IF n!=0 ADEL(this.array,n) DIMENSION this.array(this.count-1) this.count=this.count-1 ENDIF ENDIF ENDPROC *-- 清空数组。 PROCEDURE clear DIMENSION this.array[1] this.array[1]=.f. this.count=0 ENDPROC *-- 生成json数组文本。 PROCEDURE generate LOCAL oref,cvalue,i,cexpression cexpression="" IF this.count<>0 FOR i=1 TO this.count IF VARTYPE(this.item(i))="O" oref=this.item(i) cvalue=oref.generate() ELSE cvalue=this.item(i) ENDIF IF [{] $ cvalue cexpression=cexpression+cvalue+[,] ELSE cexpression=cexpression+["]+cvalue+["]+[,] ENDIF ENDFOR cexpression="["+LEFT(cexpression,LEN(cexpression)-1)+"]" ENDIF this.script=cexpression RETURN this.script ENDPROC *-- 从已知数组复制。 PROCEDURE copy PARAMETERS carrayname *调用该方法时数组变量参数前需加强制引用符号@ n=ALEN(carrayname) DIMENSION this.array(n) FOR i=1 TO n this.array(i)=carrayname(i) ENDFOR this.count=n ENDPROC *-- 设置数组项的值。 PROCEDURE set PARAMETERS nindex,eExpr this.array[nindex]=eExpr ENDPROC *-- 解读json数组结构。 PROCEDURE parse PARAMETERS cjsonarray LOCAL jsonobjectlist,nleft,right,i,ctemp,n,ii,ncount,nindex,oref ***** ***** 先检查是不是包含json结构的复合数组 ***** this.script=cjsonarray DIMENSION jsonobjectlist[1] n=0 DO WHILE .t. IF OCCURS("{",cjsonarray)>0 &&说明数组里有嵌套json结构 DIMENSION jsonobjectlist[2*n+2] &&用以保存可能的json结构 nleft=AT("{",cjsonarray) i=0 DO WHILE .t. i=i+1 nright=AT("}",cjsonarray,i) ctemp=SUBSTR(cjsonarray,nleft,nright-nleft+1) IF OCCURS("{",ctemp)<>OCCURS("}",ctemp) LOOP ELSE EXIT ENDIF ENDDO *!* 将json数组中的json结构用OJSON_开头的字符串替换,并保存在数组中 cjsonarray=STRTRAN(cjsonarray,ctemp,"OJSON_"+TRANSFORM(n+1)) *!* oref="OJSON_"+TRANSFORM(n+1) *!* &oref=NEWOBJECT([json],[myclass]) jsonobjectlist[2*n+1]="OJSON_"+TRANSFORM(n+1) *!* jsonobjectlist[2*n+1]=&oref jsonobjectlist[2*n+2]=ctemp *!* &oref..parse(ctemp) n=n+1 *!* LOOP ELSE EXIT &&没有json结构则退出循环。 ENDIF ENDDO ncount=ALINES(this.array,cjsonarray,9,[,]) FOR ii=1 TO ncount this.array[ii]=STRTRAN(this.array(ii),CHR(13),[]) this.array[ii]=STRTRAN(this.array(ii),CHR(9),[]) this.array[ii]=STRTRAN(this.array(ii),CHR(10),[]) this.array[ii]=STRTRAN(this.array(ii),["],[]) this.array[ii]=STRTRAN(this.array(ii),"[",[]) this.array[ii]=STRTRAN(this.array(ii),"]",[]) this.array[ii]=ALLTRIM(this.array[ii]) ENDFOR *!* *!* 复原json数组里的json结构 *!* IF ALEN(jsonobjectlist)>1 *!* FOR j=1 TO ALEN(jsonobjectlist) STEP 2 *!* nindex=ASCAN(this.array,jsonobjectlist[j]) *!* this.array[nindex]=jsonobjectlist[j+1] *!* ENDFOR *!* ENDIF *!* *!* *!* 复原json数组里的json结构 IF ALEN(jsonobjectlist)>1 FOR j=1 TO ALEN(jsonobjectlist) STEP 2 nindex=ASCAN(this.array,jsonobjectlist[j]) oref=this.array[nindex] &oref=NEWOBJECT([json],[myclass]) this.array[nindex]=&oref &oref..name=oref &oref..parse(jsonobjectlist[j+1]) *!* this.array[nindex]=jsonobjectlist[j+1] ENDFOR ENDIF *!* this.count=ncount ENDPROC ENDDEFINE * *-- EndDefine: jsonarray **************************************************
8,附上测试代码,你们可能需要适当修改,我这两个类是保存在myclass里面的。
程序代码:
*jsontest.prg* PUBLIC cjscript,ojson CLEAR cjscript='' SET TEXTMERGE TO memvar cjscript noshow \ { \ "test":123, \ "button":[ \ { \ "type":"click", \ "name":"今日歌曲", \ "key":"V1001_TODAY_MUSIC", \ "array":[111,"aaa","bbb"] \ }, \ { \ "name":"菜单", \ "sub_button":[ \ { \ "type":"view", \ "name":"搜索", \ "url":"http://www.\ }, \ { \ "type":"miniprogram", \ "name":"wxa", \ "url":"http://mp.weixin., \ "appid":"wx286b93c14bbf93aa", \ "pagepath":"pages/lunar/index" \ }, \ { \ "type":"click", \ "name":"赞一下我们", \ "key":"V1001_GOOD" \ }], \ "test":[111,222,333] \ }], \ "additive":"123456" \ } SET TEXTMERGE TO ojson=NEWOBJECT("json","myclass") *!* ojson.jsscript=cjscript *!* ?cjscript *!* *?EMPTY(ojson.getvalue("hello",4)) ojson.jsscript=cjscript ojson.parse(cjscript) cscript=ojson.getvalue("button") ojsa=NEWOBJECT([jsonarray],[myclass]) ojsa.parse(cscript) ?ojsa.generate() *!* FOR i=1 TO ojson.count *!* ?ojson.getkey(i) *!* ? "___" *!* IF VARTYPE(ojson(i))="O" *!* ?ojson(i).script *!* else *!* ?ojson(i) *!* ENDIF *!* ENDFOR *!* ?ojson.getvalue("sub_button",2)
运行环境:win7+vfp9.0(7423),本机编译通过。
[此贴子已经被作者于2024-12-21 23:15编辑过]