用于序列化为XML的类,列表中具有不同的节点结构

时间:2013-12-19 13:55:24

标签: c# xml serialization xml-serialization xmlserializer

我想创建一个可序列化的C#类,它将序列化为:

<metadata>
    <entry key="">
        <dimensionInfo>
            <enabled>false</enabled>
        </dimensionInfo>
    </entry>
    <entry key="">false</entry>
</metadata>
你能帮帮我吗?我无法处理不同的entry节点结构:/对我来说太难了:P

6 个答案:

答案 0 :(得分:2)

让我们从层次结构中的最低级开始:

[Serializable]
public class DimensionInfo
{
    [XmlElement("enabled")]
    public Boolean Enabled { get; set; }
    public DimensionInfo()
    {
    }
}

如你所见,这里没什么特别的。然后,继续下一步:

[Serializable]
public class Entry
{
    private DimensionInfo _dimensionInfo = default(DimensionInfo);
    private Boolean _containsDimensionInfo = true;

    [XmlAttribute("key")]
    public String Key { get; set; }

    [XmlText(typeof(String))]
    public String ContainsDimensionInfo
    {
        get
        {
            return CheckDimensionContaining().ToString().ToLower();
        }
        set
        {
            _containsDimensionInfo = Boolean.Parse(value);
        }
    }

    [XmlIgnore]
    public Boolean ContainsDimensionInfoSpecified
    {
        get { return !CheckDimensionContaining(); }
    }

    [XmlElement("dimensionInfo")]
    public DimensionInfo DimensionInfo
    {
        get { return _dimensionInfo; }
        set { _dimensionInfo = value; }
    }

    [XmlIgnore]
    public Boolean DimensionInfoSpecified
    {
        get { return CheckDimensionContaining(); }
    }

    public Entry()
    {
        Key = String.Empty;
        CheckDimensionContaining();
    }

    private Boolean CheckDimensionContaining()
    {
        return _containsDimensionInfo = _dimensionInfo != default(DimensionInfo);
    }
}

魔法开始了。使用选择性XmlIgnoreAttribute,我们可以决定对象序列化的方式。主类只包含一个条目列表:

[Serializable]
[XmlRoot("metadata")]
public class Metadata
{
    [XmlElement("entry")]
    public List<Entry> Entries { get; set; }

    public Metadata()
    {
        Entries = new List<Entry>();
    }
}

如何制作:条目包含 dimensionInfo (如果存在), false (如果不存在)。在控制台中试用代码示例:

Metadata metadata = new Metadata();
metadata.Entries.Add(new Entry()); //Adding empty entry
//Adding entry with info
metadata.Entries.Add(new Entry() { DimensionInfo = new DimensionInfo() });
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Metadata));
using (FileStream fileStream = new FileStream("info.txt", FileMode.Create))
{
    xmlSerializer.Serialize(fileStream, metadata);
}

它给了我以下输出:

<metadata>
  <entry key="">false</entry>
  <entry key="">
    <dimensionInfo>
      <enabled>false</enabled>
    </dimensionInfo>
  </entry>
</metadata>

然而,这段代码并不完美,还有很多东西需要改进,但现在你知道它是如何工作的

答案 1 :(得分:1)

如果您遇到需要通过.Net使用的XML文件,则会有一个工具XML Schema Definition Tool (Xsd.exe)自动执行转换。

  

它是一个命令行工具并打开它,你使用开始&gt;所有   节目&gt; Visual Studio 2008/10/12/13&gt; Visual Studio工具&gt;视觉   Studio命令提示符

enter image description here

MSDN文章中描述了从XML文件创建类的语法。我将概述一下让您入门的过程。

  • 将xml文件保存到temp dirtectory:
<metadata>
    <entry key="">
        <dimensionInfo>
            <enabled>false</enabled>
        </dimensionInfo>
    </entry>
    <entry key="">false</entry>
</metadata>
  • 启动Visual Studio命令提示符
  • 要查找所有选项,请输入xsd /?
  • 现在您需要将XML文件转换为XSD文件,这是命令:
  

xsd“C:\ temp \ File.xml”/ c / outputdir:c:\ temp

这将在临时目录中创建一个XSD文件。

  • 然后将XSD文件转换为Serializable C#类这是命令:
  

xsd“C:\ temp \ File.xsd”/ c / outputdir:c:\ temp

