更新答:
看着JSON.Net地图XML如何,它采用的方法是什么看到的是什么序列化,但如果看到的倍数,它将使一个数组。对于许多具有一致布局的XML DOM树来说,这非常棒,但不幸的是,它无法满足您的需求。
您可以通过在以下文件源中查看函数SerializeGroupedNodes()
和SerializeNode()
的函数来验证此情况。
XmlNodeConverter.cs source code @ CodePlex, ChangeSet #63616
还有,我以前还以为可能是矫枉过正,但现在将是有益的,我们知道,从上月底序列化的默认行为会发生什么其他的选择。
Json.Net支持使用从JsonConverter
派生的自定义转换器来根据具体情况映射特定值的情况。
我们可以在序列化一侧或反序列化一侧处理这个问题。我选择在反序列化方面编写解决方案,因为您可能有其他现有的将XML映射到JSON的原因。
一个很大的好处是你的类可以保持完整除了覆盖,这就要求你应用一个属性。以下是演示如何使用JsonAttribute
和自定义转换器类(MMArrayConverter
)来解决您的问题的代码示例。请注意,您可能会想要更彻底地测试此更新,也许可以更新转换器以处理其他情况,例如,如果您最终迁移到IList<string>
或其他一些时髦的案例,如Lazy<List<string>>
,甚至可以使其与泛型一起工作。
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
namespace JsonArrayImplictConvertTest
{
public class MMArrayConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.Equals(typeof(List<string>));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.StartArray)
{
List<string> parseList = new List<string>();
do
{
if (reader.Read())
{
if (reader.TokenType == JsonToken.String)
{
parseList.Add((string)reader.Value);
}
else
{
if (reader.TokenType == JsonToken.Null)
{
parseList.Add(null);
}
else
{
if (reader.TokenType != JsonToken.EndArray)
{
throw new ArgumentException(string.Format("Expected String/Null, Found JSON Token Type {0} instead", reader.TokenType.ToString()));
}
}
}
}
else
{
throw new InvalidOperationException("Broken JSON Input Detected");
}
}
while (reader.TokenType != JsonToken.EndArray);
return parseList;
}
if (reader.TokenType == JsonToken.Null)
{
// TODO: You need to decide here if we want to return an empty list, or null.
return null;
}
if (reader.TokenType == JsonToken.String)
{
List<string> singleList = new List<string>();
singleList.Add((string)reader.Value);
return singleList;
}
throw new InvalidOperationException("Unhandled case for MMArrayConverter. Check to see if this converter has been applied to the wrong serialization type.");
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Not implemented for brevity, but you could add this if needed.
throw new NotImplementedException();
}
}
public class ModifiedXX
{
public string yy { get; set; }
[JsonConverter(typeof(MMArrayConverter))]
public List<string> mm { get; set; }
public void Display()
{
Console.WriteLine("yy is {0}", this.yy);
if (null == mm)
{
Console.WriteLine("mm is null");
}
else
{
Console.WriteLine("mm contains these items:");
mm.ForEach((item) => { Console.WriteLine(" {0}", item); });
}
}
}
class Program
{
static void Main(string[] args)
{
string jsonTest1 = "{\"yy\":\"nn\", \"mm\": [ \"zzz\", \"aaa\" ] }";
ModifiedXX obj1 = JsonConvert.DeserializeObject<ModifiedXX>(jsonTest1);
obj1.Display();
string jsonTest2 = "{\"yy\":\"nn\", \"mm\": \"zzz\" }";
ModifiedXX obj2 = JsonConvert.DeserializeObject<ModifiedXX>(jsonTest2);
obj2.Display();
// This test is now required in case we messed up the parser state in our converter.
string jsonTest3 = "[{\"yy\":\"nn\", \"mm\": [ \"zzz\", \"aaa\" ] },{\"yy\":\"nn\", \"mm\": \"zzz\" }]";
List<ModifiedXX> obj3 = JsonConvert.DeserializeObject<List<ModifiedXX>>(jsonTest3);
obj3.ForEach((obj) => { obj.Display(); });
Console.ReadKey();
}
}
}
原来的答案:
这将是最好的解决你的源接收的JSON,因为许多人已经指出。您可能希望发布更新,显示更新后的评论中的XML如何映射到JSON,因为这将是整个最佳路线。
但是,如果您发现这是不可能的,并且您希望以某种方式序列化并事后处理变体值,则可以声明mm
为object
,然后处理可能的事件您可以使用JSON.Net的Linq支持。在您描述的两种情况下,您会发现声明mm
为object
类型将导致null
,string
或JArray
通过调用DeserializeObject<>
而被指定为mm
。
下面是一个代码示例,显示了这一行为。在其他情况下,您也可以收到一个JObject
,这也在本示例中介绍。请注意,成员函数mmAsList()
会为您修补差异。还请注意,我已通过返回null
代替List<string>
处理了null
;你可能会想要修改这个实现。
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace JsonArrayUnionTest
{
public class ModifiedXX
{
public string yy { get; set; }
public object mm { get; set; }
public List<string> mmAsList()
{
if (null == mm) { return null; }
if (mm is JArray)
{
JArray mmArray = (JArray)mm;
return mmArray.Values<string>().ToList();
}
if (mm is JObject)
{
JObject mmObj = (JObject)mm;
if (mmObj.Type == JTokenType.String)
{
return MakeList(mmObj.Value<string>());
}
}
if (mm is string)
{
return MakeList((string)mm);
}
throw new ArgumentOutOfRangeException("unhandled case for serialized value for mm (cannot be converted to List<string>)");
}
protected List<string> MakeList(string src)
{
List<string> newList = new List<string>();
newList.Add(src);
return newList;
}
public void Display()
{
Console.WriteLine("yy is {0}", this.yy);
List<string> mmItems = mmAsList();
if (null == mmItems)
{
Console.WriteLine("mm is null");
}
else
{
Console.WriteLine("mm contains these items:");
mmItems.ForEach((item) => { Console.WriteLine(" {0}", item); });
}
}
}
class Program
{
static void Main(string[] args)
{
string jsonTest1 = "{\"yy\":\"nn\", \"mm\": [ \"zzz\", \"aaa\" ] }";
ModifiedXX obj1 = JsonConvert.DeserializeObject<ModifiedXX>(jsonTest1);
obj1.Display();
string jsonTest2 = "{\"yy\":\"nn\", \"mm\": \"zzz\" }";
ModifiedXX obj2 = JsonConvert.DeserializeObject<ModifiedXX>(jsonTest2);
obj2.Display();
Console.ReadKey();
}
}
}
不能更改JSON生产方式?因为这种方式很不一致,而且总是生成一个数组更有意义。 – svick
为什么传入的JSON对象的格式不一致?如果'mm'可能包含多个元素,它应该总是以数组形式传递('[]'),而不是简单的'name:value'对。 –
您应该能够在将JSON发送到服务器之前对其进行按摩,以使其始终处于可用的格式。显示用于构造JSON对象的JS。 – arb