JSON.NET - find JObject by value regex in complex object?

妖精的绣舞 提交于 2021-02-19 07:58:10

问题


How do I search for the path of a JObject in my deserialized JSON by value using regex or other wildcard-capable method?

For instance, this is my JSON:

{
    "type": "AdaptiveCard",
    "body": [
        {
            "type": "Container",
            "items": [
                {
                    "type": "TextBlock",
                    "text": "{item.name}",
                    "size": "Large",
                    "weight": "Bolder",
                    "horizontalAlignment": "Center",
                    "color": "Accent"
                },
                {
                    "type": "Image",
                    "url": "{item.image}",
                    "altText": ""
                },
                {
                    "type": "ColumnSet",
                    "columns": [
                        {
                            "type": "Column",
                            "width": "stretch",
                            "horizontalAlignment": "Right",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "text": "{template.other}",
                                    "weight": "Bolder",
                                    "horizontalAlignment": "Right"
                                }
                            ]
                        },
                        {
                            "type": "Column",
                            "width": "stretch",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "text": "{item.other}"
                                }
                            ]
                        }
                    ]
                },
                {
                    "type": "ColumnSet",
                    "columns": [
                        {
                            "type": "Column",
                            "width": "stretch",
                            "horizontalAlignment": "Right",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "text": "{template.name}",
                                    "weight": "Bolder",
                                    "horizontalAlignment": "Right"
                                }
                            ]
                        },
                        {
                            "type": "Column",
                            "width": "stretch",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "text": "{item.name}"
                                }
                            ]
                        }
                    ]
                },
                {
                    "type": "ColumnSet",
                    "columns": [
                        {
                            "type": "Column",
                            "width": "stretch",
                            "horizontalAlignment": "Right",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "text": "{template.order}",
                                    "weight": "Bolder",
                                    "horizontalAlignment": "Right"
                                }
                            ]
                        },
                        {
                            "type": "Column",
                            "width": "stretch",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "text": "{item.order}"
                                }
                            ]
                        }
                    ]
                },
                {
                    "type": "ColumnSet",
                    "columns": [
                        {
                            "type": "Column",
                            "width": "stretch",
                            "horizontalAlignment": "Right",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "text": "{template.family}",
                                    "weight": "Bolder",
                                    "horizontalAlignment": "Right"
                                }
                            ]
                        },
                        {
                            "type": "Column",
                            "width": "stretch",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "text": "{item.genus}"
                                }
                            ]
                        }
                    ]
                },
                {
                    "type": "ColumnSet",
                    "columns": [
                        {
                            "type": "Column",
                            "width": "stretch",
                            "horizontalAlignment": "Right",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "text": "{template.species}",
                                    "weight": "Bolder",
                                    "horizontalAlignment": "Right"
                                }
                            ]
                        },
                        {
                            "type": "Column",
                            "width": "stretch",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "text": "{item.species}"
                                }
                            ]
                        }
                    ]
                },
                {
                    "type": "ColumnSet",
                    "columns": [
                        {
                            "type": "Column",
                            "width": "stretch",
                            "horizontalAlignment": "Right",
                            "items": [
                                {
                                    "type": "TextBlock",
                                    "text": "{template.clade}",
                                    "weight": "Bolder",
                                    "horizontalAlignment": "Right"
                                }
                            ]
                        },
                        {
                            "type": "Column",
                            "width": "stretch",
                            "items": [
                                {
                                    "type": "Container",
                                    "items": [
                                        {
                                            "$data": "{item.clade}",
                                            "type": "TextBlock",
                                            "text": "{$data}"
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ],
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.0"
}

How would I find the path of the element with a value that contains {item.name} with JSON.NET?

I've looked at the SelectToken method, but I can't figure out how to make it work for what I'm trying to do.


回答1:


If you are using LINQ to JSON and want to find the paths to all JValue values containing the "{item.name}" string (or more generally matching any regular expression), you have a couple options.

Let's say your regular expression looks like this:

var innerValue = Regex.Escape(@"{item.name}");
var regexString = $".*{innerValue}.*";    // Evaluates to .*\{item\.name}.*

And you have some JObject obj capturing your JSON hierarchy.

Firstly, you could search for all string-valued tokens whose value matches this expression using JContainer.DescendantsAndSelf():

var regex = new Regex(regexString);
var paths = obj.Descendants().OfType<JValue>().Where(v => v.Type == JTokenType.String)
    .Where(v => regex.IsMatch((string)v.Value))
    .Select(v => v.Path)
    .ToList();

Secondly, you could use SelectTokens() with the JSONPath regex operator:

var jsonPath = $"..[?(@ =~ /{regexString}/)]"; // Note that the regex should be delimited by `/` characters.
var paths = obj.SelectTokens(jsonPath)
    .Select(v => v.Path)
    .ToList();

Notes:

  • There is no standard for JSONPath other than the short article # JSONPath - XPath for JSON.

  • .. is the JSONPath "recursive descent" operator.

  • @ represents the current object.

  • [?( )] applies a filter (script) expression using the "underlying script engine".

  • =~ is Newtonsoft's regular expression operator. It was introduced in Json.NET 11.0.1.

  • Within the JSONPath string, the regular expression needs to be delimited by / characters (rather than ').

  • Given that there's no formal definition for JSONPath filter expressions I feel as though the first option is a little more straightforward.

  • Once you have a selected set of JValue values, you can use JToken.Ancestors() to climb up the parent hierarchy to find the lowest parent JObject.

Demo fiddle here.



来源:https://stackoverflow.com/questions/60141830/json-net-find-jobject-by-value-regex-in-complex-object

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!