这是生成的C#Serialized类文件:

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public partial class metadata {

    private metadataEntry[] itemsField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("entry", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public metadataEntry[] Items {
        get {
            return this.itemsField;
        }
        set {
            this.itemsField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
public partial class metadataEntry {

    private metadataEntryDimensionInfo[] dimensionInfoField;

    private string keyField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("dimensionInfo", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public metadataEntryDimensionInfo[] dimensionInfo {
        get {
            return this.dimensionInfoField;
        }
        set {
            this.dimensionInfoField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string key {
        get {
            return this.keyField;
        }
        set {
            this.keyField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
public partial class metadataEntryDimensionInfo {

    private string enabledField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string enabled {
        get {
            return this.enabledField;
        }
        set {
            this.enabledField = value;
        }
    }
}

答案 2 :(得分:0)

听起来像;

public class Metadata
{ 
    private Dictionary<string, object> entry;
}

字典有两个项目; “假”和另一个对象;

public class dimensionInfo
{
    public bool enabled = false;
}

但是,您有2个空字符串键。你确定键不应该有值吗?

答案 3 :(得分:0)

实际上,您可以为任何类创建自己的自定义序列化,因此在实现类时不必坚持使用模式。

您所要做的就是创建一个实现IXmlSerializable接口的类

您可以在此处详细了解该主题: Custom XML serialization

否则,您可以使用Attributes来控制XML序列化。

使用 [XmlAttribute] 会将序列化作为属性。

使用 [XmlText] 会导致序列化为节点中的内部文本。 (就像示例XML中其他元素中的false字符串一样。)

示例:

public class Program
{
    static void Main(string[] args)
    {
        Metadata meta = new Metadata();
        meta.entry = new List<Entry>();
        var dim = new dimensionInfo();
        meta.entry.Add(
            new Entry()
            {
                key = "",
                O = dim
            }
            );
        meta.entry.Add(
            new Entry()
            {
                key = "",
                text = "false",
                O = null
            }
            );


        XmlWriterSettings set = new XmlWriterSettings();
        set.NamespaceHandling = NamespaceHandling.OmitDuplicates;
        set.OmitXmlDeclaration = true;
        set.DoNotEscapeUriAttributes = false;
        set.Indent = true;
        set.NewLineChars = "\n\r";
        set.IndentChars = "\t";

        XmlWriter writer = XmlWriter.Create(Console.Out, set);
        XmlSerializer ser = new XmlSerializer(typeof(Metadata), "");
        XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
        namespaces.Add(string.Empty, string.Empty);


        ser.Serialize(writer, meta, namespaces);
    }

    [XmlRoot("metadata")]
    public class Metadata
    {
        [XmlElement]
        public List<Entry> entry;
    }

    public class dimensionInfo
    {
        [XmlElement]
        public bool enabled = false;
    }


    public class Entry
    {
        [XmlAttribute] // serialized as attribute
        public string key = "";

        [XmlText] // serialized as text node
        public string text = "";

        [XmlElement("dimensionInfo")] // serialized as an element
        public dimensionInfo O = null;
    }
}

这产生了以下XML:

<metadata>
    <entry key=""><dimensionInfo><enabled>false</enabled></dimensionInfo></entry>
    <entry key="">false</entry>
</metadata>

答案 4 :(得分:0)

您可以使用XSD.exe自动生成可以序列化的C#类。

答案 5 :(得分:0)

直接回答:

让您的班级实施IXmlSerializable界面并使用XmlSerializer来定义您所需的所有案例的行为。

private DimensionInfo _value;

public void WriteXml(XmlWriter writer)
{
    var valueSerializer = new XmlSerializer(typeof (DimensionInfo));

    var ns = new XmlSerializerNamespaces();
    ns.Add("", "");

    writer.WriteStartElement("entry");
    writer.WriteAttributeString("key", string.Empty, string.Empty);

    // Here you define how you want your XML structure to look like
    // E.g. write an empty XML node in case of a null value
    if (_value != null) 
    {
        valueSerializer.Serialize(writer, value, ns);
    }
    writer.WriteEndElement();
}

将以XML格式生成此内容

  <entry key="">
    <dimensionInfo>
      <enabled>true</enabled>
    </dimensionInfo>
  </entry>

或者null

  <entry key="" />

XmlSerializableDictionary

的更详细示例

我使用XmlSerializableDictionary方法生成您提供的XML。同样,您可以精确指定生成的XML在WriteXml方法中的外观。

[XmlRoot("metadata")]
public class XmlSerializableDictionary<TValue> : Dictionary<string, TValue>, IXmlSerializable where TValue : class
{
    private const string XmlKeyName = "key";
    private const string XmlValueName = "entry";

    public void WriteXml(XmlWriter writer)
    {
        var valueSerializer = new XmlSerializer(typeof (TValue));

        var ns = new XmlSerializerNamespaces(); ns.Add("", "");

        foreach (var key in Keys)
        {
            writer.WriteStartElement(XmlValueName);
            writer.WriteAttributeString(XmlKeyName, string.Empty, key);
            var value = this[key];

            // Only serialize the value if value is not null, otherwise write the 
            // empty XML element.
            if (value != null) 
            {
                valueSerializer.Serialize(writer, value, ns);
            }
            writer.WriteEndElement();
        }
    }

    public void ReadXml(XmlReader reader) { /* left out */ }
    public XmlSchema GetSchema() { return null; }
}

DimensionInfo类型供参考

[XmlRoot("dimensionInfo")]
public class DimensionInfo
{
    [XmlElement("enabled")]
    public Boolean Enabled { get; set; }
}

以下代码将字典序列化为XML

var xmlSerializableDictionary = new XmlSerializableDictionary<DimensionInfo>
{
    {"justakey", new DimensionInfo {Enabled = true}},
    {"anotherkey", null}
};

var xmlSerializer = new XmlSerializer(typeof (SerializableDictionary<DimensionInfo>));
xmlSerializer.Serialize(File.Open(@"D:\xmlSerializedDictionary.xml", FileMode.Create), serializableDictionary);

制作XML文件:

<?xml version="1.0"?>
<metadata>
  <entry key="justakey">
    <dimensionInfo>
      <enabled>true</enabled>
    </dimensionInfo>
  </entry>
  <entry key="anotherkey" />
</metadata>