gpt4 book ai didi

c# - 在过滤掉某些属性的同时序列化 JSON.NET JObject

转载 作者:太空狗 更新时间:2023-10-29 21:52:45 30 4
gpt4 key购买 nike

我的代码中有一个大型任意 JSON 结构作为 JObject 引用。

我想序列化这个结构,除非我遇到一个 JObject 包含一个名为 type 且值为 "encrypted" 的属性,那么我想要在写入对象之前删除相邻的 data 属性。

换句话说,如果我遇到这种情况:

{
type: "encrypted",
name: "some-name",
data: "<base64-string>"
}

它将被序列化为:

{
type: "encrypted",
name: "some-name"
}

我不能改变结构,在改变之前克隆它效率太低,所以我尝试使用 JsonConverter 如下:

public class RemoveEncryptedDataSerializer : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(JObject);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var o = (JObject)value;
if (o.Value<string>("type") != "encrypted")
{
o.WriteTo(writer);
return;
}

var copy = o.DeepClone();
copy["data"]?.Parent.Remove();
copy.WriteTo(writer);
}
}

然而,CanConvert 函数似乎只用不是从 JToken 派生的类型调用,所以我的 WriteJson 函数从未被调用。

还有其他方法可以实现吗?


编辑:下面是一些您可以用于测试的代码:

[TestMethod]
public void ItShouldExcludeEncryptedData()
{
var input = JObject.Parse(@"
{
a: {
type: 'encrypted',
name: 'some-name',
data: 'some-data'
}
}");

var expected = JObject.Parse(@"
{
a: {
type: 'encrypted',
name: 'some-name',
}
}");

var output = input.ToString(Formatting.Indented, new RemoveEncryptedDataSerializer());

Assert.AreEqual(
expected.ToString(Formatting.Indented),
output);
}

最佳答案

需要构建转换器来处理 JToken,并且它必须递归工作以确保所有加密数据都被编辑。

我能够让以下转换器工作:

public class RemoveEncryptedDataConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(JToken).IsAssignableFrom(objectType);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JToken token = (JToken)value;
if (token.Type == JTokenType.Object)
{
bool omitDataProperty = token.Value<string>("type") == "encrypted";

writer.WriteStartObject();
foreach (var prop in token.Children<JProperty>())
{
if (omitDataProperty && prop.Name == "data")
continue;

writer.WritePropertyName(prop.Name);
serializer.Serialize(writer, prop.Value); // recurse
}
writer.WriteEndObject();
}
else if (token.Type == JTokenType.Array)
{
writer.WriteStartArray();
foreach (var item in token.Children())
{
serializer.Serialize(writer, item); // recurse
}
writer.WriteEndArray();
}
else // JValue
{
token.WriteTo(writer);
}
}
}

工作演示:https://dotnetfiddle.net/0K61Bz


如果您想直接通过流使用 JsonWriter,您可以将转换器中的逻辑重构为递归扩展方法并使用它。如果您不使用序列化程序,则不需要转换器。

public static class JsonExtensions
{
public static void RedactedWriteTo(this JToken token, JsonWriter writer)
{
if (token.Type == JTokenType.Object)
{
bool omitDataProperty = token.Value<string>("type") == "encrypted";

writer.WriteStartObject();
foreach (var prop in token.Children<JProperty>())
{
if (omitDataProperty && prop.Name == "data")
continue;

writer.WritePropertyName(prop.Name);
prop.Value.RedactedWriteTo(writer); // recurse
}
writer.WriteEndObject();
}
else if (token.Type == JTokenType.Array)
{
writer.WriteStartArray();
foreach (var item in token.Children())
{
item.RedactedWriteTo(writer); // recurse
}
writer.WriteEndArray();
}
else // JValue
{
token.WriteTo(writer);
}
}
}

然后你可以像这样使用它,其中 stream 是你的输出流,input 是你的 JObject:

using (StreamWriter sw = new StreamWriter(stream))  // or StringWriter if you prefer
using (JsonWriter writer = new JsonTextWriter(sw))
{
writer.Formatting = Formatting.Indented;
input.RedactedWriteTo(writer);
}

fiddle :https://dotnetfiddle.net/l949HU

关于c# - 在过滤掉某些属性的同时序列化 JSON.NET JObject,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53669939/

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