Jq is a lightweight and flexible command-line JSON processor.
Official website:
https://jqlang.github.io/jq/
https://jqlang.github.io/jq/manual/
Jq can parse data from JSON and replace data in field expressions to generate new JSON.
For example, a JSON:
{ "foo": 42, "bar": "less interesting data" }
Using the jq expression .foo?
to extract data results in:
42
Extracting an array from JSON:
[
{ "name": "JSON", "good": true },
{ "name": "XML", "good": false }
]
Using the expression .[0]
, the extraction result is:
{ "name": "JSON", "good": true }
Jq contains a large number of expressions; please refer to the official documentation for details.
Since Jq is written in C, and does not provide other ways of API, it needs to be encapsulated by oneself.
Download the corresponding platform version of the binary file from the official reference:
├─linux
│ jq-linux64
│
└─windows
jq-win64.exe
Then use C# to encapsulate the interface:
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace JQ;
/// <summary>
/// json query
/// </summary>
public static partial class JQParse
{
private static readonly string JqExePath;
private static readonly string TempPath;
static JQParse()
{
var path = Directory.GetParent(typeof(JQParse).Assembly.Location)?.FullName ??
throw new ArgumentNullException(
$"{typeof(JQParse).Assembly.GetName()} file path is null");
JqExePath = RuntimeInformation.OSArchitecture switch
{
Architecture.X64 when OperatingSystem.IsWindows() => Path.Combine(path, "x64/windows/jq-win64.exe"),
Architecture.X64 when OperatingSystem.IsLinux() => Path.Combine(path, "/x64/linux/jq-win64"),
_ => throw new PlatformNotSupportedException(
$"The current platform is not supported: {RuntimeInformation.OSArchitecture}")
};
TempPath = Path.Combine(Path.GetTempPath(), "yworkflow");
if (!Directory.Exists(TempPath))
{
Directory.CreateDirectory(TempPath);
}
}
// <see href="https://stedolan.github.io/jq/manual/"/>
/// <summary>
/// Execute processing rules on JSON
/// </summary>
/// <param name="json">The JSON to process</param>
/// <param name="rule">JQ rule</param>
/// <returns></returns>
public static async Task<string> Execute(string json, string rule)
{
string path = Path.Combine(TempPath, $"{Guid.NewGuid().ToString()}.json");
await File.WriteAllTextAsync(path, json);
StreamReader streamReader;
string asString = string.Empty;
string message = string.Empty;
string arguments = $"-r \"{rule}\" {path}";
using Process? process = Process.Start(new ProcessStartInfo(JqExePath, arguments)
{
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false
});
if (process == null)
{
throw new ArgumentNullException("Not found JQ process!");
}
await process.WaitForExitAsync();
streamReader = process.StandardOutput;
StreamReader standardError = process.StandardError;
asString = await streamReader.ReadToEndAsync();
message = await standardError.ReadToEndAsync();
await process.WaitForExitAsync();
process.Close();
process.Dispose();
streamReader.Close();
streamReader.Dispose();
if (message != string.Empty)
throw new Exception(message);
File.Delete(path);
if (asString.EndsWith("\r\n")) return asString[0..(asString.Length - 2)];
return asString;
}
}
Example JSON:
const string json =
"""
{
"people": [
{
"fname": "Marry",
"lname": "Allice",
"address": "1234 SomeStreet",
"age": 25
},
{
"fname": "Kelly",
"lname": "Mill",
"address": "1234 SomeStreet",
"age": 30
}
]
}
""";
public class Model
{
public P[] people { get; set; }
public class P
{
public string fname { get; set; }
public string lname { get; set; }
public string address { get; set; }
public int age { get; set; }
}
}
Using the expression to extract JSON objects of people whose age is greater than or equal to 30:
var rule = "{people: [.people[] | select(.age >= 30)]}";
var text = JQParse.Execute(json, rule).Result;
After extracting into text, it can be printed or deserialized for testing:
var obj1 = Newtonsoft.Json.Linq.JObject.Parse(text);
var v1 = obj1.ToObject<Model>();
Assert.Equal("Kelly", v1.people[0].fname);
文章评论