.NET中的XML序列化选项

3
我正在构建一个返回XML格式(没有SOAP,没有ATOM,只是普通的XML)的服务。假设我的领域对象已经填充了数据,我只需要将它们转换为XML格式。在.NET上,我有哪些选择呢?
要求:
- 转换不是1:1的。比如说,我有一个地址属性,类型为Address,其中包含嵌套属性,如Line1、City、Postcode等。这可能需要生成类似于`Line1, Postcode`这样完全不同的XML。 - 一些XML元素/属性是有条件的,例如,如果客户未满18岁,则XML需要包含一些额外的信息。 - 我只需要将对象序列化为XML,反之则不重要。 - 一些技术,如数据合同,使用.NET属性。其他配置方式(外部XML配置、伙伴类等)也会有所帮助。
以下是我目前看到的选项。矫正/添加将非常受欢迎。
- 字符串连接 - 忘了它吧,这只是个玩笑 :) - Linq 2 XML - 完全控制但需要编写大量代码,需要良好的单元测试套件。 - ASP.NET MVC中的视图引擎(甚至理论上还有Web Forms),逻辑位于控制器中。问题在于如何结构化,我可以在我的控制器中拥有简单的规则引擎和每个可能输出的一个视图模板,或者直接在模板中进行决策逻辑。两者都有优缺点。 - XML序列化 - 我不确定这里的灵活性。 - 来自WCF的数据合同 - 我也不确定这里的灵活性,而且它们在简单的ASP.NET MVC应用程序(非WCF服务)中是否可用?它们现在是标准XML序列化的超集吗? - 如果存在,则可以使用某些XML-to-object映射器。我越想越觉得我正在寻找这样的东西,但我找不到任何合适的东西。
有什么意见/其他选项吗?

你说你想要一个“XML到对象映射器”,但你也说你只想将对象序列化为XML,而不是反过来。那到底是哪个呢?实际上,XmlSerializer和DataContractSerializer都可以做到这一点;虽然通常应用程序只在一个方向上使用它们。 - Cheeso
你说得对,那很令人困惑。我只需要对象到XML的转换方向。 - Borek Bernard
1个回答

8

Xml序列化工作得很好。您可以使用属性进行配置。

您可以有条件地包含元素。

编辑:我已经更新了代码以反映您更新的问题。

[XmlRoot("pdata")]  // this element name used if serialized to doc root
public class PersonalData
{
     [XmlElement]  // with no name here, elt name = prop name
     public string Name;

     [XmlElement]  // with no name here, elt name = prop name
     public int Age;

     [XmlElement("xaddr")]  // override xml element name 
     public AddressData Address;

     [XmlElement] 
     public Under18Info Other {get; set;}

     // serialize the above element, only if Age < 18
     [XmlIgnore] // do not serialize the *Specified" property in any case
     private bool OtherSpecified {
        get { return Age < 18; }
     }
}

public class AddressData
{
     [XmlIgnore]   // do not serialize (see Composite prop)
     public string Line1 { get; set;}

     [XmlAttribute("city")] // serialize as an attribute on the parent 
     public string City {get; set;}

     [XmlIgnore]   // do not serialize 
     public string Postcode {get; set;}

     [XmlText]   // serialize as the Text node
     public string Composite 
     {
        get { return Line1 + ", " + Postcode; }
        set {
          var split = value.Split(',');
          Line1 = split[0];
          Postcode= split[1];
        }
     }
}

然后,要将该实例序列化为字符串,例如:

var pdata = new PersonalData
    {
        Name = "Gordon Brown",
        Age = 57,
        Address = new AddressData
        {
            Line1 = "10 Downing St.",
            Postcode = "1QR 3E4",
            City = "London"
        }
    };

var ns= new System.Xml.Serialization.XmlSerializerNamespaces();
ns.Add( "", "");
var s1 = new XmlSerializer(typeof(PersonalData));
var builder = new System.Text.StringBuilder();
var xmlws = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
using ( var writer = System.Xml.XmlWriter.Create(builder, xmlws))
{
    s1.Serialize(writer, pdata, ns);
}
string xml = builder.ToString();

结果:

<pdata>
  <Name>Gordon Brown</Name>
  <Age>57</Age>
  <xaddr city="London">10 Downing St., 1QR 3E4</xaddr>
</pdata>

在最坏的情况下,如果 XML 序列化器不能提供您想要的内容,您总可以编写自己的序列化器。 - user170442
抱歉,我错误地格式化了XML示例(地址等),但无论如何感谢您的回复。您知道吗,数据契约是否类似甚至比这个旧的XML序列化更灵活? - Borek Bernard
你也可以使用DataContractSerializer。它很相似。在某些方面,DCS比XmlSerializer更灵活;但在大多数方面,它则不如后者。http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/ - Cheeso
根据你的更新问题,我更新了代码。我建议你在一个合成复合属性上使用XmlTextAttribute来序列化地址以符合你的要求。 - Cheeso
这个例子看起来足够简单,但是我不太喜欢演示问题泄露到模型中的方式。例如,我可能有一个以上的XML表示形式(比如说一个用于公共消费,一个用于内部存储),或者业务规则可能来自其他地方。XML序列化对这些问题有答案吗,还是我应该寻找其他地方? - Borek Bernard
使用XmlSerializer,您可以指定“属性覆盖”以覆盖源代码中存在的属性。 - Cheeso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接