在Wonderware ArchestrA/Quickscript.NET中反序列化JSON的标准最佳方法
我之前在ArchestrA IDE的QuickScript.NET环境里遇到过完全一样的问题——常用的JSON处理类(JavaScriptSerializer、DataContractJsonSerializer甚至Newtonsoft.Json)要么找不到对应的命名空间,要么直接不可用。结合这个环境的限制,我整理了几个实用的解决办法:
1. 手动解析(适合简单JSON结构)
如果你的JSON格式比较固定且不复杂(比如只有扁平的键值对,没有嵌套对象/数组),直接用字符串操作提取值是最直接的方式,不需要依赖任何额外类。
举个例子,解析如下JSON:
{"DeviceName":"Pump_01","Pressure":85.6,"IsRunning":true}
对应的QuickScript.NET代码(VB.NET):
Dim rawJson As String = "{""DeviceName"":""Pump_01"",""Pressure"":85.6,""IsRunning"":true}" ' 提取DeviceName字符串 Dim nameStart = rawJson.IndexOf("""DeviceName"":""") + 14 Dim nameEnd = rawJson.IndexOf("""", nameStart) Dim deviceName As String = rawJson.Substring(nameStart, nameEnd - nameStart) ' 提取Pressure数值 Dim pressureStart = rawJson.IndexOf("""Pressure"":") + 11 Dim pressureEnd = rawJson.IndexOf(",", pressureStart) Dim pressure As Double = Double.Parse(rawJson.Substring(pressureStart, pressureEnd - pressureStart)) ' 提取IsRunning布尔值 Dim runningStart = rawJson.IndexOf("""IsRunning"":") + 13 Dim runningEnd = rawJson.IndexOf("}", runningStart) Dim isRunning As Boolean = Boolean.Parse(rawJson.Substring(runningStart, runningEnd - runningStart))
这种方法的缺点是灵活性差,一旦JSON结构变化就得修改代码,但胜在简单直接,没有任何依赖。
2. 使用正则表达式解析(适合中等复杂度结构)
如果JSON有少量嵌套或者字段较多,可以用System.Text.RegularExpressions(这个命名空间在QuickScript.NET里是可用的)来匹配键值对,比纯手动字符串操作更灵活。
示例代码:
Imports System.Text.RegularExpressions Dim rawJson As String = "{""DeviceName"":""Pump_01"",""Pressure"":85.6,""IsRunning"":true,""Tags"":[""Flow"",""Level""]}" ' 匹配字符串类型的键值对 Dim stringMatches As MatchCollection = Regex.Matches(rawJson, """(\w+)"":""([^""]+)""") For Each match As Match In stringMatches Dim key As String = match.Groups(1).Value Dim value As String = match.Groups(2).Value ' 处理字符串值,比如打印或存储 ' Console.WriteLine($"{key}: {value}") Next ' 匹配数字/布尔类型的键值对 Dim numBoolMatches As MatchCollection = Regex.Matches(rawJson, """(\w+)"":([\d\.truefalse]+)") For Each match As Match In numBoolMatches Dim key As String = match.Groups(1).Value Dim valueStr As String = match.Groups(2).Value Select Case valueStr.ToLower() Case "true", "false" Dim boolVal As Boolean = Boolean.Parse(valueStr) ' 处理布尔值 Case Else If valueStr.Contains(".") Then Dim doubleVal As Double = Double.Parse(valueStr) ' 处理浮点数 Else Dim intVal As Integer = Integer.Parse(valueStr) ' 处理整数 End If End Select Next ' 匹配简单数组(比如字符串数组) Dim arrayMatches As Match = Regex.Match(rawJson, """Tags"":\[([^\]]+)\]") If arrayMatches.Success Then Dim arrayItems As String() = arrayMatches.Groups(1).Value.Replace("""", "").Split(","c) ' 遍历数组元素 For Each item As String In arrayItems ' 处理数组项 Next End If
正则方法能覆盖大部分常见的JSON结构,但对于深度嵌套的复杂JSON(比如多层对象嵌套),正则会变得难以维护。
3. 嵌入轻量级JSON解析器(适合复杂JSON结构)
如果你的JSON结构复杂(多层嵌套对象、数组混合),前面两种方法就不太适用了。这时候可以找一个无外部依赖、纯VB.NET编写的轻量级JSON解析器,把它的代码直接复制到你的QuickScript.NET脚本中。
这类解析器通常是单文件的类,只依赖.NET基础类库(比如System.Collections.Generic),而这些在QuickScript.NET里都是可用的。你可以自己实现一个简单的解析器,或者找公开的开源代码(比如一些精简版的JSON解析器,不需要引用任何DLL)。
比如一个极简的解析器核心逻辑示例(你需要补充完整的辅助方法):
Imports System.Collections.Generic Public Class MiniJsonParser Private Shared Sub SkipWhitespace(ByVal json As String, ByRef index As Integer) While index < json.Length AndAlso Char.IsWhiteSpace(json(index)) index += 1 End While End Sub Private Shared Function ParseString(ByVal json As String, ByRef index As Integer) As String index += 1 ' 跳过开头的引号 Dim start = index While index < json.Length AndAlso json(index) <> """"c If json(index) = "\"c Then index += 1 ' 处理转义字符 index += 1 End While Dim result = json.Substring(start, index - start) index += 1 ' 跳过结尾的引号 Return result End Function Private Shared Function ParseObject(ByVal json As String, ByRef index As Integer) As Dictionary(Of String, Object) index += 1 ' 跳过开头的{ Dim dict As New Dictionary(Of String, Object)() SkipWhitespace(json, index) While index < json.Length AndAlso json(index) <> "}"c Dim key = ParseString(json, index) SkipWhitespace(json, index) index += 1 ' 跳过冒号 Dim value = ParseValue(json, index) dict.Add(key, value) SkipWhitespace(json, index) If json(index) = ","c Then index += 1 SkipWhitespace(json, index) End While index += 1 ' 跳过结尾的} Return dict End Function ' 补充ParseValue、ParseArray、ParseBoolean、ParseNull、ParseNumber等方法 Private Shared Function ParseValue(ByVal json As String, ByRef index As Integer) As Object SkipWhitespace(json, index) Select Case json(index) Case """"c : Return ParseString(json, index) Case "{"c : Return ParseObject(json, index) Case "["c : Return ParseArray(json, index) ' 需要实现ParseArray Case "t"c : Return ParseBoolean(json, index) ' 需要实现ParseBoolean Case "f"c : Return ParseBoolean(json, index) Case "n"c : Return ParseNull(json, index) ' 需要实现ParseNull Case Else : Return ParseNumber(json, index) ' 需要实现ParseNumber End Select End Function End Class
把完整的解析器代码嵌入后,你就可以像使用常规JSON库一样解析复杂JSON了:
Dim rawJson As String = "{""Device"":{""Name"":""Pump_01"",""Sensors"":[{""Type"":""Pressure"",""Value"":85.6},{""Type"":""Flow"",""Value"":12.3}]}}" Dim jsonObj As Dictionary(Of String, Object) = MiniJsonParser.ParseObject(rawJson, 0) ' 访问嵌套对象 Dim deviceName As String = DirectCast(jsonObj("Device"), Dictionary(Of String, Object))("Name")
这个方案的优势是能处理任意复杂的JSON结构,缺点是需要引入额外的代码,但因为是直接嵌入脚本,不需要依赖外部DLL,完全符合QuickScript.NET的环境限制。
内容的提问来源于stack exchange,提问作者mijiturka

