【发布时间】:2019-04-30 19:25:12
【问题描述】:
我试图在执行 XML 反序列化时将 XML 标记的名称放入类属性中。我需要名称作为属性,因为多个 XML 标记共享同一个类。 XML 和相关的类定义如下。
我收到一个 XML 响应,格式如下:
<Data totalExecutionTime="00:00:00.0467241">
<ItemNumber id="1234" order="0" createdDate="2017-03-24T12:07:09.07" modifiedDate="2018-08-29T16:59:19.127">
<Value modifiedDate="2017-03-24T12:07:12.77">ABC1234</Value>
<Category id="5432" parentID="9876" itemOrder="0" modifiedDate="2017-03-24T12:16:23.687">The best category</Category>
... <!-- like 100 other elements -->
</ItemNumber>
</Data>
反序列化如下:
XmlSerializer serializer = new XmlSerializer(typeof(ItemData));
using (TextReader reader = new StringReader(response))
{
ItemData itemData = (ItemData)serializer.Deserialize(reader);
}
还有一个顶级课程,ItemData:
[Serializable]
[XmlRoot("Data")]
public class ItemData
{
[XmlAttribute("totalExecutionTime")]
public string ExecutionTime { get; set; }
[XmlElement("ItemNumber", Type = typeof(ItemBase))]
public List<ItemBase> Items { get; set; }
}
ItemBase 定义为:
[Serializable]
public class ItemBase
{
[XmlElement("Value")]
public virtual ItemProperty ItemNumber { get; set; } = ItemProperty.Empty;
[XmlElement("ItemName")]
public virtual ItemProperty Category { get; set; } = ItemProperty.Empty;
... // like 100 other properties
}
最后是ItemProperty:
public class ItemProperty : IXmlSerializable
{
public static ItemProperty Empty { get; } = new ItemProperty();
public ItemProperty()
{
this.Name = string.Empty;
this.Value = string.Empty;
this.Id = 0;
this.Order = 0;
}
public string Name { get; set; }
[XmlText] // no effect while using IXmlSerializable
public string Value { get; set; }
[XmlAttribute("id")] // no effect while using IXmlSerializable
public int Id { get; set; }
[XmlAttribute("itemOrder")] // no effect while using IXmlSerializable
public int Order { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
string name = reader.Name;
this.Name = name;
string val = reader.ReadElementString();
this.Value = val;
if (reader.HasAttributes)
{
string id = reader.GetAttribute("id");
this.Id = Convert.ToInt32(id);
string itemOrder = reader.GetAttribute("itemOrder");
this.Order = Convert.ToInt32(itemOrder);
string sequence = reader.GetAttribute("seq");
this.Sequence = Convert.ToInt32(sequence);
}
// it seems the reader doesn't advance to the next element after reading
if (reader.NodeType == XmlNodeType.EndElement && !reader.IsEmptyElement)
{
reader.Read();
}
}
public void WriteXml(XmlWriter writer)
{
throw new NotImplementedException();
}
}
实现IXmlSerializable 接口的目的是因为最终我需要存储为ItemProperty 的XML 标记的名称,并且在使用XML 类/属性属性时不会捕获该信息。我相信是这种情况,因为属性决定了使用哪个类进行反序列化,并且通常每个 XML 标记都有一个关联的类。我不想朝那个方向发展,因为响应中可能有大量不同的标签,而且它们都具有相似的属性。因此ItemProperty 类。
我也尝试通过ItemProperty 中的参数化构造函数传递标签的名称并在那里设置名称属性,但是在执行反序列化时,它使用默认构造函数然后设置属性值,这样不是一个选项。
反射也不起作用,因为类总是ItemProperty,因此没有唯一的名称。
也许我构建 XML 属性的方式可能会有所不同,以实现我想要做的事情,但我没有看到。
我愿意以任何方式解决这个问题,但我很确定这需要实现IXmlSerializable.ReadXml()。我知道XmlReader 的工作是阅读整个 XML 并将读者推进到文本的末尾,但我有点不清楚如何做到这一点。
TLDR:如何正确实现IXmlSerializable.ReadXml(),同时将 XML 标记名称、标记值和所有属性捕获到类属性中?
编辑:使用更新的ReadXml 方法,我获得了ItemProperty 级别所需的所有数据,但ItemData 类,Items 列表只有一项。我假设是因为我没有正确地推进读者。
【问题讨论】:
-
可能相关:Xmlserializer to C# object, store original XML element。这是否回答你的问题?它显示了将与
IXmlSerializable节点对应的整个元素加载到XElement中的示例。 -
不完全是,因为该示例在运行前就知道被反序列化的元素名称。我确实在
ItemProperty级别获得了我需要的所有数据,但我相信读者并没有进步,因为ItemData.Items只包含一项。请参阅底部的编辑。谢谢。
标签: c# .net deserialization xml-deserialization ixmlserializable