0

对于子类“作业”的所有属性,我有一个丑陋的要求,以序列化为包装在 CDATA 标记中的 XML。这是规范: http: //www.indeed.com/intl/en/xmlinfo.html

我找到的所有答案都建议了一种适用于一个或两个属性的方法,而不是整个类。例如:如何使用 XmlSerializer 将字符串序列化为 CDATA?

该文章中的一条评论建议在单个类上实现 IXmlSerializable。听起来这可能是一种更好的方法,因为我的作业类上的每个属性都需要 CDATA 包装器,而我在其他任何地方都没有这个要求。但是,如果有一个 per-property 成员可以覆盖序列化程序,我可以在执行此操作时利用它,那就更好了。

关于如何将 CDATA 实现从 200 行代码减少到 10 行的任何想法?如果没有 CDATA 要求,这将是多么简单:

public class job {
    public string title { get; set; }
    public DateTime date { get; set; }
    public int referencenumber { get; set; }
    public string url { get; set; }
    public string company { get; set; }
    public string city { get; set; }
    public string state { get; set; }
    public string country { get; set; }
    public string postalcode { get; set; }
    public string description { get; set; }
    public string salary { get; set; }
    public string category { get; set; }
    public string experience { get; set; }

    public job(DataModel.PostedJob postedJob, UrlHelper urlHelper) {
        country = "US";
        category = "contract, project, consulting";
        title = postedJob.Title;
        date = postedJob.PostedOn;
        referencenumber = postedJob.Id;
        url = urlHelper.Action(MVC.SearchJobs.Index(postedJob.Id));
        company = postedJob.Company;
        city = postedJob.City;
        state = postedJob.State;
        postalcode = postedJob.PostalCode;
        description = postedJob.Description;
        experience = postedJob.MinYears.ToString() + "+ years";
    }

    public job() { }
}

编辑:请注意,我目前正在使用此处显示的 MvcContrib“XmlResult”代码片段对其进行序列化:Return XML from a controller's action in as an ActionResult? ...属性名称本身的非传统情况反映了上面链接的规范所需的 XML 模式。我认为由于视图模型属性通常与消费者紧密耦合,因此它是合适的,但请随时纠正我。

4

1 回答 1

1

如果一切都很简单,您可以使用 LINQ to XML 编写自己的序列化程序。

这是一个非常粗糙的版本......您需要使其涵盖您需要的所有类型,并在必要时考虑如何表示空引用。

using System;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;

class Foo
{
    public string Name { get; set; }
    public int Value { get; set; }
    public DateTime When { get; set; }
}

class Test
{
    static void Main()
    {
        Foo foo = new Foo { 
            Name = "Jon", 
            Value = 5,
            When = DateTime.Now
        };

        XElement element = Serialize("Foo", foo);
        Console.WriteLine(element);
        Foo bar = Deserialize<Foo>(element);
        Console.WriteLine("Deserialized values:");
        Console.WriteLine("{0}, {1}, {2}", 
                          bar.Name, bar.Value, bar.When);
    }

    static XElement Serialize(XName elementName,
                              object value)
    {
        return new XElement(elementName,
          value.GetType()
               .GetProperties()
               .Select(p => new XElement
                   (p.Name, ConvertValue(p.GetValue(value, null)))));

    }

    static XCData ConvertValue(object value)
    {
        // This is a bit odd. It takes advantage of LINQ
        // to XML being nice with XElement, but not for
        // XCData
        XElement tmp = new XElement("ignored", value);
        return new XCData(tmp.Value);
    }

    static T Deserialize<T>(XElement element) where T : new()
    {
        T ret = new T();
        foreach (var sub in element.Elements())
        {
            var property = typeof(T).GetProperty(sub.Name.LocalName);
            SetProperty(property, sub, ret);
        }
        return ret;
    }

    static void SetProperty(PropertyInfo property,
                            XElement element,
                            object target)
    {
        // This is somewhat annoying. There should be a better
        // way...
        var type = property.PropertyType;
        object value;
        if (type == typeof(string))
        {
            value = (string) element;
        } 
        else if (type == typeof(int))
        {
            value = (int) element;
        }
        else if (type == typeof(DateTime))
        {
            value = (DateTime) element;
        }
        // ...
        else
        {
            throw new Exception("Can't convert " + type);
        }
        property.SetValue(target, value, null);
    }
}
于 2012-08-02T06:31:18.210 回答