如何从斜杠分隔的字符串创建 JSON?
How to create JSON from a slash separated String?
我有一个斜杠分隔的字符串格式。
例如
myDecision/data/buyerDecision/data/buy = food
myDecision/data/sellerDecision/data/sell = food
我想把它转换成下面的json格式
"myDecision":{
"data":{
"buyerDesision":{
"data":{"buy":"food"}
},
"sellerDesision":{
"data":{"sell":"food"}
}
}
}
我尝试了不同的解决方案,但没有用。
想到的最简单的解决方案是:
static async Task Main(string[] args)
{
var stringObjects = new string[]
{
"myDecision/data/buyerDecision/data/buy = food",
"myDecision/data/sellerDecision/data/sell = food"
};
var objectList = new List<JObject>();
foreach (var s in stringObjects)
{
objectList.Add(ParseStringObject(s));
}
}
static JObject ParseStringObject(string s)
{
// TODO! normalize input string (trim white space)
var openingBrackets = "{"; // top level braket
var closingBrakets = new string('}', s.Count(c => c == '/') + 1) ; // +1 for the top level braket
var json = $"{openingBrackets}\"{s.Replace("/", "\": { \"").Replace("=", "\":\"")}\"{closingBrakets}";
return JObject.Parse(json);
// TODO! handle exceptions
}
您需要安装 Newtonsoft.Json
才能正常工作。
不过也可以使用其他递归方法。
更新:
要将所有字符串转换为单个对象,可以使用 JObject
支持的 Merge
方法
static async Task Main(string[] args)
{
var stringObjects = new string[]
{
"myDecision/data/buyerDecision/data/buy = food",
"myDecision/data/sellerDecision/data/sell = food"
};
var resultingObject = new JObject();
var mergeSettings = new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Union
};
foreach (var s in stringObjects)
{
var obj = ParseStringObject(s);
resultingObject.Merge(obj,mergeSettings);
}
Console.WriteLine(resultingObject.ToString(Newtonsoft.Json.Formatting.Indented));
}
static JObject ParseStringObject(string s)
{
try
{
//remove whitespace
s = Regex.Replace(s, @"\s+", "");
var openingBrackets = "{"; // top level braket
var closingBrakets = new string('}', s.Count(c => c == '/') + 1); // +1 for the top level braket
var json = $"{openingBrackets}\"{s.Replace("/", "\": { \"").Replace("=", "\":\"")}\"{closingBrakets}";
return JObject.Parse(json);
}
catch (Exception)
{
// return an empty object
return new JObject();
}
}
这应该输出:
解决此问题的一种方法是手工制作 JObject
,然后将它们合并。 (这不是最高效的解决方案,因为它会多次重新创建层次结构的某些级别。)
此方法不同于 Benzara Tahar 提出的解决方案:
- Tahar:使用字符串操作构造一个有效的 json 然后使用
Json.Parse
- 我的:使用路径遍历来构造
JObject
层次结构。
核心逻辑
核心逻辑可以这样实现:
static JObject CreateHierarchy(Queue<string> pathLevels, JObject currentNode)
{
if (pathLevels.Count == 0) return currentNode;
var newNode = new JObject(new JProperty(pathLevels.Dequeue(), currentNode));
return CreateHierarchy(pathLevels, newNode);
}
- 这是一个递归函数,它构建从最内层到最外层的层次结构。
- 因此,如果我们使用以下
pathLevels
调用此方法:data, buyerDecision, data, myDescision
然后它会生成这样的东西:
new JObject(
new JProperty("myDecision",
new JObject(
new JProperty("data",
new JObject(
new JProperty("buyerDecision",
new JObject(
new JProperty("data", currentNode)))))));
调用核心逻辑
首先,将输入的字符串转换为字典,其中
- 关键是路径
- 该值为所需的最内层值:
var dataSource = new List<string>
{
"myDecision/data/buyerDecision/data/buy = food",
"myDecision/data/sellerDecision/data/sell = food"
};
var mappings = dataSource.Select(data => data.Split('=', StringSplitOptions.RemoveEmptyEntries))
.ToDictionary(parts => parts[0].Trim(), parts => parts[1].Trim());
- 注意:这很脆弱,因为如果多个数据源条目想要设置相同的 属性.
,它可能会抛出 ArgumentException: 'An item with the same key has already been added
- 我们可以遍历字典以从条目构造
JObject
s
- key应该被
/
拆分然后逆向集合
- 最里面的值和最里面的路径可以用来构造
currentNode
var objectsWithHierarchy = new List<JObject>();
foreach (var (path, innerMostValue) in mappings.Select(kv => (kv.Key, kv.Value)))
{
var entryLevels = path.Split('/').Reverse().ToArray();
objectsWithHierarchy.Add(CreateHierarchy(new Queue<string>(entryLevels.Skip(1)),
new JObject(new JProperty(entryLevels.First(), innerMostValue))));
}
合并对象
这里我们选择 objectsWithHierarchy
到集合中的第一个对象作为基础 JObject
我们 apply/merge 其余 JObject
的对象。
var baseObject = objectsWithHierarchy.First();
var mergeSettings = new JsonMergeSettings {MergeArrayHandling = MergeArrayHandling.Union};
foreach (var currentObj in objectsWithHierarchy.Skip(1))
{
baseObject.Merge(currentObj, mergeSettings);
}
Console.WriteLine(baseObject);
输出如下:
{
"myDecision": {
"data": {
"buyerDecision": {
"data": {
"buy": "food"
}
},
"sellerDecision": {
"data": {
"sell": "food"
}
}
}
}
}
结束语
- 这段代码真的很脆弱,因为它是根据两个样本数据设计的,没有实际需求
- 数据格式非常独特,所以我们想使用 JSONPath
- 实际用例也是未知的,因此解决方案本身可能会提供非常差的性能
- 在层次结构非常深的情况下
- 如果数据源非常大
我有一个斜杠分隔的字符串格式。
例如
myDecision/data/buyerDecision/data/buy = food
myDecision/data/sellerDecision/data/sell = food
我想把它转换成下面的json格式
"myDecision":{
"data":{
"buyerDesision":{
"data":{"buy":"food"}
},
"sellerDesision":{
"data":{"sell":"food"}
}
}
}
我尝试了不同的解决方案,但没有用。
想到的最简单的解决方案是:
static async Task Main(string[] args)
{
var stringObjects = new string[]
{
"myDecision/data/buyerDecision/data/buy = food",
"myDecision/data/sellerDecision/data/sell = food"
};
var objectList = new List<JObject>();
foreach (var s in stringObjects)
{
objectList.Add(ParseStringObject(s));
}
}
static JObject ParseStringObject(string s)
{
// TODO! normalize input string (trim white space)
var openingBrackets = "{"; // top level braket
var closingBrakets = new string('}', s.Count(c => c == '/') + 1) ; // +1 for the top level braket
var json = $"{openingBrackets}\"{s.Replace("/", "\": { \"").Replace("=", "\":\"")}\"{closingBrakets}";
return JObject.Parse(json);
// TODO! handle exceptions
}
您需要安装 Newtonsoft.Json
才能正常工作。
不过也可以使用其他递归方法。
更新:
要将所有字符串转换为单个对象,可以使用 JObject
Merge
方法
static async Task Main(string[] args)
{
var stringObjects = new string[]
{
"myDecision/data/buyerDecision/data/buy = food",
"myDecision/data/sellerDecision/data/sell = food"
};
var resultingObject = new JObject();
var mergeSettings = new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Union
};
foreach (var s in stringObjects)
{
var obj = ParseStringObject(s);
resultingObject.Merge(obj,mergeSettings);
}
Console.WriteLine(resultingObject.ToString(Newtonsoft.Json.Formatting.Indented));
}
static JObject ParseStringObject(string s)
{
try
{
//remove whitespace
s = Regex.Replace(s, @"\s+", "");
var openingBrackets = "{"; // top level braket
var closingBrakets = new string('}', s.Count(c => c == '/') + 1); // +1 for the top level braket
var json = $"{openingBrackets}\"{s.Replace("/", "\": { \"").Replace("=", "\":\"")}\"{closingBrakets}";
return JObject.Parse(json);
}
catch (Exception)
{
// return an empty object
return new JObject();
}
}
这应该输出:
解决此问题的一种方法是手工制作 JObject
,然后将它们合并。 (这不是最高效的解决方案,因为它会多次重新创建层次结构的某些级别。)
此方法不同于 Benzara Tahar 提出的解决方案:
- Tahar:使用字符串操作构造一个有效的 json 然后使用
Json.Parse
- 我的:使用路径遍历来构造
JObject
层次结构。
核心逻辑
核心逻辑可以这样实现:
static JObject CreateHierarchy(Queue<string> pathLevels, JObject currentNode)
{
if (pathLevels.Count == 0) return currentNode;
var newNode = new JObject(new JProperty(pathLevels.Dequeue(), currentNode));
return CreateHierarchy(pathLevels, newNode);
}
- 这是一个递归函数,它构建从最内层到最外层的层次结构。
- 因此,如果我们使用以下
pathLevels
调用此方法:data, buyerDecision, data, myDescision
然后它会生成这样的东西:
new JObject(
new JProperty("myDecision",
new JObject(
new JProperty("data",
new JObject(
new JProperty("buyerDecision",
new JObject(
new JProperty("data", currentNode)))))));
调用核心逻辑
首先,将输入的字符串转换为字典,其中
- 关键是路径
- 该值为所需的最内层值:
var dataSource = new List<string>
{
"myDecision/data/buyerDecision/data/buy = food",
"myDecision/data/sellerDecision/data/sell = food"
};
var mappings = dataSource.Select(data => data.Split('=', StringSplitOptions.RemoveEmptyEntries))
.ToDictionary(parts => parts[0].Trim(), parts => parts[1].Trim());
- 注意:这很脆弱,因为如果多个数据源条目想要设置相同的 属性. ,它可能会抛出
- 我们可以遍历字典以从条目构造
JObject
s- key应该被
/
拆分然后逆向集合 - 最里面的值和最里面的路径可以用来构造
currentNode
- key应该被
ArgumentException: 'An item with the same key has already been added
var objectsWithHierarchy = new List<JObject>();
foreach (var (path, innerMostValue) in mappings.Select(kv => (kv.Key, kv.Value)))
{
var entryLevels = path.Split('/').Reverse().ToArray();
objectsWithHierarchy.Add(CreateHierarchy(new Queue<string>(entryLevels.Skip(1)),
new JObject(new JProperty(entryLevels.First(), innerMostValue))));
}
合并对象
这里我们选择 objectsWithHierarchy
到集合中的第一个对象作为基础 JObject
我们 apply/merge 其余 JObject
的对象。
var baseObject = objectsWithHierarchy.First();
var mergeSettings = new JsonMergeSettings {MergeArrayHandling = MergeArrayHandling.Union};
foreach (var currentObj in objectsWithHierarchy.Skip(1))
{
baseObject.Merge(currentObj, mergeSettings);
}
Console.WriteLine(baseObject);
输出如下:
{
"myDecision": {
"data": {
"buyerDecision": {
"data": {
"buy": "food"
}
},
"sellerDecision": {
"data": {
"sell": "food"
}
}
}
}
}
结束语
- 这段代码真的很脆弱,因为它是根据两个样本数据设计的,没有实际需求
- 数据格式非常独特,所以我们想使用 JSONPath
- 实际用例也是未知的,因此解决方案本身可能会提供非常差的性能
- 在层次结构非常深的情况下
- 如果数据源非常大