[英]Serializing a JSON.NET JObject while filtering out certain properties
我的代碼中有一個大的任意JSON結構作為JObject
引用。
我想序列化這個結構,除非我遇到一個包含一個名為type
的屬性的JObject
,其值為"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
派生的類型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);
}
小提琴: https : //dotnetfiddle.net/l949HU
假設您使用的是Newtonsoft JSON.Net庫;
要有條件地序列化屬性,請添加一個返回與該屬性同名的布爾值的方法,然后使用ShouldSerialize作為方法名稱的前綴。 方法的結果確定屬性是否已序列化。 如果該方法返回true,則該屬性將被序列化,如果它返回false,則將跳過該屬性。
對於你的例子:
public class EncryptedData
{
public string Type { get; set; }
public string Name { get; set; }
public string Data { get; set; }
public bool ShouldSerializeData()
{
// don't serialize the Data property if the Type equals "encrypted"
return (Type != "encrypted");
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.