如何使用json路径在json字符串中添加新属性

时间:2017-08-17 16:47:16

标签: c# json.net

我想将json属性(名称和值)或json数据(数组)添加到现有的json字符串。

用户必须指定一个json路径来指定添加位置。

有人可以帮我提供一个链接/示例来推进此进展。

此致 阿玛尔

3 个答案:

答案 0 :(得分:1)

您可以使用Newtonsoft.Json

        var input = "{ test: true }";

        var jObject = JObject.Parse(input);

        jObject["updated"] = true;
        jObject["array"] = new JArray("item1", "item2", "item3");

        var s = jObject.ToString();

        // { test: true, updated: true, array: ["item1", "item2", "item3"] }
        Console.WriteLine(s);

上面我们已经将json字符串解析为JObject然后使用该JObject我们可以通过添加字段等来开始修改它。然后返回字符串表示我们只调用ToString在JObject上。

答案 1 :(得分:0)

编辑:谷歌搜索了一下之后我注意到了.SelectToken()!这是我在提到XPath时所考虑的内容。

// Inpup JSON
string input = "{ body: { name: { firstname: 'John', lastname: 'Doe' }, age: 43 } }";
JToken json = JToken.Parse(input); // Parsed to JToken as type may not be known.

// Select token based on JSONPath, see: http://goessner.net/articles/JsonPath/
JToken nameToken = json.SelectToken("$['body']['name']");
nameToken["middlename"] = "something";

// Prints: {"body":{"name":{"firstname":"John","lastname":"Doe","middlename":"something"},"age":43}}
string output = json.ToString(Newtonsoft.Json.Formatting.None);

<强> OLD:
看起来你想要像Jath的XPath。那么你可以找到一个现有的对象/数组并添加到那个?

我的建议是为Json搜索现有的路径工具。 这是一个快速而又肮脏的例子,说明了如何做到这一点:

static void Main(string[] args)
    {
        string input = "{ body: { name: { firstname: 'John', lastname: 'Doe' }, age: 43 } }";

        JToken json = JToken.Parse(input);

        UpdateJson(json, "body/name/middlename", "Something");

        // {"body":{"name":{"firstname":"John","lastname":"Doe","middlename":"Something"},"age":43}}
        string output = json.ToString(Newtonsoft.Json.Formatting.None);

        UpdateJson(json, "body/jobs", new JArray(){ "C# Dev", "Network Master" });

        // {"body":{"name":{"firstname":"John","lastname":"Doe","middlename":"Something"},"age":43,"jobs":["C# Dev","Network Master"]}}
        string output2 = json.ToString(Newtonsoft.Json.Formatting.None);
    }

    private static void UpdateJson(JToken source, string path, JToken value)
    {
        UpdateJsonInternal(source, path.Split('/'), 0, value);
    }

    private static void UpdateJsonInternal(JToken source, string[] path, int pathIndex, JToken value)
    {
        if (pathIndex == path.Length - 1)
        {
            if (source is JArray)
            {
                ((JArray)source)[int.Parse(path[pathIndex])] = value;
            }
            else if (source is JObject)
            {
                ((JObject)source)[path[pathIndex]] = value;
            }
        }
        else if (source is JArray)
        {
            UpdateJsonInternal(((JArray)source)[int.Parse(path[pathIndex])], path, pathIndex + 1, value);
        }
        else if (source is JObject)
        {
            UpdateJsonInternal(((JObject)source)[path[pathIndex]], path, pathIndex + 1, value);
        }
    }
}

这将在指定的路径上添加或更新具有JToken值的源。 所以&#39; body / name / middlename&#39;要么添加&#39;中间名&#39;名字&#39;或者使用&#39; value&#39;进行更新。如果&#39; name&#39;如果不存在,这个例子就失败了。

答案 2 :(得分:0)

如果你想设置一个存在的路径位置,你可以使用SelectToken

void SetValueByPath(JToken token, string path, object value)
{
  var newToken = value == null ? null : JToken.FromObject(value);
  var targetToken = token.SelectToken(path);
  if(targetToken.Type == JTokenType.Property)
    targetToken.Replace(newToken)
}

但是如果你想设置一个不存在的路径位置,这里是代码:

//Origin code by Squirrel.Downy(Flithor)
public static void AddTokenByPath(JToken jToken, string path, object value)
{
    // Regex.Split("a.b.d[1]['my1.2.4'][4].af['micor.a.ee.f'].ra[6]", @"(?=\[)|(?=\[\.)|(?<=])(?>\.)")
    // > { "a.b.d", "[1]", "['my1.2.4']", "[4]", "af", "['micor.a.ee.f']", "ra", "[6]" }
    var pathParts = Regex.Split(path, @"(?=\[)|(?=\[\.)|(?<=])(?>\.)").ToArray();
    JToken node = jToken;
    for (int i = 0; i < pathParts.Length; i++)
    {
        var pathPart = pathParts[i];
        var partNode = node.SelectToken(pathPart);
        //node is null or token with null value
        if (partNode == null || partNode.Type == JTokenType.Null)
        {
            if (i < pathParts.Length - 1)
            {
                //the next level is array or object
                //accept [0], not ['prop']
                JToken nextToken = Regex.IsMatch(pathParts[i + 1], @"\[\d+\]")) ?
                    new JArray() : new JObject();
                SetToken(node, pathPart, nextToken);
            }
            else if (i == pathParts.Length - 1)
            {
                //JToken.FromObject(null) will throw a exception
                var jValue = value == null ?
                   null : JToken.FromObject(value);
                SetToken(node, pathPart, jValue);
            }
            partNode = node.SelectToken(pathPart);
        }
        node = partNode;
    }
    //set new token
    void SetToken(JToken node, string pathPart, JToken jToken)
    {
        if (node.Type == JTokenType.Object)
        {
            //get real prop name (convert "['prop']" to "prop")
            var name = pathPart.Trim('[', ']', '\'');
            ((JObject)node).Add(name, jToken);
        }
        else if (node.Type == JTokenType.Array)
        {
            //get real index (convert "[0]" to 0)
            var index = int.Parse(pathPart.Trim('[', ']'));
            var jArray = (JArray)node;
            //if index is bigger than array length, fill the array
            while (index >= jArray.Count)
                jArray.Add(null);
            //set token
            jArray[index] = jToken;
        }
    }
}