VB6 / VBA是否有JSON解析器?

44

我正在尝试在VB6中使用一个Web服务。该服务目前可以返回SOAP/XML消息或JSON,我控制着这个服务。但我无法确定VB6的SOAP类型(版本1)是否能够处理返回的object,而不是像stringint等简单类型那样处理。到目前为止,我还不能弄清楚我需要做什么才能让VB6处理返回的对象。

因此,我想将Web服务响应序列化为JSON字符串。VB6中是否存在JSON解析器?


我之前有一个答案,但现在我找到了更好的方法。http://exceldevelopmentplatform.blogspot.com/2018/01/vba-parse-json-safer-with-jsonparse-and.html - S Meaden
16个回答

47

请查看JSON.org,了解多种语言中最新的JSON解析器列表(请参见主页底部)。截至本篇写作时,您会看到链接到多个不同JSON解析器的链接,但是只有一个适用于VB6/VBA(其他是.NET):

  • VB-JSON

    • 当我尝试下载zip文件时,Windows 提示数据已损坏。但是我可以使用7-zip将文件提取出来。原来,在zip文件中的主“文件夹”未被Windows识别为文件夹,但是7-zip可以看到该主“文件夹”的内容,因此您可以打开它,然后相应地提取文件。
    • 这个VB JSON库的实际语法非常简单:

      Dim p As Object
      Set p = JSON.parse(strFormattedJSON)
      
      'Print the text of a nested property '
      Debug.Print p.Item("AddressClassification").Item("Description")
      
      'Print the text of a property within an array '
      Debug.Print p.Item("Candidates")(4).Item("ZipCode")
      
    • 注意:我必须通过 VBA 编辑器中的“工具”>“引用”添加“Microsoft Scripting Runtime”和“Microsoft ActiveX Data Objects 2.8”库作为参考。
    • 注意:VBJSON 代码实际上是基于一个 Google Code 项目 vba-json。不过,VBJSON 承诺从原版中修复了几个错误。

有没有一种方法可以使用VB-JSON传递一个类对象并返回相应的JSON字符串?谢谢! - Brian Behm
你如何循环遍历对象?假设p.Item("AddressClassification")包含3个项目。我该如何遍历这些项目? - Anon21
@AlexandreH.Tremblay 你应该能够像在VB6/VBA中循环遍历任何数组一样循环遍历这个项目。 - Ben McCormack
1
@BenMcCormack 你能看一下这个问题吗?https://dev59.com/5oTba4cB1Zd3GeqP0gkZ - Koray Tugay

15

在ozmike的解决方案基础上进行改进,但对我无效(Excel 2013和IE10)。 原因是我无法调用公开的JSON对象上的方法。 因此,它的方法现在通过附加到DOM元素的函数公开。 以前不知道这是可能的(一定是那个IDispatch东西),谢谢ozmike。

如ozmike所述,没有第三方库,只有30行代码。

Option Explicit

Public JSON As Object
Private ie As Object

Public Sub initJson()
    Dim html As String

    html = "<!DOCTYPE html><head><script>" & _
    "Object.prototype.getItem=function( key ) { return this[key] }; " & _
    "Object.prototype.setItem=function( key, value ) { this[key]=value }; " & _
    "Object.prototype.getKeys=function( dummy ) { keys=[]; for (var key in this) if (typeof(this[key]) !== 'function') keys.push(key); return keys; }; " & _
    "window.onload = function() { " & _
    "document.body.parse = function(json) { return JSON.parse(json); }; " & _
    "document.body.stringify = function(obj, space) { return JSON.stringify(obj, null, space); }" & _
    "}" & _
    "</script></head><html><body id='JSONElem'></body></html>"

    Set ie = CreateObject("InternetExplorer.Application")
    With ie
        .navigate "about:blank"
        Do While .Busy: DoEvents: Loop
        Do While .readyState <> 4: DoEvents: Loop
        .Visible = False
        .document.Write html
        .document.Close
    End With

    ' This is the body element, we call it JSON:)
    Set JSON = ie.document.getElementById("JSONElem")

End Sub

Public Function closeJSON()
    ie.Quit
