我正在构建一个从外部源获取运行时 JSON 消息的应用程序。
我对消息文本的结构一无所知。
我想获取这个 JSON 文本,将其渲染到树视图(或类似的 UI 相关),在我刚刚动态创建的树视图中编辑这个 JSON,然后将文本发送回源。
我真的不知道从哪里开始..有什么建议吗?
private void btn_Convert_MouseClick(object sender, MouseEventArgs e)
{
try
{
string json = rbt_display.Text;
JObject obj = JObject.Parse(json);
tvw_display.Nodes.Clear();
TreeNode parent = Json2Tree(obj);
parent.Text = "Root Object";
tvw_display.Nodes.Add(parent);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "ERROR");
}
}
private TreeNode Json2Tree(JObject obj)
{
//create the parent node
TreeNode parent = new TreeNode();
//loop through the obj. all token should be pair<key, value>
foreach (var token in obj)
{
//change the display Content of the parent
parent.Text = token.Key.ToString();
//create the child node
TreeNode child = new TreeNode();
child.Text = token.Key.ToString();
//check if the value is of type obj recall the method
if (token.Value.Type.ToString() == "Object")
{
// child.Text = token.Key.ToString();
//create a new JObject using the the Token.value
JObject o = (JObject)token.Value;
//recall the method
child = Json2Tree(o);
//add the child to the parentNode
parent.Nodes.Add(child);
}
//if type is of array
else if (token.Value.Type.ToString() == "Array")
{
int ix = -1;
// child.Text = token.Key.ToString();
//loop though the array
foreach (var itm in token.Value)
{
//check if value is an Array of objects
if (itm.Type.ToString() == "Object")
{
TreeNode objTN = new TreeNode();
//child.Text = token.Key.ToString();
//call back the method
ix++;
JObject o = (JObject)itm;
objTN = Json2Tree(o);
objTN.Text = token.Key.ToString() + "[" + ix + "]";
child.Nodes.Add(objTN);
//parent.Nodes.Add(child);
}
//regular array string, int, etc
else if(itm.Type.ToString() == "Array")
{
ix++;
TreeNode dataArray = new TreeNode();
foreach (var data in itm)
{
dataArray.Text = token.Key.ToString() + "[" + ix + "]";
dataArray.Nodes.Add(data.ToString());
}
child.Nodes.Add(dataArray);
}
else
{
child.Nodes.Add(itm.ToString());
}
}
parent.Nodes.Add(child);
}
else
{
//if token.Value is not nested
// child.Text = token.Key.ToString();
//change the value into N/A if value == null or an empty string
if (token.Value.ToString() == "")
child.Nodes.Add("N/A");
else
child.Nodes.Add(token.Value.ToString());
parent.Nodes.Add(child);
}
}
return parent;
}
sample json
{
"firstName": "John",
"lastName": "Smith",
"isAlive": true,
"age": 25,
"height_cm": 167.6,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [],
"spouse": null
}
注意:此示例使用 NewtonSoft Json。右键单击解决方案并单击管理 NuGet 包以安装参考。
此代码将处理 JArray 或 JObject 作为输入:
string jsonString = "your json string here";
string rootName = "root", nodeName = "node";
JContainer json;
try {
if (jsonString.StartsWith("["))
{
json = JArray.Parse(jsonString);
treeView1.Nodes.Add(Utilities.Json2Tree((JArray)json, rootName, nodeName));
}
else
{
json = JObject.Parse(jsonString);
treeView1.Nodes.Add(Utilities.Json2Tree((JObject)json, text));
}
}
catch(JsonReaderException jre)
{
MessageBox.Show("Invalid Json.");
}
public class Utilities
{
public static TreeNode Json2Tree(JArray root, string rootName = "", string nodeName="")
{
TreeNode parent = new TreeNode(rootName);
int index = 0;
foreach(JToken obj in root)
{
TreeNode child = new TreeNode(string.Format("{0}[{1}]", nodeName, index++));
foreach (KeyValuePair<string, JToken> token in (JObject)obj)
{
switch (token.Value.Type)
{
case JTokenType.Array:
case JTokenType.Object:
child.Nodes.Add(Json2Tree((JObject)token.Value, token.Key));
break;
default:
child.Nodes.Add(GetChild(token));
break;
}
}
parent.Nodes.Add(child);
}
return parent;
}
public static TreeNode Json2Tree(JObject root, string text = "")
{
TreeNode parent = new TreeNode(text);
foreach (KeyValuePair<string, JToken> token in root)
{
switch (token.Value.Type)
{
case JTokenType.Object:
parent.Nodes.Add(Json2Tree((JObject)token.Value, token.Key));
break;
case JTokenType.Array:
int index = 0;
foreach(JToken element in (JArray)token.Value)
{
parent.Nodes.Add(Json2Tree((JObject)element, string.Format("{0}[{1}]", token.Key, index++)));
}
if (index == 0) parent.Nodes.Add(string.Format("{0}[ ]", token.Key)); //to handle empty arrays
break;
default:
parent.Nodes.Add(GetChild(token));
break;
}
}
return parent;
}
private static TreeNode GetChild(KeyValuePair<string, JToken> token)
{
TreeNode child = new TreeNode(token.Key);
child.Nodes.Add(string.IsNullOrEmpty(token.Value.ToString()) ? "n/a" : token.Value.ToString());
return child;
}
}
你可以试试这段代码:
public class JsonTag
{
public JsonTag(JsonReader reader)
{
TokenType = reader.TokenType;
Value = reader.Value;
ValueType = reader.ValueType;
}
public JsonToken TokenType { get; set; }
public object Value { get; set; }
public Type ValueType { get; set; }
}
private void JsonToTreeview(string json)
{
tvwValue.BeginUpdate();
var parentText = string.Empty;
TreeNodeCollection parentNodes = tvwValue.Nodes;
TreeNode current = null;
tvwValue.Nodes.Clear();
var reader = new JsonTextReader(new StringReader(json));
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.None:
break;
case JsonToken.StartObject:
current = new TreeNode("{}") { Tag = new JsonTag(reader) };
parentNodes.Add(current);
parentNodes = current.Nodes;
break;
case JsonToken.StartArray:
current = new TreeNode("[]") { Tag = new JsonTag(reader) };
parentNodes.Add(current);
if (current.PrevNode != null)
{
if (((JsonTag)current.PrevNode.Tag).TokenType == JsonToken.PropertyName)
current.Parent.Text += "[]";
parentText = current.Parent.Text;
if (current.Parent.Parent.Text.Length > 2)
parentText = ", " + parentText;
current.Parent.Parent.Text = current.Parent.Parent.Text.Insert(current.Parent.Parent.Text.Length - 1, parentText);
}
parentNodes = current.Nodes;
break;
case JsonToken.StartConstructor:
break;
case JsonToken.PropertyName:
current = new TreeNode("\"" + reader.Value + "\" : ");
parentNodes.Add(current);
if (current.PrevNode != null)
current.PrevNode.Text += ",";
parentNodes = current.Nodes;
current = new TreeNode(reader.Value.ToString()) { Tag = new JsonTag(reader) };
parentNodes.Add(current);
break;
case JsonToken.Comment:
break;
case JsonToken.Raw:
break;
case JsonToken.Date:
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.Boolean:
case JsonToken.String:
var readerValue = "";
if (reader.TokenType == JsonToken.String)
readerValue = "\"" + reader.Value + "\"";
else
readerValue = reader.Value.ToString();
current = new TreeNode(readerValue) { Tag = new JsonTag(reader) };
parentNodes.Add(current);
current.Parent.Text += readerValue;
parentText = current.Parent.Text;
if (current.Parent.Parent.Text.Length > 2)
parentText = ", " + parentText;
current.Parent.Parent.Text = current.Parent.Parent.Text.Insert(current.Parent.Parent.Text.Length - 1, parentText);
if (((JsonTag)current.PrevNode.Tag).TokenType == JsonToken.PropertyName)
current = current.Parent;
current = current.Parent;
parentNodes = current.Nodes;
break;
case JsonToken.Bytes:
break;
case JsonToken.Null:
break;
case JsonToken.Undefined:
break;
case JsonToken.EndObject:
if (current.FirstNode.Tag != null &&
((JsonTag)current.FirstNode.Tag).TokenType == JsonToken.PropertyName)
current = current.Parent;
current = current.Parent;
if (current == null)
parentNodes = tvwValue.Nodes;
else
parentNodes = current.Nodes;
break;
case JsonToken.EndArray:
if (((JsonTag)current.PrevNode.Tag).TokenType == JsonToken.PropertyName)
current = current.Parent;
current = current.Parent;
if (current == null)
parentNodes = tvwValue.Nodes;
else
parentNodes = current.Nodes;
break;
case JsonToken.EndConstructor:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
tvwValue.EndUpdate();
}
那里有很多问题,真的。如果您真的需要关于每个部分的指导,那么在这里尝试回答很多。
有用于读取 JSON 结构的类,现成可用。正如 Yosi 间接链接的那样,有JSON.net
一旦可以读取 JSON,就可以使用它来构造TreeView
编辑很简单,因为它TreeView
有一个LabelEdit
支持就地编辑的属性。从那里开始,只需对此做出反应并跟踪变化。或者也许在最后一口气读完,你的选择。无论哪种方式,TreeView
都有事件,例如BeforeLabelEdit
,AfterLabelEdit
等,所有这些都可以在TreeView
上面的链接中找到。
从包管理器控制台:
PM> Install-Package Newtonsoft.Json
然后清理@vinceg 的答案,我推出了一个静态类:
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Windows.Forms;
public static class clsJSON2treeview
{
/// <summary>Parse JSON string, individual tokens become TreeView Nodes ~mwr</summary>
/// <param name="oTV">TreeView control to display parsed JSON</param>
/// <param name="sJSON">Incoming JSON string</param>
/// <param name="rootName">Title of top node in TreeView wrapping all JSON</param>
public static void JsonToTreeview(TreeView oTV, string sJSON, string rootName)
{
JContainer json = sJSON.StartsWith("[")
? (JContainer)JArray.Parse(sJSON)
: (JContainer)JObject.Parse(sJSON);
oTV.Nodes.Add(Ele2Node(json, rootName));
}
private static TreeNode Ele2Node(object oJthingy, string text = "")
{
TreeNode oThisNode = new TreeNode(text);
switch (oJthingy.GetType().Name) //~mwr could not find parent object for all three JObject, JArray, JValue
{
case "JObject":
foreach (KeyValuePair<string, JToken> oJtok in (JObject)oJthingy)
oThisNode.Nodes.Add(Ele2Node(oJtok.Value, oJtok.Key));
break;
case "JArray":
int i = 0;
foreach (JToken oJtok in (JArray)oJthingy)
oThisNode.Nodes.Add(Ele2Node(oJtok, string.Format("[{0}]", i++)));
if (i == 0) oThisNode.Nodes.Add("[]"); //to handle empty arrays
break;
case "JValue":
oThisNode.Nodes.Add(new TreeNode(oJthingy.ToString()));
break;
default:
throw new System.Exception("clsJSON2Treeview can't interpret object:" + oJthingy.GetType().Name);
}
return oThisNode;
}
}