普通 Json 的对象表示应该是这样的:
using J = Newtonsoft.Json.JsonPropertyAttribute;
public partial class Data
{
[J("isDemo")] public bool? IsDemo { get; set; }
[J("Asynchronous")] public bool? IsAsynchronous { get; set; }
[J("OrderId")] public string OrderId { get; set; }
[J("CustomerReference")] public string CustomerReference { get; set; }
[J("Fee")] public double? Fee { get; set; }
}
虽然有一个自定义的JsonConverter 来处理整个 Xml 表示会很好。我发现很难编写和维护。
你应该分而治之:
- 生成一个表示 Xml-ish Json 的类。
- 删除不必要的属性,在需要的地方保留 Xml“nil”
- 创建简单的自定义转换器,将字符串表示映射到正确的类型。
例如:“真”=>布尔,“123”=>整数,
public partial class XmlRepresentation
{
[J("isDemo")] public BoolWrapper IsDemo { get; set; }
[J("Asynchronous")] public BoolWrapper Asynchronous { get; set; }
[J("Fee")] public DoubleWrapper Fee { get; set; }
[J("CustomerReference")] public StringWrapper CustomerReference { get; set; }
[J("OrderId")] public string OrderId { get; set; }
}
public partial class NullableXmlValue
{
[J("@xsi:nil")][JsonConverter(typeof(BoolParseStringConverter))]
public bool IsNull { get; set; }
}
public partial class BoolWrapper :NullableXmlValue
{
[J("#text")][JsonConverter(typeof(BoolParseStringConverter))]
public bool Value { get; set; }
}
public partial class StringWrapper :NullableXmlValue
{
[J("#text")] public string Value { get; set; }
}
public partial class DoubleWrapper :NullableXmlValue
{
[J("#text")][JsonConverter(typeof(DoubleParseStringConverter))]
public double Value { get; set; }
}
使用一些简单的 String 类型 {Bool, Double} 解析器:
internal class BoolParseStringConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(bool) || t == typeof(bool?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
var value = serializer.Deserialize<string>(reader);
if (Boolean.TryParse(value, out bool b))
{
return b;
}
throw new Exception("Cannot unmarshal type bool");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (bool)untypedValue;
var boolString = value ? "true" : "false";
serializer.Serialize(writer, boolString);
return;
}
public static readonly BoolParseStringConverter Singleton = new BoolParseStringConverter();
}
internal class DoubleParseStringConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(double) || t == typeof(double?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
var value = serializer.Deserialize<string>(reader);
if (Double.TryParse(value, out double l))
{
return l;
}
throw new Exception("Cannot unmarshal type long");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (double)untypedValue;
serializer.Serialize(writer, value.ToString());
return;
}
public static readonly DoubleParseStringConverter Singleton = new DoubleParseStringConverter();
}
这样就可以直接反序列化为XmlRepresentation,使用简单的投影逻辑来获取Data。
public partial class XmlRepresentation
{
public Data ToDataType(){
var result = new Data();
if( !this.IsDemo?.IsNull ?? false)
result.IsDemo = this.IsDemo.Value;
// etc..
return result;
}
}
为了知道它是普通的 Json 还是 Xml-ish 的,我将简单地使用 try catch。
这样我就不必编写复杂的 JsonConverter 或代表 Normal 和 Xml-ish 的类。