End Function
以下测试从头构建一个 JavaScript 对象,然后将其转换为字符串。 接着,它解析对象并遍历其键。
Sub testJson()
    Call initJson

    Dim jsObj As Object
    Dim jsArray As Object

    Debug.Print "Construction JS object ..."
    Set jsObj = JSON.Parse("{}")
    Call jsObj.setItem("a", 1)
    Set jsArray = JSON.Parse("[]")
    Call jsArray.setItem(0, 13)
    Call jsArray.setItem(1, Math.Sqr(2))
    Call jsArray.setItem(2, 15)
    Call jsObj.setItem("b", jsArray)

    Debug.Print "Object: " & JSON.stringify(jsObj, 4)

    Debug.Print "Parsing JS object ..."
    Set jsObj = JSON.Parse("{""a"":1,""b"":[13,1.4142135623730951,15]}")

    Debug.Print "a: " & jsObj.getItem("a")
    Set jsArray = jsObj.getItem("b")
    Debug.Print "Length of b: " & jsArray.getItem("length")
    Debug.Print "Second element of b: "; jsArray.getItem(1)

    Debug.Print "Iterate over all keys ..."
    Dim keys As Object
    Set keys = jsObj.getKeys("all")

    Dim i As Integer
    For i = 0 To keys.getItem("length") - 1
        Debug.Print keys.getItem(i) & ": " & jsObj.getItem(keys.getItem(i))
    Next i

    Call closeJSON
End Sub

输出

Construction JS object ...
Object: {
    "a": 1,
    "b": [
        13,
        1.4142135623730951,
        15
    ]
}
Parsing JS object ...
a: 1
Length of b: 3
Second element of b:  1,4142135623731 
Iterate over all keys ...
a: 1
b: 13,1.4142135623730951,15

7

希望这对那些在搜索“vba json”后一直来到这个页面的人有所帮助。

我发现这个页面非常有用。它提供了几个与Excel兼容的VBA类,用于处理JSON格式的数据。


你会推荐哪一个? - Koray Tugay

7

由于Json只是一些字符串,因此如果我们能以正确的方式操纵它,那么就可以轻松处理它,无论结构多么复杂。我认为没有必要使用任何外部库或转换器来完成这个技巧。下面是一个示例,我使用字符串操作解析了json数据。

