XmlSerializer按属性过滤

沙绍尔姆

使用XmlSerializer将XML反序列化为实体类时,是否可以按属性过滤?例如,假设我有一个项目,其类型可以为“ a”或类型为“ b”。我想反序列化所有项目,但仅反序列化“ a”类型的项目。

我之所以需要它,是因为我的实际情况是我们的端点接收到非常大的XML(有些可能超过100MB),其中包含成千上万个类型的标签,<item>但我只需要其中的一些-类型为“ a”的标签我想避免为其余的分配(包括其子标记不少)。

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问题,也不是过早的优化。我们已经确定,我们需要通过性能分析等来提高性能。同样,过滤掉反序列化后的值也无济于事-那时分配已经完成,必须进行垃圾回收。

奥古兹(Oguz Ozgul)

这可以通过自己处理反序列化过程来实现(至少对于根类而言)

请让我提醒您,您提供的XML内容不足以运行单元测试,因此,这是一个非常基本的实现,但是,它应该直接为您工作,或者只需在此处和此处进行一些调整即可。

首先,我们将Item类的XML序列化属性更改为root。“为什么”将很快得到回答。

[XmlRoot("item")]
public class Item
{
    [XmlAttribute("type")]
    public string Type { get; set; }

    [XmlElement("prop1")]
    public int Prop1 { get; set; }
}

我还添加了一个简单的整数属性,以证明反序列化可以按预期进行。

我还更改了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类,它现在显式实现了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();
    }
}

反序列化逻辑保持不变,就像新的XmlSerializer(typeof(Root))。Deserialize()一样。

剩下的..是要测试。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章