【问题标题】:Serialize Property as Xml Attribute in Element将属性序列化为元素中的 Xml 属性
【发布时间】:2012-07-05 01:11:27
【问题描述】:

我有以下课程:

[Serializable]
public class SomeModel
{
    [XmlElement("SomeStringElementName")]
    public string SomeString { get; set; }

    [XmlElement("SomeInfoElementName")]
    public int SomeInfo { get; set; }
}

使用 XmlSerializer.Serialize() 进行序列化(填充一些测试数据时)会产生以下 XML:

<SomeModel>
  <SomeStringElementName>testData</SomeStringElementName>
  <SomeInfoElementName>5</SomeInfoElementName>
</SomeModel>

我需要的是:

<SomeModel>
  <SomeStringElementName Value="testData" />
  <SomeInfoElementName Value="5" />
</SomeModel>

有没有办法在不编写我自己的自定义序列化代码的情况下将其指定为属性?

【问题讨论】:

    标签: c# .net xml xml-serialization


    【解决方案1】:

    您将需要包装类:

    public class SomeIntInfo
    {
        [XmlAttribute]
        public int Value { get; set; }
    }
    
    public class SomeStringInfo
    {
        [XmlAttribute]
        public string Value { get; set; }
    }
    
    public class SomeModel
    {
        [XmlElement("SomeStringElementName")]
        public SomeStringInfo SomeString { get; set; }
    
        [XmlElement("SomeInfoElementName")]
        public SomeIntInfo SomeInfo { get; set; }
    }
    

    如果您愿意,也可以使用更通用的方法:

    public class SomeInfo<T>
    {
        [XmlAttribute]
        public T Value { get; set; }
    }
    
    public class SomeModel
    {
        [XmlElement("SomeStringElementName")]
        public SomeInfo<string> SomeString { get; set; }
    
        [XmlElement("SomeInfoElementName")]
        public SomeInfo<int> SomeInfo { get; set; }
    }
    

    然后:

    class Program
    {
        static void Main()
        {
            var model = new SomeModel
            {
                SomeString = new SomeInfo<string> { Value = "testData" },
                SomeInfo = new SomeInfo<int> { Value = 5 }
            };
            var serializer = new XmlSerializer(model.GetType());
            serializer.Serialize(Console.Out, model);
        }
    }
    

    将产生:

    <?xml version="1.0" encoding="ibm850"?>
    <SomeModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <SomeStringElementName Value="testData" />
      <SomeInfoElementName Value="5" />
    </SomeModel>
    

    【讨论】:

    • 是的,这为我提供了所需的 XML 模式,但它为模型增加了不必要的间接性和复杂性。现在,不仅仅是 Object.SomeProperty,我还有 Object.SomeProperty.Value。我意识到我可能无法同时使用内置序列化 - 但这是问题的本质。
    • 我知道这有点老了,但我会添加从 TSomeInfo&lt;T&gt; 的隐式转换操作,反之亦然。
    • 我们不得不以这种方式破解 XmlSerializer 来进行这样的基本处理,这很令人痛苦,但它确实给了我一个可用的选择。
    【解决方案2】:

    有点,使用XmlAttribute 而不是XmlElement,但它看起来不像你想要的。它将如下所示:

    <SomeModel SomeStringElementName="testData"> 
    </SomeModel> 
    

    我能想到的实现您想要的(本机)的唯一方法是让属性指向名为 SomeStringElementName 和 SomeInfoElementName 的对象,其中类包含一个名为“value”的 getter。您可以更进一步并使用 DataContractSerializer 以便包装类可以是私有的。 XmlSerializer 不会读取私有属性。

    // TODO: make the class generic so that an int or string can be used.
    [Serializable]  
    public class SerializationClass
    {
        public SerializationClass(string value)
        {
            this.Value = value;
        }
    
        [XmlAttribute("value")]
        public string Value { get; }
    }
    
    
    [Serializable]                     
    public class SomeModel                     
    {                     
        [XmlIgnore]                     
        public string SomeString { get; set; }                     
    
        [XmlIgnore]                      
        public int SomeInfo { get; set; }  
    
        [XmlElement]
        public SerializationClass SomeStringElementName
        {
            get { return new SerializationClass(this.SomeString); }
        }               
    }
    

    【讨论】:

    • 嘿,克里斯,是的,我可以使用 XmlAttribute,但正如您所说,它不能提供我需要的结果。我希望能够在不编写自己的序列化代码的情况下得到我需要的东西。
    • @IUnknown - 我拼凑了一种可能的方式来实现你想要的。创建类来获取节点并不漂亮,所以如果其他人知道更好的方法,我也会感兴趣。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多