【问题标题】:How do you deserialize XML with dynamic element names?如何使用动态元素名称反序列化 XML?
【发布时间】:2016-09-12 07:34:28
【问题描述】:

我的 XML 如下所示:

<rates>
    <rate1>1250.00</rate1>
    <rate2>1900.00</rate2>
</rates>

这是在我的 Serializable 类中:

[XmlRoot("main")]
public class Main
{
    [XmlArray("rates"), XmlAnyElement]
    public Rates Rates { get; set; }
}

public class Rates : List<Rate> { }

public class Rate
{
    [XmlAnyElement]
    public string Rate;
}

如何反序列化 XML 以便我可以使用:

var rate1 = Main.Rates[0].Rate;
var rate2 = Main.Rates[1].Rate;

【问题讨论】:

标签: c# xml deserialization


【解决方案1】:

您可以通过将Rates 收藏implement IXmlSerializable 做到这一点:

public class Rates : List<Rate>, IXmlSerializable
{
    public Rates() : base() { }
    public Rates(IEnumerable<Rate> collection) : base(collection) { }

    #region IXmlSerializable Members

    XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    void IXmlSerializable.ReadXml(XmlReader reader)
    {
        // for the `decodeName` delegate, you could check that the node name matches the pattern "rateN" for some integer N, if you want.
        XmlKeyValueListHelper.ReadXml(reader, this, null, s => new Rate { RateValue = s });
    }

    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
        XmlKeyValueListHelper.WriteXml(writer, this, (i, rate) => "rate" + XmlConvert.ToString(i), r => r.RateValue);
    }

    #endregion
}

public class Rate
{
    public string RateValue;
}

public static class XmlKeyValueListHelper
{
    const string XsiNamespace = @"http://www.w3.org/2001/XMLSchema-instance";
    const string XsiNil = "nil";

    public static void WriteXml<T>(XmlWriter writer, IEnumerable<T> collection, Func<int, T, string> encodeName, Func<T, string> encodeValue)
    {
        int i = 0;
        foreach (var item in collection)
        {
            writer.WriteStartElement(XmlConvert.EncodeLocalName(encodeName(i, item)));
            if (item == null)
            {
                writer.WriteAttributeString(XsiNil, XsiNamespace, XmlConvert.ToString(true));
            }
            else
            {
                writer.WriteValue(encodeValue(item) ?? "");
            }
            writer.WriteEndElement();
            i++;
        }
    }

    public static void ReadXml<T>(XmlReader reader, ICollection<T> collection, Func<int, string, bool> decodeName, Func<string, T> decodeValue)
    {
        if (reader.IsEmptyElement)
        {
            reader.Read();
            return;
        }

        int i = 0;
        reader.ReadStartElement(); // Advance to the first sub element of the list element.
        while (reader.NodeType == XmlNodeType.Element)
        {
            var key = XmlConvert.DecodeName(reader.Name);
            if (decodeName == null || decodeName(i, key))
            {
                var nilValue = reader[XsiNil, XsiNamespace];
                if (!string.IsNullOrEmpty(nilValue) && XmlConvert.ToBoolean(nilValue))
                {
                    collection.Add(default(T));
                    reader.Skip();
                }
                else
                {
                    string value;
                    if (reader.IsEmptyElement)
                    {
                        value = string.Empty;
                        // Move past the end of item element
                        reader.Read();
                    }
                    else
                    {
                        // Read content and move past the end of item element
                        value = reader.ReadElementContentAsString();
                    }
                    collection.Add(decodeValue(value));
                }
            }
            else
            {
                reader.Skip();
            }
            i++;
        }
        // Move past the end of the list element
        reader.ReadEndElement();
    }
}

例如fiddle

【讨论】:

    【解决方案2】:

    使用XmlSerializer.UnknownElement 事件处理程序可以轻松处理动态元素名称。

    例如,我们有以下xml:

    <main>
      <rates>
        <rate1>1250.00</rate1>
        <rate2>1900.00</rate2>
      </rates>
    </main>
    

    和类:

    [XmlRoot("main")]
    public class Main
    {
        public List<Rate> Rates { get; set; }
    }
    
    public class Rate
    {
        public string Value { get; set; }
    }
    

    反序列化:

    var xs = new XmlSerializer(typeof(Main));
    // add event handler
    xs.UnknownElement += Xs_UnknownElement;
    
    Main main;
    using (var fs = new FileStream("test.xml", FileMode.Open))
        main = (Main)xs.Deserialize(fs);
    

    事件处理代码:

    private void Xs_UnknownElement(object sender, XmlElementEventArgs e)
    {
        Main main = (Main)e.ObjectBeingDeserialized;
    
        foreach (XmlNode node in e.Element.ChildNodes)
            main.Rates.Add(new Rate { Value = node.InnerText });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多