C# 使用JSON.Net从JSON动态删除字段
我有一些JSON输入,其形状我无法预测,我必须进行一些转换(称之为某种转换),以便不记录某些字段。例如,如果我有这个JSON:C# 使用JSON.Net从JSON动态删除字段,c#,json,json.net,C#,Json,Json.net,我有一些JSON输入,其形状我无法预测,我必须进行一些转换(称之为某种转换),以便不记录某些字段。例如,如果我有这个JSON: { "id": 5, "name": "Peter", "password": "some pwd" } 然后在转换之后,它应该是这样的: { "id": 5, "name": "Peter" } 上面的示例并不重要,但实际案例并不那么令人满意/容易。我将有一些正则表达式,如果输入JSON上的任何字段与之匹配,那么它不应该
{
"id": 5,
"name": "Peter",
"password": "some pwd"
}
然后在转换之后,它应该是这样的:
{
"id": 5,
"name": "Peter"
}
上面的示例并不重要,但实际案例并不那么令人满意/容易。我将有一些正则表达式,如果输入JSON上的任何字段与之匹配,那么它不应该出现在结果中。如果我有一些嵌套的对象,我将不得不递归地进行。我在LinqtoJSON上看到了一些东西,但我没有发现任何东西能满足我的需求
有没有办法做到这一点
注:
这是日志库的一部分。如果需要或更简单,我可以使用JSON字符串。问题是,在我的日志管道中的某个点上,我获取了对象(或需要的字符串),然后我需要从中删除敏感数据,如密码,以及任何其他客户端指定的数据。您可以将JSON解析为一个(对象或数组),然后使用搜索JSON层次结构,以查找名称与某些
Regex
匹配的属性,或与Regex
匹配的字符串值,并删除这些项
例如,给定以下JSON:
{
"Items": [
{
"id": 5,
"name": "Peter",
"password": "some pwd"
},
{
"id": 5,
"name": "Peter",
"password": "some pwd"
}
],
"RootPasswrd2": "some pwd",
"SecretData": "This data is secret",
"StringArray": [
"I am public",
"This is also secret"
]
}
您可以按如下方式删除名称中包含“pass.*w.*r.*d”
的所有属性:
var root = (JContainer)JToken.Parse(jsonString);
var nameRegex = new Regex(".*pass.*w.*r.*d.*", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
var query = root.DescendantsAndSelf()
.OfType<JProperty>()
.Where(p => nameRegex.IsMatch(p.Name));
query.RemoveFromLowestPossibleParents();
您可以通过执行以下操作删除包含子字符串secret
的所有字符串值:
var valueRegex = new Regex(".*secret.*", RegexOptions.IgnoreCase);
var query2 = root.DescendantsAndSelf()
.OfType<JValue>()
.Where(v => v.Type == JTokenType.String && valueRegex.IsMatch((string)v));
query2.RemoveFromLowestPossibleParents();
var finalJsonString = root.ToString();
为方便起见,我使用以下扩展方法:
public static partial class JsonExtensions
{
public static TJToken RemoveFromLowestPossibleParent<TJToken>(this TJToken node) where TJToken : JToken
{
if (node == null)
return null;
JToken toRemove;
var property = node.Parent as JProperty;
if (property != null)
{
// Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
toRemove = property;
property.Value = null;
}
else
{
toRemove = node;
}
if (toRemove.Parent != null)
toRemove.Remove();
return node;
}
public static IEnumerable<TJToken> RemoveFromLowestPossibleParents<TJToken>(this IEnumerable<TJToken> nodes) where TJToken : JToken
{
var list = nodes.ToList();
foreach (var node in list)
node.RemoveFromLowestPossibleParent();
return list;
}
}
公共静态部分类JsonExtensions
{
公共静态TJToken从低概率父节点(此TJToken节点)移除,其中TJToken:JToken
{
if(node==null)
返回null;
jtokentoremove;
var property=node.Parent作为JProperty;
if(属性!=null)
{
//另外,将节点与其立即包含的属性分离--Remove()不执行此操作,即使它看起来应该这样做
toRemove=财产;
property.Value=null;
}
其他的
{
toRemove=节点;
}
如果(toRemove.Parent!=null)
toRemove.Remove();
返回节点;
}
公共静态IEnumerable RemovefromLowerstPossibleParents(此IEnumerable节点),其中TJToken:JToken
{
var list=nodes.ToList();
foreach(列表中的var节点)
node.RemoveFromLowestPossibleParent();
退货清单;
}
}
演示小提琴。您可以将JSON解析为
JToken
,然后使用递归助手方法将属性名称与正则表达式匹配。只要存在匹配项,就可以从其父对象中删除该属性。删除所有敏感信息后,只需使用JToken.ToString()
获取经过编辑的JSON
以下是帮助器方法的外观:
public static string RemoveSensitiveProperties(string json, IEnumerable<Regex> regexes)
{
JToken token = JToken.Parse(json);
RemoveSensitiveProperties(token, regexes);
return token.ToString();
}
public static void RemoveSensitiveProperties(JToken token, IEnumerable<Regex> regexes)
{
if (token.Type == JTokenType.Object)
{
foreach (JProperty prop in token.Children<JProperty>().ToList())
{
bool removed = false;
foreach (Regex regex in regexes)
{
if (regex.IsMatch(prop.Name))
{
prop.Remove();
removed = true;
break;
}
}
if (!removed)
{
RemoveSensitiveProperties(prop.Value, regexes);
}
}
}
else if (token.Type == JTokenType.Array)
{
foreach (JToken child in token.Children())
{
RemoveSensitiveProperties(child, regexes);
}
}
}
以下是结果输出:
{
"users": [
{
"id": 5,
"name": "Peter Gibbons",
"company": "Initech",
"login": "pgibbons",
"financialDetails": {
"creditCards": [
{
"vendor": "Viza",
"lastUse": "2016-10-15"
},
{
"vendor": "MasterCharge",
"lastUse": "2016-10-02"
}
],
"bankAccounts": [
{
"accountType": "checking",
"financialInsitution": "1st Bank of USA"
}
]
},
"interests": "Computer security, numbers and passwords"
}
]
}
Fiddle:用JObject解析它。解析它,这样你就可以得到一个JObject。然后您可以使用Remove(key)方法我可以使用正则表达式在
JObject
上搜索吗?您可以直接使用键索引语法,如obj[“password”]这太宽泛了。您需要在什么时候进行转换?能把它做成粗线吗?可以在反序列化过程中进行吗?变更的约束条件是什么?这里没有足够的帮助,问题应该按当前编写的方式结束。我想执行类似于parsed.Children().Where(myRegex.Matches)
的操作,并删除与我的regex匹配的项,如果任何子项本身有子项,则对它们执行与扩展方法相同的操作,在什么情况下,您需要提升多个级别才能找到不是JProperty
的容器?JProperty
不能将JProperty
作为其父级,对吗?@KyleDelaney-我很久以前写过这个。我当前版本的RemoveFromLowestPossibleParent();我已经更新了答案,包括它+一把小提琴演示。
public static string RemoveSensitiveProperties(string json, IEnumerable<Regex> regexes)
{
JToken token = JToken.Parse(json);
RemoveSensitiveProperties(token, regexes);
return token.ToString();
}
public static void RemoveSensitiveProperties(JToken token, IEnumerable<Regex> regexes)
{
if (token.Type == JTokenType.Object)
{
foreach (JProperty prop in token.Children<JProperty>().ToList())
{
bool removed = false;
foreach (Regex regex in regexes)
{
if (regex.IsMatch(prop.Name))
{
prop.Remove();
removed = true;
break;
}
}
if (!removed)
{
RemoveSensitiveProperties(prop.Value, regexes);
}
}
}
else if (token.Type == JTokenType.Array)
{
foreach (JToken child in token.Children())
{
RemoveSensitiveProperties(child, regexes);
}
}
}
public static void Test()
{
string json = @"
{
""users"": [
{
""id"": 5,
""name"": ""Peter Gibbons"",
""company"": ""Initech"",
""login"": ""pgibbons"",
""password"": ""Sup3rS3cr3tP@ssw0rd!"",
""financialDetails"": {
""creditCards"": [
{
""vendor"": ""Viza"",
""cardNumber"": ""1000200030004000"",
""expDate"": ""2017-10-18"",
""securityCode"": 123,
""lastUse"": ""2016-10-15""
},
{
""vendor"": ""MasterCharge"",
""cardNumber"": ""1001200230034004"",
""expDate"": ""2018-05-21"",
""securityCode"": 789,
""lastUse"": ""2016-10-02""
}
],
""bankAccounts"": [
{
""accountType"": ""checking"",
""accountNumber"": ""12345678901"",
""financialInsitution"": ""1st Bank of USA"",
""routingNumber"": ""012345670""
}
]
},
""securityAnswers"":
[
""Constantinople"",
""Goldfinkle"",
""Poppykosh"",
],
""interests"": ""Computer security, numbers and passwords""
}
]
}";
Regex[] regexes = new Regex[]
{
new Regex("^.*password.*$", RegexOptions.IgnoreCase),
new Regex("^.*number$", RegexOptions.IgnoreCase),
new Regex("^expDate$", RegexOptions.IgnoreCase),
new Regex("^security.*$", RegexOptions.IgnoreCase),
};
string redactedJson = RemoveSensitiveProperties(json, regexes);
Console.WriteLine(redactedJson);
}
{
"users": [
{
"id": 5,
"name": "Peter Gibbons",
"company": "Initech",
"login": "pgibbons",
"financialDetails": {
"creditCards": [
{
"vendor": "Viza",
"lastUse": "2016-10-15"
},
{
"vendor": "MasterCharge",
"lastUse": "2016-10-02"
}
],
"bankAccounts": [
{
"accountType": "checking",
"financialInsitution": "1st Bank of USA"
}
]
},
"interests": "Computer security, numbers and passwords"
}
]
}