【问题标题】:XmlElement filter by attributeXmlElement 按属性过滤
【发布时间】:2015-06-08 09:15:03
【问题描述】:

背景: 我有一个简单的 XML 表,我无法更改,这是由第 3 方提供的,类和反序列化由我们维护

问题我如何让 xml 正确反序列化,它显然需要以某种方式检查“名称”属性来决定填充哪个属性,但对于我来说,我不记得如何去做这个。 我们当前使用的序列化程序是“System.Xml.Serialization.XmlSerializer”,由于遗留的依赖代码,我们无法更改它。

XML

<result>
    <rowset name="divisions" key="accountKey" columns="accountKey,description">
      <row accountKey="1000" description="Division 1"/>
      <row accountKey="1001" description="Division 2"/>
      <row accountKey="1002" description="Division 3"/>
      <row accountKey="1003" description="Division 4"/>
      <row accountKey="1004" description="Division 5"/>
      <row accountKey="1005" description="Division 6"/>
      <row accountKey="1006" description="Division 7"/>
    </rowset>
    <rowset name="walletDivisions" key="accountKey" columns="accountKey,description">
      <row accountKey="1000" description="Wallet Division 1"/>
      <row accountKey="1001" description="Wallet Division 2"/>
      <row accountKey="1002" description="Wallet Division 3"/>
      <row accountKey="1003" description="Wallet Division 4"/>
      <row accountKey="1004" description="Wallet Division 5"/>
      <row accountKey="1005" description="Wallet Division 6"/>
      <row accountKey="1006" description="Wallet Division 7"/>
    </rowset>
</result>

[Serializable]
[XmlRoot("result", IsNullable = false)]
public class TestClass
{
    [XmlElement("rowset")]
    public EveXmlRowCollection<Division> Divisions { get; set; }
    [XmlElement("rowset")]
    public EveXmlRowCollection<Division> WalletDivisions { get; set; }

    [Serializable]
    [XmlRoot("row")]
    public class Division
    {
        [XmlAttribute("accountKey")]
        public int AccountKey { get; set; }

        [XmlAttribute("description")]
        public string Description { get; set; }
    }
}
public class EveXmlRowCollection<T> : Collection<T>, IXmlSerializable 
{
    //... Other, Irrelevant implementations

    public void ReadXml(XmlReader reader) {
        var serializer = new XmlSerializer(typeof (T));
        if (!reader.IsStartElement()) return;
        RowSetMeta.Name = reader.GetAttribute("name");
        RowSetMeta.Key = reader.GetAttribute("key");
        RowSetMeta.Columns = reader.GetAttribute("columns");
        reader.ReadToDescendant("row");
        while (reader.Name == "row") {
            if (reader.IsStartElement()) {
                var row = (T) serializer.Deserialize(reader);
                Items.Add(row);
            }
            reader.ReadToNextSibling("row");
        }
    }
}

【问题讨论】:

  • 什么是EveXmlRowCollection
  • 一个非常简单的自定义集合:public class EveXmlRowCollection:Collection, IXmlSerializable { ... }
  • 不确定你问了什么?

标签: c# xml deserialization xmlserializer


【解决方案1】:

分两步做呢?首先,您可以在没有任何逻辑的情况下反序列化 xml。只需创建适当的模型:

[XmlRoot("result")]
public class Result
{
    [XmlElement("rowset")]
    public DivisionSet[] DivisionSets { get; set; }
}

public class DivisionSet
{
    [XmlAttribute("name")]
    public string Name { get; set; }

    [XmlElement("row")]
    public Division[] Divisions { get; set; }
}

public class Division
{
    [XmlAttribute("accountKey")]
    public int AccountKey { get; set; }

    [XmlAttribute("description")]
    public string Description { get; set; }
}

使用它们进行反序列化非常简单:

var serializer = new XmlSerializer(typeof(Result));
using (TextReader reader = new StringReader("...XML..."))
{
    var result = (Result)serializer.Deserialize(reader);
}

然后您可以使用 C# 的强大功能创建所需的模型:

public class DeserializedAndNormilizedObject
{
    public IEnumerable<Division> Divisions { get; set; }
    public IEnumerable<Division> WalletDivisions { get; set; }
}

var obj = new DeserializedAndNormilizedObject();
var devisionsSet = result.DivisionSets.FirstOrDefault(x => x.Name == "divisions");
if (devisionsSet != null)
{
    obj.Divisions = devisionsSet.Divisions;
}
// Same for walletDivisions

你将返回 DeserializedAndNormilizedObject 作为反序列化的结果。

【讨论】:

  • 投反对票,需要一个纯粹的“反序列化”方法,值列表中的列表是非常低效和糟糕的代码。你的方法可行,是的,但这不是我要找的答案,谢谢你的尝试
  • 为什么它“效率极低”?它代表您的 XML 的结构。
  • 因为我必须使用 2 个属性来公开数据(WalletDivisions & Divisions),并且由于技术要求,我不允许使用第 3 个隐藏属性(或列表中的列表)
  • 我更新了答案。我的想法是你将返回你想要的对象。当然,您不想返回带有嵌套数组的对象。您只需规范化反序列化的对象。
猜你喜欢
  • 2020-08-03
  • 2013-09-16
  • 1970-01-01
  • 2017-07-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多