使用 json.net 和 linq 在 json 中查找模式



我正在搜索一个 json 文件,结构如下:

{
    "objects": [
        {    
        "name": "obj1",
            "state": {
                "type": 4,
                    "childs": [
                         "state": {
                              "type": 5,
                               ...

状态可以包含作为子项的状态,直到任意数量的级别。现在我试图找到包含特定状态模式的所有对象,例如状态 4 与子状态 5 与子状态 2。

到目前为止,我的代码是这样的。

        JObject o = JObject.Parse(System.IO.File.ReadAllText(@"j.json"));
        var oObjects=
            from p in o["objects"]
            where (string)p["state"] == "4"
            select (string)p["name"];

如何扩展代码以查找任何级别上包含搜索模式的所有对象?

要使其适用于无限级别,则需要使用如下所示的递归方法:

void Main()
{
    var str = @"{
        ""objects"": [
            {
                ""name"": ""obj1"",
                ""state"": {
                    ""type"": 4,
                    ""childs"": [
                        {
                            ""state"": {
                                ""type"": 5
                            }
                        }
                    ]
                }
            }
        ]
    }";
    var obj = JObject.Parse(str);
    GetValidObjects(obj, new string[] { "4", "5" }); // Name list of valid objects
}

以及帮助程序方法的定义如下:

public IEnumerable<string> GetValidObjects(JObject obj, IEnumerable<string> values)
{
    return obj["objects"]
        .Where(i => (string)i["state"]["type"] == values.First() && ContainsState((JArray)i["state"]["childs"], values.Skip(1)))
        .Select(i => (string)i["name"]);
}
public bool ContainsState(JArray childs, IEnumerable<string> values)
{
    if (childs == null)
    {
        return values.Count() == 0;
    }
    return childs.Any(i => (string)i["state"]["type"] == values.First() && ContainsState((JArray)i["state"]["childs"], values.Skip(1)));
}

一个选项是将 json 转换为 xml,然后使用 xpath 查询获取节点列表。

        string json = System.IO.File.ReadAllText(@"j.json");
        XmlDocument document = (XmlDocument)JsonConvert.DeserializeXmlNode(json);
        XmlNodeList nodes = document.SelectNodes("//name[../state[type[.=4] and childs/state[type[.=5] and childs/state[type[.=2]]]]]");

你可以使用SelectTokens来实现这一点:

var objects = o.SelectTokens("$.objects[?(@.state.type == 4 
                       && @.state.childs[*].state.type == 5)].name")
                    .Select(s => (string)s)
                    .ToList();

相关内容

  • 没有找到相关文章