求助:如何实现按规则自动生成带占位符的JSON模板?
解决方案:基于Json.NET的JSON模板生成工具
核心思路
要实现需求,需要分两步处理:
- 统计属性名出现次数:递归遍历整个JSON结构,记录每个属性名的总出现次数,以此判断是否需要添加父节点前缀。
- 递归替换占位符:再次遍历JSON,根据属性名的重复情况生成对应占位符,同时保留原数据类型的格式(字符串加引号、数字/布尔值不加引号)。
VB.NET 实现代码
首先确保项目引用了Newtonsoft.Json(可通过NuGet安装),然后使用以下代码:
Imports Newtonsoft.Json Imports Newtonsoft.Json.Linq Imports System.Collections.Generic Public Class JsonTemplateGenerator Public Function GenerateTemplate(inputJson As String) As String ' 解析输入JSON Dim rootObj As JObject = JObject.Parse(inputJson) ' 第一步:统计所有属性名的出现次数 Dim propertyCount As Dictionary(Of String, Integer) = CountAllPropertyNames(rootObj) ' 第二步:遍历顶级节点,替换所有子节点的值为占位符 For Each topProperty As JProperty In rootObj.Properties() If topProperty.Value.Type = JTokenType.Object Then ReplaceNodeValues(topProperty.Value, propertyCount, topProperty.Name) End If Next ' 返回格式化后的模板JSON Return rootObj.ToString(Formatting.Indented) End Function ' 递归统计所有属性名的出现次数 Private Function CountAllPropertyNames(token As JToken) As Dictionary(Of String, Integer) Dim countDict As New Dictionary(Of String, Integer)() TraverseTokenForCount(token, countDict) Return countDict End Function Private Sub TraverseTokenForCount(token As JToken, countDict As Dictionary(Of String, Integer)) Select Case token.Type Case JTokenType.Object For Each prop As JProperty In DirectCast(token, JObject).Properties() ' 更新计数 If countDict.ContainsKey(prop.Name) Then countDict(prop.Name) += 1 Else countDict(prop.Name) = 1 End If ' 递归处理子节点 TraverseTokenForCount(prop.Value, countDict) Next Case JTokenType.Array For Each item As JToken In DirectCast(token, JArray) TraverseTokenForCount(item, countDict) Next End Select End Sub ' 递归替换节点值为占位符 Private Sub ReplaceNodeValues(token As JToken, propertyCount As Dictionary(Of String, Integer), topParentName As String) If token.Type <> JTokenType.Object Then Return For Each prop As JProperty In DirectCast(token, JObject).Properties() ' 生成占位符 Dim placeholder As String = If(propertyCount(prop.Name) = 1, $"$[{prop.Name}]", $"$[{topParentName}{prop.Name}]") ' 根据原数据类型设置占位符格式 Select Case prop.Value.Type Case JTokenType.String prop.Value = JToken.Parse($" ""{placeholder}"" ") Case JTokenType.Integer, JTokenType.Float, JTokenType.Boolean prop.Value = JToken.Parse(placeholder) Case JTokenType.Null prop.Value = JToken.Parse($" ""{placeholder}"" ") End Select ' 递归处理子节点 If prop.Value.Type = JTokenType.Object Then ReplaceNodeValues(prop.Value, propertyCount, topParentName) ElseIf prop.Value.Type = JTokenType.Array Then For Each item As JToken In DirectCast(prop.Value, JArray) ReplaceNodeValues(item, propertyCount, topParentName) Next End If Next End Sub End Class
使用示例
' 调用示例 Dim generator As New JsonTemplateGenerator() Dim inputJson As String = "你的输入JSON字符串" Dim templateJson As String = generator.GenerateTemplate(inputJson) Console.WriteLine(templateJson)
代码说明
- 统计属性次数:
CountAllPropertyNames和TraverseTokenForCount递归遍历整个JSON,不管嵌套层级多深,都会统计每个属性名的出现次数。 - 替换占位符:
ReplaceNodeValues递归处理每个节点,根据属性是否重复生成对应占位符:- 唯一属性:直接使用
$[属性名] - 重复属性:使用
$[顶级父节点名+属性名] - 保留原数据类型格式:字符串类型的占位符会被包裹在引号中,数字/布尔值则直接使用占位符,null值也转换为带引号的占位符(与示例保持一致)。
- 唯一属性:直接使用
- 支持嵌套数组:代码中处理了JArray类型,所以即使JSON中有数组结构也能正确生成模板。
解决你之前的问题
你之前的代码只遍历了两层节点,没有递归处理深层嵌套,也没有统计属性出现次数,所以无法判断属性是否重复,也无法生成正确的占位符。本方案通过递归遍历解决了深层节点的处理问题,同时通过统计次数实现了规则中的重复属性判断。
内容的提问来源于stack exchange,提问作者Roli
相关产品推荐
相关产品推荐

