解析JSON字符串到.net对象
本文关键字:net 对象 字符串 JSON 解析 | 更新日期: 2023-09-27 18:14:10
我正在用Newtonsoft库将JSON字符串解析为相应的。net对象。我有一个问题解析JSON属性是数组。JSON属性有时是一个数组,有时是单个元素。
的例子:这是。net对象:
public class xx
{
public string yy { get; set; }
public List<string> mm{ get; set; }
}
当我收到这个JSON:
{ "xx": {"yy":"nn", "mm": [ "zzz", "aaa" ] } }
我完全可以做到:
JsonConvert.DeserializeObject<xx>(json);
但有时我收到这个JSON:
{ "xx": {"yy":"nn", "mm":"zzz"} }
反序列化失败是因为c#对象的list属性。
我如何定义一个对象来反序列化同一对象中的两个JSON字符串(与List<string>
)。
-------- UPDATE -----
首先一个WS生成一个XML做一些操作。XML就像
<xx yy='nn'><mm>zzz</mm></xx>
,如果有更多的元素,则为:
<xx yy='nn'><mm>zzz</mm><mm>aaa</mm></xx>
最后WS转换这个XML做:
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var json = JsonConvert.SerializeXmlNode(doc);
并发送给我json..这就是我的问题…
更新答案:
看JSON如何。Net映射XML,它采用的方法是它所看到的就是它所序列化的,除了如果它看到倍数,它将创建一个数组。这对于许多具有一致布局的XML DOM树来说非常好,但不幸的是不能满足您的目的。
您可以通过查看以下文件源中的函数SerializeGroupedNodes()
和SerializeNode()
来验证这一点。
XmlNodeConverter.cs源代码@ 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
类型将导致通过调用DeserializeObject<>
将null
、string
或JArray
分配给mm
。
下面的代码示例演示了这一点。在其他情况下也有可能收到JObject
,这也在本示例中进行了介绍。请注意,成员函数mmAsList()
为您完成了弥补差异的工作。还要注意,我在这里通过为List<string>
返回null
来处理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();
}
}
}
发送服务发送的内容应该符合合同。如果没有,那么好吧,要么你痛打发送的开发人员,让他们修复它,要么发送给你的各种东西是合同。遗憾的是你没有任何元数据可以确定,你只能尝试各种各样的合同,直到一个有效。
object someValue;
try
{
someValue =JsonConvert.DeserializeObject<TypeWithList>(json);
}
catch
{
try
{
someValue = JsonConvert.DeserializeObject<TypeWithString>(json);
}
catch
{
//Darn, yet another type
}
}
在您的情况下,您可以直接使用JsonConvert类
中的静态方法PopulateObject(字符串值,对象目标,JsonSerializerSettings设置);
传递JsonSerializerSettings对象作为
new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.All})
我认为你需要看看你的Javascript对象。如果你显式地声明了要序列化成JSON的对象的属性类型,你应该不会遇到任何不一致的情况。
var stringProperty = new String();
var arrayProperty = new Array();
// Assign value to stringProperty and push elements into arrayProperty
var object = {
stringProperty: stringProperty,
arrayProperty: arrayProperty
};
var jsonObject = JSON.stringify(object);
document.write(jsonObject);
如果你看一下输出,你会发现arrayProperty
总是被序列化成一个数组,无论它有0个、一个还是多个元素。