如何序列化属性上的属性或跳过类层次结构

本文关键字:属性 层次结构 序列化 | 更新日期: 2023-09-27 18:00:06

我有一个使用XmlSerializer序列化的类。除了其他属性之外,我还需要向对象添加一块预构建的xml。我在这篇文章中已经问过如何处理这种xml:如何在序列化对象时删除手动添加的xml字符串上的空名称空间属性?

现在,我需要向包含xml字符串的属性添加一个属性。我知道如何将属性添加到类中,而不是添加到属性中。如果我创建了一个新的类来保存属性,那么我的输出中会有一个额外的层次结构。

这是我的简化代码:

public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    public XmlElement Extension { get; set; }
    public Book()
    {
    }
    public void AddExtension()
    {
        string xmlString = "<AdditionalInfo xmlns='"http://www.somenamespace.com'">" +
                                "<SpecialHandling>Some Value</SpecialHandling>" +
                           "</AdditionalInfo>";
        this.Extension = GetElement(xmlString);
    }
    public static XmlElement GetElement(string xml)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xml);
        return doc.DocumentElement;
    }
}
static void Main(string[] args)
{
    TestSerialization p = new TestSerialization();
    Book bookOne = new Book();
    bookOne.Title = "How to Fix Code";
    bookOne.Author = "Dee Bugger";
    bookOne.AddExtension();
    System.Xml.Serialization.XmlSerializer serializer = new XmlSerializer(typeof(Book), "http://www.somenamespace.com");
    using (var writer = new StreamWriter("C:''BookReport.xml"))
    using (var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings { Indent = true }))
    {
        serializer.Serialize(xmlWriter, bookOne);
    }
}

它生成以下输出:

<?xml version="1.0" encoding="utf-8"?>
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.somenamespace.com">
  <Title>How to Fix Code</Title>
  <Author>Dee Bugger</Author>
  <Extension>
    <AdditionalInfo xmlns="http://www.somenamespace.com">
      <SpecialHandling>Some Value</SpecialHandling>
    </AdditionalInfo>
  </Extension>
</Book>

现在我需要为Extension添加一个属性,使Extension输出看起来像:

...
<Extension Modifier="ABC">
    <AdditionalInfo xmlns="http://www.somenamespace.com">
      <SpecialHandling>Some Value</SpecialHandling>
    </AdditionalInfo>
</Extension>

有没有办法把Book类改成这样?我试图创建一个Extension类来保存xml字符串的Modifier属性和XmlElement,但这导致了一个额外的级别:

public class Extension
{
    [XmlAttribute]
    public string Modifier { get; set; }
    [XmlElementAttribute("Extension")]
    public XmlElement ExtensionAsElement { get; set; }
    public Extension()
    {
    }
    public Extension(XmlElement extensionAsElement)
    {
        this.Modifier = "ABC";
        this.ExtensionAsElement = extensionAsElement;
    }
}
public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    [XmlElementAttribute("Extension")]
    public Extension ExtensionObj { get; set; }
    public Book()
    {
    }
    public void AddExtension()
    {
        string xmlString = "<AdditionalInfo xmlns='"http://www.somenamespace.com'">" +
                                "<SpecialHandling>Some Value</SpecialHandling>" +
                           "</AdditionalInfo>";
        this.ExtensionObj = new Extension(GetElement(xmlString));
    }
    public static XmlElement GetElement(string xml)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xml);
        return doc.DocumentElement;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.somenamespace.com">
  <Title>How to Fix Code</Title>
  <Author>Dee Bugger</Author>
  <Extension Modifier="ABC">
    <Extension>
      <AdditionalInfo xmlns="http://www.somenamespace.com">
        <SpecialHandling>Some Value</SpecialHandling>
      </AdditionalInfo>
    </Extension>
  </Extension>
</Book>

注意:这是我的代码的一个过于简化的例子,Book类不是我的根。我只需要序列化,而不需要反序列化。

如何序列化属性上的属性或跳过类层次结构

您可以使用[XmlAnyElement("Extension")]指定您的Extension属性应作为元素<Extension>本身原样插入XML流中,而不是作为该名称元素的。完成此操作后,您将能够使用SetAttribute()GetAttribute()设置元素本身的属性。

因此,您的Book类变成类似于:

public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    [XmlAnyElement("Extension")]
    public XmlElement Extension { get; set; }
    public Book()
    {
        this.Extension = new XmlDocument().CreateElement("Extension");
    }
    public Book AddExtension()
    {
        string innerXmlString = "<AdditionalInfo xmlns='"http://www.somenamespace.com'">" +
                                "<SpecialHandling>Some Value</SpecialHandling>" +
                           "</AdditionalInfo>";
        if (Extension == null)
            // Since Extension is marked with [XmlAnyElement("Extension")], its value must
            // be an XmlElement named "Extension".  Its InnerXml can be anything.
            Extension = new XmlDocument().CreateElement("Extension");
        Extension.InnerXml = innerXmlString;
        return this;
    }
    const string ModifierName = "Modifier";
    [XmlIgnore]
    public string Modifier
    {
        get
        {
            if (Extension == null)
                return null;
            return Extension.GetAttribute(ModifierName);
        }
        set
        {
            if (Extension == null)
                AddExtension();
            if (value == null)
                Extension.RemoveAttribute(ModifierName);
            else
                Extension.SetAttribute(ModifierName, value);
        }
    }
}

并从以下内容创建XML:

var bookOne = new Book { Title = "How to Fix Code", Author = "Dee Bugger", Modifier = "AAA" }
    .AddExtension();

产生结果:

<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Title>How to Fix Code</Title>
    <Author>Dee Bugger</Author>
    <Extension Modifier="AAA">
        <AdditionalInfo xmlns="http://www.somenamespace.com">
            <SpecialHandling>Some Value</SpecialHandling>
        </AdditionalInfo>
    </Extension>
</Book>