在元素中将属性序列化为Xml属性


69

我有以下课程:

[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>

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

Answers:


95

您将需要包装器类:

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>

5
是的,这给了我所需的XML模式,但它为模型增加了不必要的间接和复杂性。现在我有了Object.SomeProperty.Value,而不仅仅是Object.SomeProperty。我意识到使用内置的序列化可能无法同时使用这两种方法,但这是问题的本质。
IUnknown 2012年

2
我知道这有点老了,但是我会添加从T到的隐式强制转换操作,SomeInfo<T>反之亦然。
Shago

令人苦恼的是我们必须以这种方式对XmlSerializer进行这种基本处理,但这确实给了我一个可用的选择。
Suncat2000

8

有点,请使用XmlAttribute代替XmlElement,但看起来不会像您想要的那样。它将如下所示:

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

我能想到的(本机)实现的唯一方法是拥有指向名为SomeStringElementName和SomeInfoElementName的对象的属性,其中该类包含一个名为“ value”的单一吸气剂。您可以更进一步,并使用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 2012年

1
@IUnknown-我提出了一种实现您想要的方法。创建类来获取节点不是很漂亮,所以如果其他人知道更好的方法,我也会很感兴趣。
克里斯·盖斯勒
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.