ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 25113|回复: 37

[分享] JSON 直写 Range,轻松完成格式转换。

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2015-9-7 10:07 | 显示全部楼层 |阅读模式
本帖已被收录到知识树中,索引项:脚本语言应用
本帖最后由 coby001 于 2015-9-7 11:08 编辑

JSON 直写 Range,轻松完成格式转换。

原题在此:
如何用Excel VBA解析JSON数据(这个对我真的好难!)
http://club.excelhome.net/thread-1227992-1-1.html
--------------------
JSON数据格式如下:
{"1":{"id":1,"pid":"3600","cid":"1376","name":"\u8702\u871c\u67da\u5b50\u8336 Honey Citron Tea","price":"30","mprice":"0","ctype":"0","is_discount":"1","second_discount":"1","is_free":0,"cost":"0","num":"1","type":"","practice_id":"6"},"2":{"id":2,"pid":"3536","cid":"1370","name":"\u62ff\u94c1 Caffe Latte","price":"32","mprice":"0","ctype":"0","is_discount":"1","second_discount":"1","is_free":0,"cost":"0","num":"1","type":""}}

------------
此 json 的难点在哪里呢?
看前 5 个字符:{"1":
用了数字 1 和 2 作为 key,而 数字 在多数编程语言里不是合法的标示符。想用 obj.1 来索引对象中的数据,编译器就报错!
在 js 里有 方括号 [] 可以处理这种问题, 例如:obj [1] 或者 obj ["1"] ,这样能正确操作对象中的数据了。
但是,VAB里没这个 [] 语法啊。肿么办~~~
这时,该 VBA的 CallByName() 函数来救场了~~ 这个函数能象 js里的 [] 一样把各种奇形怪状的key逮住。
看例子:

  • Sub jsonCBN()    '方法二
  •     Dim aa, y As Object, x As Object
  •     Dim name, id   ' 这里重新定义 json 中的 key,避免vba自动改大小写而失败。
  •     Set x = CreateObject("ScriptControl")
  •     x.Language = "JScript"
  •     aa = Me.[a1] ' JSON数据在 A1
  •     Set y = x.eval("a=" & aa) ' 返回解析后的json对象
  •     Dim iRow&
  •     For iRow = 1 To 2
  •         With CallByName(y, iRow, VbGet)
  •             Debug.Print .id, .pid, .name
  •         End With
  •     Next
  • End Sub


效果图,点击看大图

评分

3

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-9-7 10:39 | 显示全部楼层
CallByName() 的详细用法,请在EH里搜索就能找到~ 在此不赘述。
看看1楼的标题,不是说JSON 直写 Range么~ 怎么丢个 CallByName()就了事?


----------
当然不是到此为止,因为 CallByName() 有缺点啊~ 用的不是很爽~
当 json 中的 key 改变后,CallByName() 不太好处理,用起来很别扭。


有么有更好的办法呢?
有!
ScriptControl 对象 有个方法:AddObject

看看它的说明:
Sub AddObject(Name As String, Object As Object, [AddMembers As Boolean = False])
    MSScriptControl.ScriptControl 的成员
    Add an object to the global namespace of the scripting engine
--------
可以给脚本引擎的全局命名空间添加一个 对象 哟。然后可以用脚本操作此对象。

对象!我们可爱的Range 就是个 对象啊~
来看例子吧:

  • Sub JsonToRng()    'JSON 直写 Range
  •     Dim sJson$, js$
  •     sJson = Me.[a1] ' JSON 数据在A1
  •     js = "var r,k,row=c=1,d={};for(r in j){row++;for(k in j[r]){if(!d[k]){d[k]=c++;rng(1,d[k])=k;}rng(row,d[k])= j[r][k];}}"
  •     js = "j=" & sJson & ";" & js
  •     With CreateObject("ScriptControl")
  •         .Language = "JScript"
  •         .AddObject "rng", Me.Cells(3, "A")  ' A3 是起始单元格,可以改为别的单元格
  •         .eval (js)
  •     End With
  • End Sub


点击看大图
jsonToRng.gif

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-9-7 11:02 | 显示全部楼层
    js = "var r,k,row=c=1,d={};for(r in j){row++;for(k in j[r]){if(!d[k]){d[k]=c++;rng(1,d[k])=k;}rng(row,d[k])= j[r][k];}}"
    js = "j=" & sJson & ";" & js


对这段 js 做个说明:


  • //j= sJson , rng 是用 AddObject 加入的单元格
  • var r, k,
  •     row = c = 1, //起始单元格的相对 行、列 偏移
  •     d = {}; //空字典
  • for (r in j) {
  •     row++; //行 偏移
  •     for (k in j[r]) {
  •         if (!d[k]) {  //如果key不存在,则添加 key 和 标题行
  •             d[k] = c++; //列 偏移 和 key 相关联
  •             rng(1, d[k]) = k; //把key写到 标题行
  •         }
  •         rng(row, d[k]) = j[r][k]; //把Value写到 单元格
  •     }
  • }


TA的精华主题

TA的得分主题

 楼主| 发表于 2015-9-7 11:16 | 显示全部楼层
本帖最后由 coby001 于 2015-9-8 07:25 编辑

在来一个例子,这次是是个数组,它的元素是 字典,仍然用 2楼的 JsonToRng 方法搞定。
--------------------
原题:
如何用Excel VBA解析JSON数据
http://club.excelhome.net/thread-1228326-1-1.html


--------------------
整理出 JSON数据格式如下:
[ {'sn':'篮球','kz':'birinxi','cp':'baishi'} , {'sn':'报龄','kz':'kazet','py':'baoling'} , {'sn':'编简','kz':'taryh','py':'bianjian'} , {'sn':'白兆灯','kz':'tokا','py':'biannianshi'} , {'sn':'杠铃','kz':'dop','py':'bieshi'}]
============
将上面这段JSON 字串贴到 A1 中,2楼的代码不变,
看看效果:点击看大图
jsonToRng-2.gif

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-9-8 07:34 | 显示全部楼层
JsonToRng 方法可以轻松搞定 二维结构的 json ,标题行都是自适应的,不用特别处理。
还在为不能处理 Json 而烦恼吗?~~
{:soso_e120:}

TA的精华主题

TA的得分主题

发表于 2015-9-8 16:59 | 显示全部楼层
coby001 发表于 2015-9-8 07:34
JsonToRng 方法可以轻松搞定 二维结构的 json ,标题行都是自适应的,不用特别处理。
还在为不能处理 Json ...

大神,哪里有JScript的基础知识学习,提供个链接吧,看那一串串字符串真是头晕啊

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-9-8 17:27 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2015-9-8 17:38 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2015-9-8 17:55 | 显示全部楼层
LIUZHU 发表于 2015-9-8 16:59
大神,哪里有JScript的基础知识学习,提供个链接吧,看那一串串字符串真是头晕啊

有什么好晕的。
JSON 用来表示 数组和对象。
大括号{}表示对象,中括号[]表示数组。

["1","2","3"]   这个就表示一个数组,里面有元素 1、2、3

{"a":1,"b":2,"c":3}  表示一个对象,a b c 可以看成对象的属性,1 、2、3 分别为他们的值。属性间用逗号分割,属性和对应值之间用冒号分割。 字符型的值用引号引住,数字型的值可不用引号。

[{"a":"一","b":"二"},{"c":"三","d":"四"},{"e":"五","f":"六"}]  表示一个数组中有三个对象,每个对象中还有两个属性。

和VBA一样,这两个可以互相嵌套。
比如:  {"1":{"id":1},"2":{"id":2}}  表示一个大的对象里面有两个属性,每个属性的值又分别是一个对象   对象1的值为{"id":1}, 对象2的值为{"id":2}。
这个其实就和一楼的
{
    "1":{"id":1,"pid":"3600","cid":"1376","name":"\u8702\u871c\u67da\u5b50\u8336 Honey Citron   Tea","price":"30","mprice":"0","ctype":"0","is_discount":"1","second_discount":"1","is_free":0,"cost":"0","num":"1","type":"","practice_id":"6"},
    "2":{"id":2,"pid":"3536","cid":"1370","name":"\u62ff\u94c1 Caffe Latte","price":"32","mprice":"0","ctype":"0","is_discount":"1","second_discount":"1","is_free":0,"cost":"0","num":"1","type":""}
}
是一样的,只是属性1 和属性2 的对象的属性多了几个而已。很明显,蓝色是属性1的值,橙色是属性1的值的对象的属性。

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2015-9-8 17:59 | 显示全部楼层
无标题.jpg
这样写都看得懂了吧?
其实了解之后自己用字符串处理的方式就可以解析了。

评分

1

查看全部评分

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-18 21:32 , Processed in 0.043710 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表