如何向XmlArray元素添加属性(XML序列化)?

时间:2009-06-27 10:13:56

标签: c# .net xml-serialization

如何在序列化对象时向XmlArray元素(而不是XmlArrayItem)添加属性?

2 个答案:

答案 0 :(得分:70)

XmlArray用于告诉xmlserializer将属性视为数组,并根据元素名称的参数对其进行序列化。

[XmlArray("FullNames")]
[XmlArrayItem("Name")]
public string[] Names{get;set;}

会给你

<FullNames>
    <Name>Michael Jackson</Name>
    <Name>Paris Hilton</Name>
</FullNames>

为了向FullNames元素添加xml属性,您需要为它声明一个类。

[XmlType("FullNames")]
public class Names
{
   [XmlAttribute("total")]
   public int Total {get;set;} 
   [XmlElement("Name")]
   public string[] Names{get;set;}
}

这会给你

<FullNames total="2">
    <Name>Michael Jackson</Name>
    <Name>Paris Hilton</Name>
</FullNames>

答案 1 :(得分:0)

这可以通过从 IXmlSerializable 派生来完成。我附上了一个带有基类的示例,它可以完成这项工作:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace XmlSerializerApp {
  class Program {
    static void Main() {
      using (var ms = new MemoryStream()) {
        var serializer = new XmlSerializer(typeof(RootObject));
        serializer.Serialize(ms, new RootObject());
        ms.Position = 0;
        var formatted =
          new XmlDocument {
            XmlResolver = null,
            PreserveWhitespace = false
          };
        formatted.Load(ms);
        var stringWriter = new StringWriter();
        var xmlTextWriter =
          new XmlTextWriter(stringWriter) {Formatting = Formatting.Indented};

        formatted.WriteTo(xmlTextWriter);
        Console.WriteLine(stringWriter.ToString());

        ms.Position = 0;

        var rootObj = serializer.Deserialize(ms) as RootObject;

        if (rootObj?.Children != null) {
          Console.WriteLine($"Whatever: {rootObj?.Children?.Whatever}");

          foreach (var child in rootObj.Children) {
            if (child == null) {
              continue;
            }
            Console.WriteLine($"  {child.Name}={child.Value}");
          }
        }
      }
    }
  }

  [XmlRoot(ElementName = "root")]
  public class RootObject{
    [XmlAttribute(AttributeName = "version")]
    public string Version {get; set;} = "1.0.0";

    [XmlElement(ElementName = "children")]
    public ListOfChildren Children {get; set;} = new ListOfChildren {
      new Child{ Name = "one", Value = "firstValue"}
    };
  }

  [XmlRoot(ElementName = "add")]
  public class Child {
    [XmlAttribute(AttributeName = "name")]
    public string Name { get; set; }
    [XmlAttribute(AttributeName = "value")]
    public string Value { get; set; }
  }

  public class ListOfChildren : ListBase<Child> {
    [XmlAttribute(AttributeName = "whatever")]
    public bool Whatever { get; set; } = true;
  }
  public class ListBase<T>
    : List<T>
    , IXmlSerializable
  {
    private static readonly Type _s_type = typeof(T);
    // ReSharper disable once StaticMemberInGenericType
    private static readonly XmlAttributeOverrides _s_overrides =
      new Func<XmlAttributeOverrides>(
        () => {
          var overrides = new XmlAttributeOverrides();
          overrides.Add(_s_type, new XmlAttributes{ XmlRoot = new XmlRootAttribute("add")});
          return overrides;
        })();
    // ReSharper disable once StaticMemberInGenericType
    private static readonly XmlSerializer _s_serializer = new XmlSerializer(_s_type, _s_overrides);

    /// <inheritdoc />
    public XmlSchema GetSchema() { throw new NotImplementedException(); }

    /// <inheritdoc />
    public void ReadXml(XmlReader reader) {
      var localName = reader.LocalName;
      var prefix = reader.Prefix;
      var namespaceUri = reader.NamespaceURI;
      var depth = reader.Depth;
      var attributes =
        GetAttributes()?.ToArray()
         ?? Array.Empty<KeyValuePair<PropertyInfo, XmlAttributeAttribute>>();

      while (reader.MoveToNextAttribute()) {
        var attribute =
          attributes
            .Where(
              a =>
                string.Equals(
                  a.Value?.AttributeName,
                  reader.LocalName,
                  StringComparison.Ordinal)
                && string.Equals(
                  a.Value?.Namespace ?? string.Empty,
                  reader.NamespaceURI,
                  StringComparison.Ordinal)
                )
            .Select(x => x.Key)
            .FirstOrDefault();

        if (attribute != null) {
          var attributeValue = reader.Value;

          if (attribute.PropertyType == typeof(string)) {
            attribute.SetValue(attributeValue, null);
          }
          else if (attribute.PropertyType == typeof(bool)) {
            if ("1".Equals(attributeValue, StringComparison.Ordinal)
                || "-1".Equals(attributeValue, StringComparison.Ordinal)
                || "TRUE".Equals(attributeValue, StringComparison.OrdinalIgnoreCase)) {
              attribute.SetValue(this, true);
            }
          }
          else if (attribute.PropertyType == typeof(short)
                   && short.TryParse(attributeValue, out var shortValue)) {
            attribute.SetValue(this, shortValue);
          }
          else if (attribute.PropertyType == typeof(int)
                   && int.TryParse(attributeValue, out var intValue)) {
            attribute.SetValue(this, intValue);
          }
          else if (attribute.PropertyType == typeof(long)
                   && long.TryParse(attributeValue, out var longValue)) {
            attribute.SetValue(this, longValue);
          }
          else if (attribute.PropertyType == typeof(decimal)
                   && decimal.TryParse(attributeValue, out var decimalValue)) {
            attribute.SetValue(this, decimalValue);
          }
          else if (attribute.PropertyType == typeof(float)
                   && float.TryParse(attributeValue, out var floatValue)) {
            attribute.SetValue(this, floatValue);
          }
          else if (attribute.PropertyType == typeof(double)
                   && double.TryParse(attributeValue, out var doubleValue)) {
            attribute.SetValue(this, doubleValue);
          }
          else if (attribute.PropertyType == typeof(Guid)
                   && Guid.TryParse(attributeValue, out var guidValue)) {
            attribute.SetValue(this, guidValue);
          }
          else if (attribute.PropertyType == typeof(Version)
                   && Version.TryParse(attributeValue, out var versionValue)) {
            attribute.SetValue(this, versionValue);
          }
          else if (attribute.PropertyType == typeof(Uri)
                   && Uri.TryCreate(
                     attributeValue,
                     UriKind.RelativeOrAbsolute,
                     out var uriValue)) {
            attribute.SetValue(this, uriValue);
          }
        }
      }

      Clear();

      while (reader.Read()) {
        if (reader.NodeType != XmlNodeType.Element) {
          if (reader.NodeType == XmlNodeType.EndElement
              && prefix.Equals(reader.Prefix, StringComparison.Ordinal)
              && localName.Equals(reader.LocalName, StringComparison.Ordinal)
              && namespaceUri.Equals(reader.NamespaceURI, StringComparison.Ordinal)
              && depth == reader.Depth
            ) {
            break;
          }
          continue;
        }

        var x = reader.ReadSubtree();

        var item = (T)_s_serializer?.Deserialize(x);
        Add(item);
      }
    }

    /// <inheritdoc />
    public void WriteXml(XmlWriter writer) {
      var enumerable = GetAttributes();

      if (enumerable != null) {
        foreach (var attribute in enumerable) {
          if (attribute.Key == null || attribute.Value?.AttributeName == null) {
            continue;
          }

          var value = attribute.Key.GetValue(this, null);

          if (value is bool b) {
            value = b
                      ? "true"
                      : "false";
          }

          if (value != null) {
            writer.WriteAttributeString(attribute.Value.AttributeName,
              attribute.Value.Namespace,
              value.ToString() ?? string.Empty
              );
          }
        }
      }

      foreach (var item in this) {
        if (item == null) {
          continue;
        }
        _s_serializer?.Serialize(writer, item);
      }
    }

    private IEnumerable<KeyValuePair<PropertyInfo, XmlAttributeAttribute>> GetAttributes() {
      return GetType()
          .GetProperties()
          .Select(
            p =>
              new KeyValuePair<PropertyInfo, XmlAttributeAttribute>(
                p,
                p.GetCustomAttributes(
                  typeof(XmlAttributeAttribute),
                  true)
                 .Cast<XmlAttributeAttribute>()
                 .FirstOrDefault())
            )
          .Where(x => x.Value != null);
    }
  }
}