更新答:
看着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