简单的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 月 - 初稿