Sub GetJsonContent()
    Dim http As New XMLHTTP60, itm As Variant

    With http
        .Open "GET", "http://jsonplaceholder.typicode.com/users", False
        .send
        itm = Split(.responseText, "id"":")
    End With

    x = UBound(itm)

    For y = 1 To x
        Cells(y, 1) = Split(Split(itm(y), "name"": """)(1), """")(0)
        Cells(y, 2) = Split(Split(itm(y), "username"": """)(1), """")(0)
        Cells(y, 3) = Split(Split(itm(y), "email"": """)(1), """")(0)
        Cells(y, 4) = Split(Split(itm(y), "street"": """)(1), """")(0)
    Next y
End Sub

1
这对于简单的JSON对象可以工作。但对于具有嵌套集合和嵌套对象的对象来说,它不够通用。 - John Foll

6

VBA-JSON 是 Tim Hall 创作的开源项目,遵循 MIT 开源许可协议,并托管在 GitHub 上。它是 vba-json 的另一个分支,于 2014 年底出现。声称可以在 Mac Office 和 Windows 32 位和 64 位上运行。


包含在 VBA-Web 中,非常适合进行网络请求。也可以在 Mac 上使用。 - ComputerVersteher

6

更新:发现解析JSON的更安全方法,而非使用Eval,本博客文章显示Eval的危险...http://exceldevelopmentplatform.blogspot.com/2018/01/vba-parse-json-safer-with-jsonparse-and.html

虽然有些晚了,但最简单的方法是使用Microsoft Script Control。以下是一些示例代码,使用VBA.CallByName进行钻取。

'Tools->References->
'Microsoft Script Control 1.0;  {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx

Private Sub TestJSONParsingWithCallByName()

    Dim oScriptEngine As ScriptControl
    Set oScriptEngine = New ScriptControl
    oScriptEngine.Language = "JScript"

    Dim sJsonString As String
    sJsonString = "{'key1': 'value1'  ,'key2': { 'key3': 'value3' } }"


    Dim objJSON As Object
    Set objJSON = oScriptEngine.Eval("(" + sJsonString + ")")
    Debug.Assert VBA.CallByName(objJSON, "key1", VbGet) = "value1"
    Debug.Assert VBA.CallByName(VBA.CallByName(objJSON, "key2", VbGet), "key3", VbGet) = "value3"

End Sub

我实际上做了一系列有关JSON/VBA相关主题的问答。

问题1:在Windows上的Excel VBA中,如何缓解IDE的大小写行为破坏已解析JSON的点语法遍历的问题?

问题2:在Windows上的Excel VBA中,如何循环遍历已解析的JSON数组?

问题3:在Windows上的Excel VBA中,如何获取已解析JSON变量的字符串化JSON表示,而不是“[object Object]”?

问题4:在Windows上的Excel VBA中,如何获取JSON键来预防“运行时错误'438':对象不支持此属性或方法”?

问题5:在Windows上的Excel VBA中,对于已解析的JSON变量,这个JScriptTypeInfo是什么?


这应该是答案。 - lucid_dreamer
JSON键区分大小写(在oScriptEngine.Eval返回的VBA对象中,键不区分大小写) - drgs
2
这似乎在64位上无法工作,因为微软没有将其移植到64位! - RIBH

4

4

这里有一个“本地”的VB JSON库。

可以使用IE8+已经具备的JSON功能。这样您就不需要依赖于第三方库,它可能会过时或未经测试。

请在此处查看amedeus的另一种版本(链接)

Sub myJSONtest()


Dim oJson As Object
Set oJson = oIE_JSON() ' See below gets IE.JSON object

' using json objects
Debug.Print oJson.parse("{ ""hello"": ""world"" }").hello ' world
Debug.Print oJson.stringify(oJson.parse("{ ""hello"": ""world"" }")) ' {"hello":"world"}

' getting items
Debug.Print oJson.parse("{ ""key1"": ""value1"" }").key1 ' value1
Debug.Print oJson.parse("{ ""key1"": ""value1"" }").itemGet("key1") ' value1
Debug.Print oJson.parse("[ 1234, 4567]").itemGet(1) '  4567

' change  properties
Dim o As Object
Set o = oJson.parse("{ ""key1"": ""value1"" }")
o.propSetStr "key1", "value\""2"
Debug.Print o.itemGet("key1") ' value\"2
Debug.Print oJson.stringify(o) ' {"key1":"value\\\"2"}
o.propSetNum "key1", 123
Debug.Print o.itemGet("key1") ' 123
Debug.Print oJson.stringify(o) ' {"key1":123}

' add properties
o.propSetNum "newkey", 123 ' addkey! JS MAGIC
Debug.Print o.itemGet("newkey") ' 123
Debug.Print oJson.stringify(o) ' {"key1":123,"newkey":123}

' assign JSON 'objects' to properties
Dim o2 As Object
Set o2 = oJson.parse("{ ""object2"": ""object2value"" }")
o.propSetJSON "newkey", oJson.stringify(o2) ' set object
Debug.Print oJson.stringify(o) ' {"key1":123,"newkey":{"object2":"object2value"}}
Debug.Print o.itemGet("newkey").itemGet("object2") ' object2value

' change array items
Set o = oJson.parse("[ 1234, 4567]") '
Debug.Print oJson.stringify(o) ' [1234,4567]
Debug.Print o.itemGet(1)
o.itemSetStr 1, "234"
Debug.Print o.itemGet(1)
Debug.Print oJson.stringify(o) ' [1234,"234"]
o.itemSetNum 1, 234
Debug.Print o.itemGet(1)
Debug.Print oJson.stringify(o) ' [1234,234]

' add array items
o.itemSetNum 5, 234 ' add items! JS Magic
Debug.Print o.itemGet(5) ' 234
Debug.Print oJson.stringify(o) ' [1234,234,null,null,null,234]

' assign JSON object to array item
o.itemSetJSON 3, oJson.stringify(o2)  ' assign object
Debug.Print o.itemGet(3) '[object Object]
Debug.Print oJson.stringify(o.itemGet(3)) ' {"object2":"object2value"}
Debug.Print oJson.stringify(o) ' [1234,234,null,{"object2":"object2value"},null,234]


oIE_JSON_Quit ' quit IE, must shut down or the IE sessions remain.
Debug.Print oJson.stringify(o) ' can use after but but IE server will shutdown... soon
End Sub

你可以从VB中连接到IE.JSON。
创建一个名为oIE_JSON的函数。
Public g_IE As Object ' global


Public Function oIE_JSON() As Object


    ' for array access o.itemGet(0) o.itemGet("key1")
    JSON_COM_extentions = "" & _
            " Object.prototype.itemGet        =function( i ) { return this[i] }   ;            " & _
            " Object.prototype.propSetStr     =function( prop , val ) { eval('this.' + prop + '  = ""' + protectDoubleQuotes (val) + '""' )   }    ;            " & _
            " Object.prototype.propSetNum     =function( prop , val ) { eval('this.' + prop + '  = ' + val + '')   }    ;            " & _
            " Object.prototype.propSetJSON    =function( prop , val ) { eval('this.' + prop + '  = ' + val + '')   }    ;            " & _
            " Object.prototype.itemSetStr     =function( prop , val ) { eval('this[' + prop + '] = ""' + protectDoubleQuotes (val) + '""' )   }    ;            " & _
            " Object.prototype.itemSetNum     =function( prop , val ) { eval('this[' + prop + '] = ' + val )   }    ;            " & _
            " Object.prototype.itemSetJSON    =function( prop , val ) { eval('this[' + prop + '] = ' + val )   }    ;            " & _
            " function protectDoubleQuotes (str)   { return str.replace(/\\/g, '\\\\').replace(/""/g,'\\""');   }"

    ' document.parentwindow.eval dosen't work some versions of ie eg ie10?
     IEEvalworkaroundjs = "" & _
         " function IEEvalWorkAroundInit ()   { " & _
         " var x=document.getElementById(""myIEEvalWorkAround"");" & _
         " x.IEEval= function( s ) { return eval(s) } ; } ;"

    g_JS_framework = "" & _
      JSON_COM_extentions & _
      IEEvalworkaroundjs

    ' need IE8 and DOC type
    g_JS_HTML = "<!DOCTYPE html>  " & _
         " <script>" & g_JS_framework & _
                  "</script>" & _
         " <body>" & _
         "<script  id=""myIEEvalWorkAround""  onclick=""IEEvalWorkAroundInit()""  ></script> " & _
                 " HEllo</body>"

On Error GoTo error_handler

' Create InternetExplorer Object
Set g_IE = CreateObject("InternetExplorer.Application")
With g_IE
    .navigate "about:blank"
    Do While .Busy: DoEvents: Loop
    Do While .ReadyState <> 4: DoEvents: Loop
    .Visible = False ' control IE interface window
    .Document.Write g_JS_HTML
End With

Set objID = g_IE.Document.getElementById("myIEEvalWorkAround")
objID.Click ' create  eval
Dim oJson As Object

'Set oJson = g_IE.Document.parentWindow.Eval("JSON") ' dosen't work some versions of IE
Set oJson = objID.IEEval("JSON")

Set objID = Nothing
Set oIE_JSON = oJson

Exit Function
error_handler:
MsgBox ("Unexpected Error, I'm quitting. " & Err.Description & ".  " & Err.Number)
g_IE.Quit
Set g_IE = Nothing

End Function

Public Function oIE_JSON_Quit()
         g_IE.Quit
         Exit Function
End Function

如果您觉得有用,请点赞


无法使用Excel 2013和IE10:无法调用返回的JSON对象上的方法。我所能做的就是 cstr(oJson),它确实返回了 _[object JSON]_。 - Wolfgang Kuehn
谢谢。我没有2013版本进行测试,但是一旦我有了,我会研究一下。如果你能找到解决方法,请告诉我们。 - ozmike

2
理解这是一篇旧文章,但我最近在为一个老的VB6应用程序添加网络服务消费时偶然发现了它。 接受的答案(VB-JSON)仍然有效并且似乎可以工作。 然而,我发现Chilkat已经更新包括REST和JSON功能,使其成为一个一站式(尽管需要付费)工具。 他们甚至有一个在线代码生成器,生成解析复制粘贴的JSON数据的代码。 JsonObject链接 代码生成器链接

2
我建议使用一个 .Net 组件。你可以通过 Interop 在 VB6 中使用 .Net 组件 - 这里有一个教程。我猜 .Net 组件比为 VB6 开发的任何东西更可靠且得到更好的支持。
在 Microsoft .Net 框架中有一些组件,如 DataContractJsonSerializerJavaScriptSerializer。你也可以使用第三方库,如 JSON.NET

谢谢您的建议。您提出了一个很好的观点,即.NET组件将比VB6中的任何内容得到更好的支持。这当然是事实。然而(我可能错了),JSON足够简单,即使是VB6也不应该有问题。我提到的VB-JSON代码迄今为止运行良好。 - Ben McCormack
1
@Ben JSON很简单,但你说谷歌代码项目作为起点仍然存在几个错误,所以仍有可能出错。 - MarkJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接