问题
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 parentJObject
.
Demo fiddle here.
来源:https://stackoverflow.com/questions/60141830/json-net-find-jobject-by-value-regex-in-complex-object