【问题标题】:Deserialize/Read xml when casing of elements is inconsistent.当元素的大小写不一致时反序列化/读取 xml。
【发布时间】:2017-08-19 21:51:19
【问题描述】:

我目前很高兴为第 3 方编写一个接口,其精彩的 web 服务根据响应类型以不同的 xml 大小写响应。即使给出相同的请求,大小写也会根据结果是否成功、错误、错误类型等而有所不同。你明白了,这是一场噩梦。

据我所知,没有不区分大小写的反序列化器可用。 到目前为止,我得到的最好的方法是将 xml 解析为 XElement 并尝试一些常见的大小写,例如 Pasal Casing、Camel Casing、小写等。

有更好的建议吗?

【问题讨论】:

标签: c# xml parsing deserialization


【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-28
    • 1970-01-01
    相关资源
    最近更新 更多