gpt4 book ai didi

c# - JSON.net 与 XPATH : How to preserve node order in SelectTokens?

转载 作者:行者123 更新时间:2023-11-30 12:20:26 25 4
gpt4 key购买 nike

XPath 2 声明选择的节点顺序应按照它们在文档中的顺序返回。当您在 JSON.Net 中选择 token (JSONPath)时,情况似乎并非如此

当我处理下面的文档时

string json = @"
{
""Files"": {
""dir1"": {
""Files"": {
""file1.1.txt"": {
""size:100""},
""file1.2.txt"": {
""size:100""}
}
},
""dir2"": {
""Files"": {
""file2.1.txt"": {
""size:100""},
""file2.2.txt"": {
""size:100""}
}
},
""file3.txt"": {
""size:100""}
}
}";

使用JSON.net SelectTokens("$..files.*")时顺序如下

dir1
dir2
file3.txt
file1.1.txt
file1.2.txt
file2.1.txt
file2.2.txt

当我期望以下顺序时(如 Xpath//files/*)

dir1
file1.1.txt
file1.2.txt
dir2
file2.1.txt
file2.2.txt
file3.txt

我应该如何编写查询以便获得 XPath 顺序的列表?

最佳答案

除了修改 Json.Net 源代码,我看不到直接控制顺序的方法 SelectTokens() 返回其结果。它似乎在使用广度优先排序。

而不是使用 SelectTokens() ,您可以将 LINQ-to-JSON 查询与 Descendants() 结合使用方法。这将按深度优先顺序返回标记。但是,您需要过滤掉您不感兴趣的属性名称,例如"file"和“大小”。

string json = @"
{
""Files"": {
""dir1"": {
""Files"": {
""file1.1.txt"": { ""size"": 100 },
""file1.2.txt"": { ""size"": 100 }
}
},
""dir2"": {
""Files"": {
""file2.1.txt"": { ""size"": 100 },
""file2.2.txt"": { ""size"": 100 }
}
},
""file3.txt"": { ""size"": 100 }
}
}";

JObject jo = JObject.Parse(json);

var files = jo.Descendants()
.OfType<JProperty>()
.Select(p => p.Name)
.Where(n => n != "Files" && n != "size")
.ToArray();

Console.WriteLine(string.Join("\n", files));

fiddle :https://dotnetfiddle.net/yRAev4


如果您不喜欢这个想法,另一种可能的解决方案是使用自定义 IComparer<T> 事后将所选属性排序回其原始文档顺序:

class JPropertyDocumentOrderComparer : IComparer<JProperty>
{
public int Compare(JProperty x, JProperty y)
{
var xa = GetAncestors(x);
var ya = GetAncestors(y);
for (int i = 0; i < xa.Count && i < ya.Count; i++)
{
if (!ReferenceEquals(xa[i], ya[i]))
{
return IndexInParent(xa[i]) - IndexInParent(ya[i]);
}
}
return xa.Count - ya.Count;
}

private List<JProperty> GetAncestors(JProperty prop)
{
return prop.AncestorsAndSelf().OfType<JProperty>().Reverse().ToList();
}

private int IndexInParent(JProperty prop)
{
int i = 0;
var parent = (JObject)prop.Parent;
foreach (JProperty p in parent.Properties())
{
if (ReferenceEquals(p, prop)) return i;
i++;
}
return -1;
}
}

像这样使用比较器:

JObject jo = JObject.Parse(json);

var files = jo.SelectTokens("$..Files")
.OfType<JObject>()
.SelectMany(j => j.Properties())
.OrderBy(p => p, new JPropertyDocumentOrderComparer())
.Select(p => p.Name)
.ToArray();

Console.WriteLine(string.Join("\n", files));

fiddle :https://dotnetfiddle.net/xhx7Kk

关于c# - JSON.net 与 XPATH : How to preserve node order in SelectTokens?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51772089/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com