[英]XmlSerializer filter by attribute
使用 XmlSerializer 將 XML 反序列化為實體 class 時,是否可以按屬性進行過濾? 例如,假設我有一個可以是“a”類型或“b”類型的項目。 我想反序列化所有項目,但只有“a”類型的項目。
我需要這個,因為我的實際情況是我們的端點接收非常大的 XML(有些可能超過 100MB),其中包含數十萬個<item>
類型的標簽,但我只需要其中的一些 - “a”類型的標簽。 我想避免分配給 rest(包括他們的子標簽,這些標簽並不多)。
示例 XML:
<root>
<item type="a"/>
<item type="a"/>
<item type="b"/>
<item type="c"/>
</root>
實體:
[XmlRoot("root")]
public class Root {
[XmlElement("item")]
public Item[] Items { get; set; }
}
public class Item {
[XmlAttribute("type")]
[DeserializeIfValueIs("a")] // <-- Is there something like this?
public string Type { get; set; }
}
代碼:
var serializer = new XmlSerializer(typeof(Root));
var dto = (Root) serializer.Deserialize(XmlReader.Create("input.xml"));
// Show the results - {"Items":[{"Type":"a"},{"Type":"a"},{"Type":"b"},{"Type":"c"}]}
Console.WriteLine(JsonConvert.SerializeObject(dto));
如何讓它只為“a”類型的項目分配對象?
強制性說明:這既不是 XY 問題,也不是過早優化。 我們已經確定我們需要通過分析等來提高這方面的性能。 同樣過濾掉反序列化后的值也無濟於事 - 到那時分配已經完成並且必須進行垃圾收集。
這可以通過我們自己處理反序列化過程來實現(至少對於根類)
請讓我提醒您,您提供的 XML 內容不足以運行單元測試,所以這是一個非常基本的實現,但是應該直接為您工作,或者只是在這里和那里稍微調整一下。
首先,我們將 Item class XML 序列化屬性更改為 root。 “為什么”很快就會得到回答。
[XmlRoot("item")]
public class Item
{
[XmlAttribute("type")]
public string Type { get; set; }
[XmlElement("prop1")]
public int Prop1 { get; set; }
}
我還添加了一個簡單的 integer 屬性來證明反序列化按預期工作。
我還更改了 XML 內容以匹配新類型,以進行測試。
<root>
<item type="b">
<prop1>5</prop1>
</item>
<item type="a">
<prop1>5</prop1>
</item>
<item type="a">
<prop1>5</prop1>
</item>
<item type="b">
<prop1>5</prop1>
</item>
<item type="c">
<prop1>5</prop1>
</item>
</root>
現在出現了 Root class,它現在顯式地實現了 IXmlSerializable:
[XmlRoot("root")]
public class Root : IXmlSerializable
{
[XmlElement("item")]
public Item[] Items { get; set; }
// These two methods are not implemented for you need to deserialize only,
// and because you haven't provided the schema for your XML content
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { throw new NotImplementedException(); }
void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) { throw new NotImplementedException(); }
void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
{
// The element is <root> when here for the first time.
// Maintain a list to keep items with type "a"
List<Item> typeAItems = new List<Item>();
// Create a serializer for the type Item
XmlSerializer deserializer = new XmlSerializer(typeof(Item));
while (reader.Read())
{
// The code is self explanatory.
// Skip() will help omitting unnecessary reads
// if we are not interested in the Item
if (reader.IsStartElement() && reader.Name == "item")
{
if (reader.GetAttribute("type") == "a")
{
// This works, and deserializes the current node
// into an Item object. When the deserialization
// is completed, the reader is at the beginning
// of the next <Item> element
typeAItems.Add((Item)deserializer.Deserialize(reader));
}
else
{
// skip element with all its children
reader.Skip();
}
}
else
{
// skip element with all its children
reader.Skip();
}
}
Items = typeAItems.ToArray();
}
}
反序列化邏輯保持不變,如 new XmlSerializer(typeof(Root)).Deserialize()。
rest.. 用於測試。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.