- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
假设我有以下 JToken:
@"{
""data"": [
{
""company"": {
""ID"": ""12345"",
""location"": ""Some Location""
},
""name"": ""Some Name""
}
]
}";
我想将此标记传递给输出此 JToken 的 FlattenToken 函数:
@"{
""data"": [
{
""company_ID"": ""12345"",
""company_location"": ""Some Location"",
""name"": ""Some Name""
}
]}"
这样做的原因是我可以将扁平化的 JToken 反序列化为 DataTable。
不过,我迷失在 JObject、JTokens、JProperties 和其他 JMadness 的困惑中。我在 this post 上看到了答案,这很有帮助,但我还是没弄对。
这是我目前所拥有的:
public static JToken FlattenToken(JToken token)
{
foreach (JToken topLevelItem in token["data"].Children())
{
foreach (JToken field in topLevelItem.Value<JToken>())
{
foreach (JProperty property in field.Value<JObject>().Properties())
{
field.AddAfterSelf(JObject.Parse(@"{""" + property.Name + "_" + property.Value));
}
field.Remove();
}
}
return token;
}
通过外部 foreach 循环的第一次迭代,topLevelItem =
{
"company": {
"ID": "12345"
},
"name": "Some Name"
}
而第一次迭代通过第二次foreach循环,field =
"company": {
"ID": "12345"
}
到目前为止看起来不错。但是,当我进入最里面的 foreach 循环时,我在 foreach 行中遇到异常:“无法将 Newtonsoft.Json.Linq.JProperty 转换为 Newtonsoft.Json.Linq.JToken。”
不确定那里发生了什么。我的印象是 field.Value 调用将生成 JToken 并尝试将其转换为 JProperty。那么,正如错误提示的那样,试图将 JProperty 转换为 JToken 的位置在哪里?
此外,这感觉像是一种非常粗糙的扁平化 JToken 的方式。有没有更好的办法?
最佳答案
Json.NET 中对象的层次结构可能相当深。可以在 this answer 中找到粗略的指南。 .
要解决您的问题,您首先需要一个扩展方法来获取 JObject
的属性,然后返回一个带有名称前缀的集合:
public static class JsonExtensions
{
public static IEnumerable<KeyValuePair<string, JToken>> FlattenFields(this JObject obj, string prefix)
{
foreach (var field in obj)
{
string fieldName = prefix + "_" + field.Key;
var fieldValue = field.Value;
yield return new KeyValuePair<string, JToken>(fieldName, fieldValue);
}
}
}
接下来,您需要一些递归工具来遍历 Json.NET 层次结构并重写所选 JObject
的属性集合:
public static class JsonExtensions
{
public static IEnumerable<T> Yield<T>(this T item)
{
yield return item;
}
public static JToken EditFields(this JToken token, Func<KeyValuePair<string, JToken>, IEnumerable<KeyValuePair<string, JToken>>> editor)
{
if (token == null)
return null;
switch (token.Type)
{
case JTokenType.Array:
return EditFields((JArray)token, editor);
case JTokenType.Object:
return EditFields((JObject)token, editor);
default:
return token;
}
}
static JToken EditFields(JArray array, Func<KeyValuePair<string, JToken>, IEnumerable<KeyValuePair<string, JToken>>> editor)
{
JArray newArray = null;
foreach (var element in array)
{
var newElement = EditFields(element, editor);
if (newElement != null)
{
if (newArray == null)
newArray = new JArray();
newArray.Add(newElement);
}
}
return newArray;
}
static JToken EditFields(JObject obj, Func<KeyValuePair<string, JToken>, IEnumerable<KeyValuePair<string, JToken>>> editor)
{
JObject newObj = null;
foreach (var field in obj)
{
foreach (var newField in editor(field))
{
if (newObj == null)
newObj = new JObject();
newObj[newField.Key] = newField.Value.EditFields(editor);
}
}
return newObj;
}
}
最后,将它们放在一起创建一个方法,将命名的 JObject
属性的属性提升到它们的父级 JObject
,在属性名称前加一个下划线:
public static class JsonExtensions
{
public static JToken PromoteNamedPropertiesToParents(this JToken token, string propertyName)
{
return token.EditFields(pair =>
{
if (pair.Key == propertyName && pair.Value is JObject)
{
return ((JObject)pair.Value).FlattenFields(pair.Key);
}
return pair.Yield();
});
}
}
然后,进行测试:
public static class TestFlatten
{
public static void Test()
{
string jsonString = @"{
""data"": [
{
""company"": {
""ID"": ""12345"",
""location"": ""Some Location""
},
""name"": ""Some Name""
}
]
}";
JObject obj = JObject.Parse(jsonString);
var newObj = (JObject)obj.PromoteNamedPropertiesToParents("company");
Debug.WriteLine(newObj);
}
}
输出是:
{
"data": [
{
"company_ID": "12345",
"company_location": "Some Location",
"name": "Some Name"
}
]
}
这是你想要的。请注意,此代码创建了一个新的 JObject
层次结构,而不是修改原始层次结构。
关于c# - 展平 JToken,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27713897/
我有以下 Json { "error": { "errors": [ { "domain": "global", "reason": "requ
我有以下... JArray clients = (JArray)clientsParsed["objects"]; foreach (JObject item in clients.Children
JToken.ToObject() 之间有什么区别?方法和 JToken.Value()扩展方法(没有 key 参数的方法)? var jToken = JToken.Parse("123"); va
我有以下 JToken 输出。我如何从 TenantID 中检索此处的“值”,在这种情况下应为 1? {[ { "value": 1, "metadata": { "userType"
我有一个包含参数/值对的 JObject(例如“param1”:“aValue”)。我想根据数据网格中捕获的数据更新这些值。 然后根据定义以下类型的 JSON 架构验证参数值:“字符串”、“整数”和“
假设我有以下 JToken: @"{ ""data"": [ { ""company"": { ""ID"": ""12
我有一个值为 {1234} 的 JToken 如何将其转换为整数值,如 var totalDatas = 1234; var tData = jObject["$totalDatas"]; int t
我有一个 JObject,我想为它设置一个强类型对象的属性。 JObject["ProductionVersion"] = new ProductionVersion(); 为此,需要将 Produc
我有一个 json JTokens 列表: List subjectresults = jObj[jp]["subjects"].Children().ToList(); 请注意,我的 jp 是 va
作为我的问题的后续行动: JSON.NET: Obtain JObject from JProperty Value ... 我阅读了链接并消化了上述评论和建议。现在我想知道:为什么没有“直接”(即简
这是我的情况: 我有一个解析为 JObject 的 JSON 字符串。 JObject jObject = JObject.Parse(json); 我跳转到 JSON 中的“白名单”标记 JToke
这是我的情况: 我有一个解析为 JObject 的 JSON 字符串。 JObject jObject = JObject.Parse(json); 我跳转到 JSON 中的“白名单”标记 JToke
我正在尝试动态查找结构事先未知的 JSON 对象的叶节点名称。首先,我将字符串解析为 JTokens 列表,如下所示: string req = @"{'creationRequest
我有以下JToken: { "ID": "9dbefe3f5424d972e040007f010038f2" } 但每当我在 JToken 对象上运行 ToString() 以获取字符串形式的
在收到来自 API 的响应后,我有以下信息: JObject goatHerd = JObject.Parse(responseString); JToken goat = goatHerd["val
如何将这两个 JToken 合并为一个 JToken。这听起来应该很简单,但我无法绕过它。 { "data":[ { "ID":"53a1862000404a304942546b3
我想比较两个相同类型和结构的任意 JTokens(NewtonSoft 的 Json.Net)。 static int CompareTokens(JToken x, JToken y); // p
我从返回 JSON 响应的 Web 服务获取数据。这是我的代码: WebClient client = new WebClient(); var result = client.DownloadSt
我正在尝试更新 JToken 的值,但它的引用没有得到更新。 JSON 字符串: { "Title": "master", "Presentation": [ {
我想将 JToken 内容反序列化为一个对象(User)。我怎么能做到这一点? 这是我的 json 字符串: string json = @"[{""UserId"":0,""Username"":"
我是一名优秀的程序员,十分优秀!