简体   繁体   中英

How do I add a attribute to a XmlArray element (XML Serialization)?

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

XmlArray is used to tell the xmlserializer to treat the property as array and serialize it according its parameters for the element names.

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

will give you

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

In order to add an xml attribute to FullNames element, you need declare a class for it.

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

This will give you

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

This can be done by deriving from IXmlSerializable . I have attached a sample with a base class which does the job:

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);
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM