我目前很高兴为第三方编写接口,其精彩的web服务根据响应类型以不同的xml大小写响应。即使给出相同的请求,套管也会有所不同,具体取决于结果是否成功,错误,错误类型等等。你得到了这一点,这是一场噩梦。
据我所知,没有可用的不区分大小写的反序列化器。 到目前为止,最好的ive是将xml解析为XElement并尝试一些常见的外壳,如Pasal Casing,Camel Casing,小写等。
有更好的建议吗?
答案 0 :(得分:1)
一种选择是在反序列化之前使用XSLT转换将所有节点和属性名称转换为小写。有关必要的XSLT转换,请参阅this answer;有关在c#中使用XSLT转换的说明,请参阅this question。
另一种选择是使用Json.NET从XML转换为JSON,如Converting between JSON and XML所示,然后使用Json.NET反序列化,即case insensitive。您需要了解XML和JSON之间的一个不一致,即JSON具有数组的概念,而XML则不然,因此使用重复元素来表示数组。 Json.NET的XML-to-JSON converter检测重复元素并将它们转换为数组,但是当XML数组只有一个元素时,这不会发生。在这种情况下,有必要按照Convert XML to JSON and force array中的说明操作,并将json:Array='true'
属性添加到XML中。
因此,您可以介绍以下扩展方法:
public static class JsonExtensions
{
const string JsonNamespace = @"http://james.newtonking.com/projects/json";
const string ArrayAttributeName = @"Array";
public static JToken ToJToken(this XElement xElement, bool omitRootObject, string deserializeRootElementName)
{
return xElement.ToJToken(omitRootObject, deserializeRootElementName, Enumerable.Empty<Func<XElement, IEnumerable<XElement>>>());
}
public static JToken ToJToken(this XElement xElement, bool omitRootObject, string deserializeRootElementName, IEnumerable<Func<XElement, IEnumerable<XElement>>> arrayQueries)
{
foreach (var query in arrayQueries)
{
var name = XName.Get(ArrayAttributeName, JsonNamespace);
foreach (var element in query(xElement))
{
element.SetAttributeValue(name, true);
}
}
// Convert to Linq to XML JObject
var settings = new JsonSerializerSettings { Converters = { new XmlNodeConverter { OmitRootObject = omitRootObject, DeserializeRootElementName = deserializeRootElementName } } };
var root = JToken.FromObject(xElement, JsonSerializer.CreateDefault(settings));
return root;
}
}
然后,给出以下XML:
<root>
<perSon ID='1'>
<name>Alan</name>
<url>http://www.google.com</url>
</perSon>
</root>
以下类型:
public class Person
{
public string Name { get; set; }
public string URL { get; set; }
[XmlAttribute(AttributeName = "id")]
[JsonProperty("@id")]
public string Id { get; set; }
}
public class Root
{
[XmlElement]
public List<Person> Person { get; set; }
}
您可以按如下方式反序列化XML:
var xElement = XElement.Parse(xml);
var jToken = xElement.ToJToken(true, "",
new Func<XElement, IEnumerable<XElement>> [] { e => e.Elements().Where(i => string.Equals(i.Name.LocalName, "Person", StringComparison.OrdinalIgnoreCase)) });
var root = jToken.ToObject<Root>();
示例fiddle。