简单的JSON编辑器






4.88/5 (9投票s)
从基于文件的JSON字符串构建解析树,并允许您以树形或字符串形式进行编辑。
引言
本项目描述了一个简单的 JSON string 编辑器。它还描述了各种有用窗口控件的简单用法 - TreeView、MenuBar 和 Context menu。
在很长一段时间里,我一直从这个网站获得了极大的便利,现在终于能够回馈一些东西,即使它很简单。
背景
我一直在逐步转向 JSON,既作为文件存储范式,也作为异构系统(特别是桌面/移动和嵌入式系统)之间共享对象范式的基础。使用文本编辑器跟踪多个文件中的大型 JSON 对象非常麻烦,所以我最终决定编写一个 JSON 文件编辑器。
搜索在 CodeProject 上没有找到类似的工程,尽管这个版本还有很长的路要走,但它是第一个可用的版本。
Using the Code
代码相对简单。一个窗体,两个标签页支持 TreeView 和 TextView。切换标签页可以将 JSON string 转换为 JSON 解析树,反之亦然。用户可以编辑树视图或文本视图。


我使用了基于 Mehdi Gholam 的项目的 JSON 解析器,并进行了一些调整,以获得 实用性修复,甚至 更多速度。
除了基本调整之外,我还添加了一组基本的 JSON 值类。这些类对于在重复的序列化/反序列化操作中保留 JSON 类型至关重要。
有关 JSON 规范,请参阅:www.json.org。JSON string 定义了:
- JSON 对象,一组名称/值对,其中“name”是string,“value”是任何 JSON 值,或者
- JSON 数组,一个有序的 JSON 值列表。
有 7 种定义的 JSON 值:
- string、- number、- true、- false、- null、- object、- array
其中,string、number、true、false、null 可以被视为“基本值”,而 object 和 array 被视为“复合值”。
复合值是 JSON 值的结构化集合,例如:
    { "name" : "this is the value" }
    { "name" : 123.45 }
    { "name" : { "object" : 123 } }
    [ "string", 1234, true, false, null, { "object" : 123 } ]
    { "name" : [ "string", 1234, true, false, null, { "object" : 123 } ] }
Mehdi 的原始代码将所有基本 JSON 值转换为 C# 类型 'string',并且原始 JSON 类型信息丢失了。在序列化/反序列化时,有时重要的是不要丢失基本值类型的跟踪,因此我扩展了 *JSON.cs* 实现以保留原始值类型信息。这样做会以极低的吞吐量损失为代价来创建派生对象。
主要的添加是在 *JSON.cs* 中的一组基本类类型,如下所示:
    public class jsonValue
    public class jsonBoolean : jsonValue
    public abstract class jsonNumber : jsonValue
    public class jsonInteger : jsonNumber
    public class jsonReal : jsonNumber
基本值 'null' 被处理为没有派生类型的 jsonValue。
这些类具有一组隐式运算符,允许像这样编写代码:
jsonInteger a = 1;
jsonInteger b = "1";
jsonNumber c = "1";
jsonNumber d = 1;
jsonNumber e = 1.234;
jsonNumber f = "1.234";
jsonReal g = 1.5;
jsonReal h = "1.6";
string s = (string) a;
string s1 = (string) d;
string s2 = (string) g;
JSON 要求所有 string 值都必须用引号括起来,但任何其他值都保持不带引号。因此,除了标准的 ToString() 方法外,每个类还有一个 Emit() 方法,允许值正确地作为 JSON string 输出。
ToString() 用于内部检查值的内容,而 Emit() 用于将更改的数据输出到 JSON 派生的 string。以下是 jsonString 的两个方法:
public override string ToString()
{
    return value.ToString();
}
public override string Emit()
{
    return "\"" + value + "\"";
} 
所有其他细节都在 MainForm 代码中处理。这并非最优雅,但最透明。树处理只有一个技巧,ArrayList 节点被像键值对一样处理,但没有键。此外,Node.Tag 字段用于存储所有对象,无论其类型如何。然而,作为 C# 对象,JSON 对象和 JSON ArrayLists 看起来是相同的,并且只有一个 Tag 字段,我确实应该找到一种更简洁的方法来处理这种歧义。目前,Node.Text 字段用于区分,这有点晦涩。
最糟糕的例子可能是 scanTree() ,它扫描树以输出 JSON string。
private void scanTree(TreeNode t)
  {
  foreach (TreeNode o in t.Nodes)
        {
        if (o.Nodes.Count == 0)
           {
           // leaf node
           for (int i = 0; i < indentCount; i++)
              sb.Append(indentString);
              
           // figure object (named) or array (no name)
           string[] s = o.Text.Split(':');
           if ((s[0] = s[0].Trim()) != "")
              // not an array, so emit the name
              sb.Append("\"" + s[0] + "\" : ");
              
           // emit the value string
           sb.Append(((jsonValue)o.Tag).Emit());
           endLine(",");
           }
        else
           {
           newLine("\"" + o.Text + "\" : ");
           indent((string)o.Tag);
           scanTree(o);
           dedent(((string)o.Tag)[0] == '[' ? "]," : "},");
           }
        }
   } 
如您所见,它使用 Node.Text string 的格式来区分对象(总是有名称)和数组(从没有名称)。
也许有人可以建议一种更优雅的方法来处理这个问题 - 也许继续派生类以包括 jsonObject 和 jsonArray?
关注点
我主要是嵌入式系统方面的 C 语言开发者。每次我接触 C#,都是为了完成一些有助于嵌入式设备操作的事情。这往往导致对该语言的非常临时的知识,通过疯狂地翻阅食谱向前推进 10 步,又因为我忘记了这一切而向后退 9 步。
历史
- V1.00 2011 年 11 月 - 初稿


