我可以将匿名类型序列化为xml吗?

Rad*_*adu 51 .net xml serialization anonymous-types

我知道匿名类型被编译器标记为私有,属性是只读的.有没有办法将它们序列化为xml(没有反序列化)?它适用于JSON,我如何使用XML?

Mat*_*ted 68

这样的事情应该让你开始......

class Program
{
    static void Main(string[] args)
    {
        var me = new
        {
            Hello = "World",
            Other = new
            {
                My = "Object",
                V = 1,
                B = (byte)2
            }
        };

        var x = me.ToXml();
    }
}
public static class Tools
{
    private static readonly Type[] WriteTypes = new[] {
        typeof(string), typeof(DateTime), typeof(Enum), 
        typeof(decimal), typeof(Guid),
    };
    public static bool IsSimpleType(this Type type)
    {
        return type.IsPrimitive || WriteTypes.Contains(type);
    }
    public static XElement ToXml(this object input)
    {
        return input.ToXml(null);
    }
    public static XElement ToXml(this object input, string element)
    {
        if (input == null)
            return null;

        if (string.IsNullOrEmpty(element))
            element = "object";
        element = XmlConvert.EncodeName(element);
        var ret = new XElement(element);

        if (input != null)
        {
            var type = input.GetType();
            var props = type.GetProperties();

            var elements = from prop in props
                           let name = XmlConvert.EncodeName(prop.Name)
                           let val = prop.GetValue(input, null)
                           let value = prop.PropertyType.IsSimpleType()
                                ? new XElement(name, val)
                                : val.ToXml(name)
                           where value != null
                           select value;

            ret.Add(elements);
        }

        return ret;
    }
}
Run Code Online (Sandbox Code Playgroud)

...结果xml ...

<object>
  <Hello>World</Hello>
  <Other>
    <My>Object</My>
    <V>1</V>
    <B>2</B>
  </Other>
</object>
Run Code Online (Sandbox Code Playgroud)

  • 嘿 - 你的代码就像一个魅力.我做了一些细微的变化,所以它支持数组,我写在这里:http://martinnormark.com/serialize-c-dynamic-and-anonymous-types-to-xml (3认同)
  • 这应该被选为正确的答案 (2认同)

Joh*_*ers 26

使用XmlSerializernor也无法实现DataContractSerializer.它可以通过手动编写的代码来完成,如下所示(我无法评论代码是否足够全面以处理所有类型 - 但这是一个非常好的开始).

  • 但这并不意味着你不能用第三方课程来做. (3认同)
  • 我相信马修斯在下面的回答是正确的答案.我接受了他的代码并开箱即用 - 我做了一些修改以使其支持Arrays:http://martinnormark.com/serialize-c-dynamic-and-anonymous-types-to-xml (3认同)

ric*_*rdo 24

谢谢你,出色的工作@Matthew和@Martin.

我做了一些修改来容纳Nullables和Enums.我也改变了它,以便根据属性+索引的名称命名数组元素.

如果有人有兴趣,这是代码

public static class ObjectExtensions {
    #region Private Fields
    private static readonly Type[] WriteTypes = new[] {
        typeof(string), typeof(DateTime), typeof(Enum), 
        typeof(decimal), typeof(Guid),
    };
    #endregion Private Fields
    #region .ToXml
    /// <summary>
    /// Converts an anonymous type to an XElement.
    /// </summary>
    /// <param name="input">The input.</param>
    /// <returns>Returns the object as it's XML representation in an XElement.</returns>
    public static XElement ToXml(this object input) {
        return input.ToXml(null);
    }

    /// <summary>
    /// Converts an anonymous type to an XElement.
    /// </summary>
    /// <param name="input">The input.</param>
    /// <param name="element">The element name.</param>
    /// <returns>Returns the object as it's XML representation in an XElement.</returns>
    public static XElement ToXml(this object input, string element) {
        return _ToXml(input, element);
    }

    private static XElement _ToXml(object input, string element, int? arrayIndex = null, string arrayName = null) {
        if (input == null)
            return null;

        if (String.IsNullOrEmpty(element)) {
            string name = input.GetType().Name;
            element = name.Contains("AnonymousType") 
                ? "Object" 
                : arrayIndex != null
                    ? arrayName + "_" + arrayIndex
                    : name;
        }

        element = XmlConvert.EncodeName(element);
        var ret = new XElement(element);

        if (input != null) {
            var type = input.GetType();
            var props = type.GetProperties();

            var elements = props.Select(p => {
                var pType = Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType;
                var name = XmlConvert.EncodeName(p.Name);
                var val = pType.IsArray ? "array" : p.GetValue(input, null);
                var value = pType.IsArray 
                    ? GetArrayElement(p, (Array)p.GetValue(input, null))
                    : pType.IsSimpleType() || pType.IsEnum 
                        ? new XElement(name, val) 
                        : val.ToXml(name);
                return value;
            })
            .Where(v=>v !=null);

            ret.Add(elements);
        }

        return ret;
    }

    #region helpers
    /// <summary>
    /// Gets the array element.
    /// </summary>
    /// <param name="info">The property info.</param>
    /// <param name="input">The input object.</param>
    /// <returns>Returns an XElement with the array collection as child elements.</returns>
    private static XElement GetArrayElement(PropertyInfo info, Array input) {
        var name = XmlConvert.EncodeName(info.Name);

        XElement rootElement = new XElement(name);

        var arrayCount = input == null ? 0 : input.GetLength(0);

        for (int i = 0; i < arrayCount; i++) {
            var val = input.GetValue(i);
            XElement childElement = val.GetType().IsSimpleType() ? new XElement(name + "_" + i, val) : _ToXml(val, null, i, name);

            rootElement.Add(childElement);
        }

        return rootElement;
    }

    #region .IsSimpleType
    public static bool IsSimpleType(this Type type) {
        return type.IsPrimitive || WriteTypes.Contains(type);
    }
    #endregion .IsSimpleType

    #endregion helpers
    #endregion .ToXml
}
Run Code Online (Sandbox Code Playgroud)


Pav*_*vel 7

我知道这是一篇旧帖子,但我的解决方案仅用2 行代码将匿名类型转换为 XML 。

首先将您的匿名类型转换为 JSON,然后从 JSON 转换为 XML。

var jsonText = JsonConvert.SerializeObject(data);           // convert to JSON
XmlDocument doc = JsonConvert.DeserializeXmlNode(jsonText); // convert JSON to XML Document
Run Code Online (Sandbox Code Playgroud)

样本

var data = new       // data - Anonymous Type
{
    Request = new
    {
        OrderNumber = 123,
        Note = "Hello World"
    }
};

var jsonText = JsonConvert.SerializeObject(data);           
XmlDocument doc = JsonConvert.DeserializeXmlNode(jsonText);

Console.WriteLine(doc.OuterXml);                            
Run Code Online (Sandbox Code Playgroud)

输出

<Request>
    <OrderNumber>123</OrderNumber>
    <Note>Hello World</Note>
</Request>
Run Code Online (Sandbox Code Playgroud)