JSON:将数据行序列化为父对象
我有一个树形结构,从DataTable中的行创建,每个DataRow生成一个节点 每个节点当然应该包含子节点,但也包含源数据行:JSON:将数据行序列化为父对象,json,json.net,Json,Json.net,我有一个树形结构,从DataTable中的行创建,每个DataRow生成一个节点 每个节点当然应该包含子节点,但也包含源数据行: public class TreeNode { public List<TreeNode> Items { get; internal set; } public JToken RowJToken { get; internal set; } } 其中“[children]”表示节点的子节点(为简洁
public class TreeNode
{
public List<TreeNode> Items { get; internal set; }
public JToken RowJToken { get; internal set; }
}
其中“[children]”表示节点的子节点(为简洁起见,省略)
然而,结果却是:
{
"items": [children],
"rowJToken": {
"columnA": "ValueA",
"columnB": "ValueB",
"columnC": "ValueC"
}
}
问题:如何将RowJToken内容序列化为与Items数组“在同一级别”,即不嵌入“RowJToken”对象
DataTable中的列集合事先是未知的(但我知道列名不会与“items”冲突)
下面的代码片段。请注意,在这种情况下,树结构本身的构造并不重要。
我在树节点中存储RowJToken而不是DataRow的原因是JSON.Net没有DataRow序列化程序,只有DataTable序列化程序。因此,我首先将DataTable序列化为JArray,然后获取与DataRow对应的JToken并将其粘贴到TreeNode中
public class TreeNode
{
public JToken RowJToken { get; internal set; }
public List<TreeNode> Items { get; internal set; }
}
...
List<TreeNode> treeNodes = GetTreeNodes(dataTable, childColumnName, parentColumnName);
DefaultContractResolver contractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
string json = JsonConvert.SerializeObject(treeNodes, new JsonSerializerSettings
{
ContractResolver = contractResolver,
Formatting = Formatting.Indented
});
...
private List<TreeNode> GetTreeNodes(DataTable dataTable, string childColumnName, string parentColumnName)
{
DataColumn childColumn = dataTable.Columns[childColumnName];
DataColumn parentColumn = dataTable.Columns[parentColumnName];
//
// Use the serializer for DataTable to generate a JSON array, containing each DataRow
//
var jArray = JArray.FromObject(dataTable, JsonSerializer.CreateDefault(new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }));
//
// The use of "NullObject" is merely to allow NULL values as the key to the dictionary
//
Dictionary<NullObject<string>, List<TreeNode>> hash = new Dictionary<NullObject<string>, List<TreeNode>>();
var rowIndex = 0;
foreach (DataRow r in dataTable.Rows)
{
string childId = r.Field<string>(childColumn);
string parentId = r.Field<string>(parentColumn);
if (!hash.TryGetValue(childId, out List<TreeNode> childIdTreeNodes))
{
childIdTreeNodes = new List<TreeNode>();
hash.Add(childId, childIdTreeNodes);
}
if (!hash.TryGetValue(parentId, out List<TreeNode> parentIdTreeNodes))
{
parentIdTreeNodes = new List<TreeNode>();
hash.Add(parentId, parentIdTreeNodes);
}
//
// Put the JToken which corresponds to this DataRow in the TreeNode
//
var rowJToken = jArray[rowIndex++];
parentIdTreeNodes.Add(new TreeNode()
{
Items = childIdTreeNodes,
RowJToken = rowJToken
});
}
//
// Return the root node(s), i.e. the nodes with NULL as parent ID
//
return hash[null];
}
公共类树节点
{
公共JToken RowJToken{get;内部集;}
公共列表项{get;internal set;}
}
...
List treeNodes=GetTreeNodes(dataTable、childColumnName、parentColumnName);
DefaultContractResolver contractResolver=新的DefaultContractResolver
{
NamingStrategy=新CamelCaseNamingStrategy()
};
string json=JsonConvert.SerializeObject(树节点,新JsonSerializerSettings
{
ContractResolver=ContractResolver,
格式化=格式化。缩进
});
...
私有列表GetTreeNodes(DataTable DataTable、string childColumnName、string parentColumnName)
{
DataColumn childColumn=dataTable.Columns[childColumnName];
DataColumn parentColumn=dataTable.Columns[parentColumnName];
//
//使用DataTable的序列化程序生成包含每个DataRow的JSON数组
//
var jArray=jArray.FromObject(dataTable,JsonSerializer.CreateDefault(新的JsonSerializerSettings{NullValueHandling=NullValueHandling.Ignore}));
//
//“NullObject”的使用仅仅是允许空值作为字典的键
//
字典哈希=新字典();
var-rowIndex=0;
foreach(dataTable.Rows中的DataRow r)
{
字符串childId=r.Field(childColumn);
字符串parentId=r.Field(parentColumn);
if(!hash.TryGetValue(childId,out List childIdTreeNodes))
{
childIdTreeNodes=新列表();
Add(childId,childIdTreeNodes);
}
if(!hash.TryGetValue(parentId,out List parentIdTreeNodes))
{
parentIdTreeNodes=新列表();
Add(parentId,parentIdTreeNodes);
}
//
//将与此数据行对应的JToken放入树节点
//
var rowJToken=jArray[rowIndex++];
parentIdTreeNodes.Add(新TreeNode()
{
Items=childIdTreeNodes,
RowJToken=RowJToken
});
}
//
//返回根节点,即父ID为NULL的节点
//
返回哈希值[null];
}
您只需做一些简单的更改即可获得所需的输出
TreeNode
类中,将RowJToken
的类型从JToken
更改为JObject
。(为了保持一致,您可能还希望将属性名称更改为RowJObject
,但严格来说这不是必需的。)
[JsonExtensionData]
属性装饰RowJToken
属性
[JsonExtensionData]
public JObject RowJToken { get; internal set; }
GetTreeNodes
方法中,将从jArray
检索到的JToken
强制转换为JObject
var rowJToken = (JObject)jArray[rowIndex++];
treeNodes
列表时,每个TreeNode
的RowJToken
属性将与其相应的项
数组处于同一级别
概念验证:太好了,谢谢,效果非常好!使用JsonExtensionData属性和所有属性时,我非常接近,但是使用JToken时,我得到了一个错误;很高兴我能帮忙
[JsonExtensionData]
不能与JToken
一起工作,因为JToken
不能实现IDictionary
。但是JObject
可以。事实证明,您的JArray
中已经有了JObjects
,所以这只是更改类型和执行演员阵容的问题。
[JsonExtensionData]
public JObject RowJToken { get; internal set; }
var rowJToken = (JObject)jArray[rowIndex++];