我有一个实现自定义类列表的类。该类还有两个属性。但是当我序列化该类时,XML只包含我的自定义类的数组,但不包含另外两个属性。 这是班级:
public class Porudzbina : List<PorudzbenicaStavka>, IEnumerable<SqlDataRecord>
{
public long KomSifra { get; set; }
public Guid KomId { get; set; }
IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
{
var sqlRow = new SqlDataRecord(
new SqlMetaData("rb", SqlDbType.Int),
new SqlMetaData("RobaSifra", SqlDbType.NVarChar, 50),
new SqlMetaData("RobaNaziv", SqlDbType.NVarChar, 100)
);
foreach (PorudzbenicaStavka por in this)
{
sqlRow.SetInt32(0, por.rb);
sqlRow.SetString(1, por.RobaSifra);
sqlRow.SetString(2, por.RobaNaziv);
yield return sqlRow;
}
}
}
和我用来序列化它的代码:
XmlSerializer serializer = new XmlSerializer(typeof(Porudzbina));
using (TextWriter writer = new StreamWriter(@"C:\Xmle.xml"))
{
serializer.Serialize(writer, por);
}
这是我得到的XML:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfPorudzbenicaStavka xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PorudzbenicaStavka>
<rb>1</rb>
<RobaSifra>3702</RobaSifra>
<RobaNaziv>Foullon mlecna cokolada 33% Ecuador 100g</RobaNaziv>
</PorudzbenicaStavka>
<PorudzbenicaStavka>
<rb>2</rb>
<RobaSifra>1182</RobaSifra>
<RobaNaziv>IL Capitano zelena maslina sa paprikom 720g</RobaNaziv>
</PorudzbenicaStavka>
<PorudzbenicaStavka>
<rb>3</rb>
<RobaSifra>1120</RobaSifra>
<RobaNaziv>Kaiser tuna steak sa papricicom u ulju 170g.</RobaNaziv>
</PorudzbenicaStavka>
</ArrayOfPorudzbenicaStavka>
我希望我的xml包含两个属性以及一个自定义类数组,我可以将其反序列化为原始状态...
答案 0 :(得分:1)
文档部分Serializing a Class that Implements the ICollection Interface解释了您的属性未反序列化的原因:
您可以通过实现ICollection接口来创建自己的集合类,并使用XmlSerializer序列化这些类的实例。请注意,当类实现ICollection接口时,只会序列化类包含的集合。 添加到班级的所有公共属性或字段都不会被序列化。
那就是那个。
您可以考虑更改设计,以便您的课程没有属性。出于某些原因进行此更改,请参阅Why not inherit from List?。
如果您仍然选择具有可序列化属性的集合,则需要manually implement IXmlSerializable
。这很麻烦,因为您需要处理许多“边缘”情况,包括空元素,意外元素,注释以及是否存在空格,所有这些都会导致ReadXml()
方法失效。有些背景,请参阅How to Implement IXmlSerializable Correctly。
首先,为具有可序列化属性的通用列表创建基类:
public class XmlSerializableList<T> : List<T>, IXmlSerializable where T : new()
{
public XmlSerializableList() : base() { }
public XmlSerializableList(IEnumerable<T> collection) : base(collection) { }
public XmlSerializableList(int capacity) : base(capacity) { }
#region IXmlSerializable Members
const string CollectionItemsName = "Items";
const string CollectionPropertiesName = "Properties";
void IXmlSerializable.WriteXml(XmlWriter writer)
{
// Do not write the wrapper element.
// Serialize the collection.
WriteCollectionElements(writer);
// Serialize custom properties.
writer.WriteStartElement(CollectionPropertiesName);
WriteCustomElements(writer);
writer.WriteEndElement();
// Do not end the wrapper element.
}
private void WriteCollectionElements(XmlWriter writer)
{
if (Count < 1)
return;
// Serialize the collection.
writer.WriteStartElement(CollectionItemsName);
var serializer = new XmlSerializer(typeof(T));
var ns = new XmlSerializerNamespaces();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
foreach (var item in this)
{
serializer.Serialize(writer, item, ns);
}
writer.WriteEndElement();
}
/// <summary>
/// Write ALL custom elements to the XmlReader
/// </summary>
/// <param name="writer"></param>
protected virtual void WriteCustomElements(XmlWriter writer)
{
}
void IXmlSerializable.ReadXml(XmlReader reader)
{
if (reader.IsEmptyElement)
{
reader.Read();
return;
}
reader.ReadStartElement(); // Advance to the first sub element of the wrapper element.
while (reader.NodeType != XmlNodeType.EndElement)
{
if (reader.NodeType != XmlNodeType.Element)
// Comment, whitespace
reader.Read();
else if (reader.IsEmptyElement)
reader.Read();
else if (reader.Name == CollectionItemsName)
ReadCollectionElements(reader);
else if (reader.Name == CollectionPropertiesName)
ReadCustomElements(reader);
else
// Unknown element, skip it.
reader.Skip();
}
// Move past the end of the wrapper element
reader.ReadEndElement();
}
void ReadCustomElements(XmlReader reader)
{
reader.ReadStartElement(); // Advance to the first sub element of the collection element.
while (reader.NodeType != XmlNodeType.EndElement)
{
if (reader.NodeType == XmlNodeType.Element)
{
using (var subReader = reader.ReadSubtree())
{
while (subReader.NodeType != XmlNodeType.Element) // Read past XmlNodeType.None
if (!subReader.Read())
break;
ReadCustomElement(subReader);
}
}
reader.Read();
}
// Move past the end of the properties element
reader.Read();
}
void ReadCollectionElements(XmlReader reader)
{
var serializer = new XmlSerializer(typeof(T));
reader.ReadStartElement(); // Advance to the first sub element of the collection element.
while (reader.NodeType != XmlNodeType.EndElement)
{
if (reader.NodeType == XmlNodeType.Element)
{
using (var subReader = reader.ReadSubtree())
{
while (subReader.NodeType != XmlNodeType.Element) // Read past XmlNodeType.None
if (!subReader.Read())
break;
var item = (T)serializer.Deserialize(subReader);
Add(item);
}
}
reader.Read();
}
// Move past the end of the collection element
reader.Read();
}
/// <summary>
/// Read ONE custom element from the XmlReader
/// </summary>
/// <param name="reader"></param>
protected virtual void ReadCustomElement(XmlReader reader)
{
}
XmlSchema IXmlSerializable.GetSchema()
{
return null;
}
#endregion
}
要使用此课程,您需要覆盖ReadCustomElement(XmlReader reader)
,其中包含单个自定义属性,而WriteCustomElements(XmlWriter writer)
则会覆盖所有自定义属性。 (注意不对称性,它使实现类层次结构更容易一些。)然后按如下方式创建Porudzbina
类:
public class Porudzbina : XmlSerializableList<PorudzbenicaStavka>
{
public long KomSifra { get; set; }
public Guid KomId { get; set; }
const string KomSifraName = "KomSifra";
const string KomIdName = "KomId";
protected override void WriteCustomElements(XmlWriter writer)
{
writer.WriteElementString(KomSifraName, XmlConvert.ToString(KomSifra));
writer.WriteElementString(KomIdName, XmlConvert.ToString(KomId));
base.WriteCustomElements(writer);
}
protected override void ReadCustomElement(XmlReader reader)
{
if (reader.Name == KomSifraName)
{
KomSifra = reader.ReadElementContentAsLong();
}
else if (reader.Name == KomIdName)
{
var s = reader.ReadElementContentAsString();
KomId = XmlConvert.ToGuid(s);
}
else
{
base.ReadCustomElement(reader);
}
}
}
这将创建如下所示的XML:
<Porudzbina> <Items> <PorudzbenicaStavka> <!-- contents of first PorudzbenicaStavka --> </PorudzbenicaStavka> <!-- Additional PorudzbenicaStavka --> </Items> <Properties> <KomSifra>101</KomSifra> <KomId>bb23a3b8-23d3-4edd-848b-d7621e6ed2c0</KomId> </Properties> </Porudzbina>
答案 1 :(得分:0)
我已将序列化库上传到Github,处理此类问题。
我假设你有以下数据类。我刚刚在属性上添加了[XmlElement]属性,强制它们序列化为xml元素。
public class Porudzbina : List<PorudzbenicaStavka>, IEnumerable<SqlDataRecord>
{
[XmlElement]
public long KomSifra { get; set; }
[XmlElement]
public Guid KomId { get; set; }
IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
{
var sqlRow = new SqlDataRecord(
new SqlMetaData("rb", SqlDbType.Int),
new SqlMetaData("RobaSifra", SqlDbType.NVarChar, 50),
new SqlMetaData("RobaNaziv", SqlDbType.NVarChar, 100)
);
foreach (PorudzbenicaStavka por in this)
{
sqlRow.SetInt32(0, por.rb);
sqlRow.SetString(1, por.RobaSifra);
sqlRow.SetString(2, por.RobaNaziv);
yield return sqlRow;
}
}
}
public class PorudzbenicaStavka
{
[XmlElement]
public int rb { get; set; }
[XmlElement]
public string RobaSifra { get; set; }
[XmlElement]
public string RobaNaziv { get; set; }
}
这是实例:
var o = new Porudzbina
{
new PorudzbenicaStavka { rb=1, RobaSifra="3702", RobaNaziv="Foullon mlecna cokolada 33% Ecuador 100g" },
new PorudzbenicaStavka { rb=2, RobaSifra="1182", RobaNaziv="IL Capitano zelena maslina sa paprikom 720g" },
new PorudzbenicaStavka { rb=3, RobaSifra="1120", RobaNaziv="Kaiser tuna steak sa papricicom u ulju 170g." },
};
o.KomId = new Guid("{EC63AEC3-1512-451F-B967-836DD0E9820A}");
o.KomSifra = 999999;
以下是atlas xml序列化库的工作原理:
var serialized = Atlas.Xml.Serializer.Serialize(o, true);
var deserialized = Atlas.Xml.Serializer.Deserialize<Porudzbina>(serialized);
Xml看起来像这样:
<Porudzbina>
<KomSifra>999999</KomSifra>
<KomId>ec63aec3-1512-451f-b967-836dd0e9820a</KomId>
<item>
<rb>1</rb>
<RobaSifra>3702</RobaSifra>
<RobaNaziv>Foullon mlecna cokolada 33% Ecuador 100g</RobaNaziv>
</item>
<item>
<rb>2</rb>
<RobaSifra>1182</RobaSifra>
<RobaNaziv>IL Capitano zelena maslina sa paprikom 720g</RobaNaziv>
</item>
<item>
<rb>3</rb>
<RobaSifra>1120</RobaSifra>
<RobaNaziv>Kaiser tuna steak sa papricicom u ulju 170g.</RobaNaziv>
</item>
</Porudzbina>
如果你改变这样的数据类:
[Atlas.Xml.XmlSerializationType(ChildElementName = "PorudzbenicaStavka")]
public class Porudzbina : List<PorudzbenicaStavka>, IEnumerable<SqlDataRecord>
{
public long KomSifra { get; set; }
public Guid KomId { get; set; }
// ...
}
public class PorudzbenicaStavka
{
public int rb { get; set; }
public string RobaSifra { get; set; }
[XmlText]
public string RobaNaziv { get; set; }
}
然后,序列化的类将是这样的:
<Porudzbina KomSifra="999999" KomId="ec63aec3-1512-451f-b967-836dd0e9820a">
<PorudzbenicaStavka rb="1" RobaSifra="3702">Foullon mlecna cokolada 33% Ecuador 100g</PorudzbenicaStavka>
<PorudzbenicaStavka rb="2" RobaSifra="1182">IL Capitano zelena maslina sa paprikom 720g</PorudzbenicaStavka>
<PorudzbenicaStavka rb="3" RobaSifra="1120">Kaiser tuna steak sa papricicom u ulju 170g.</PorudzbenicaStavka>
</Porudzbina>