33

How do I add a attribute to a XmlArray element ( not to XmlArrayItem ) while serializing the object?

1
  • An example of desired output would be ideal... Commented Jun 27, 2009 at 10:48

2 Answers 2

77

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>
Sign up to request clarification or add additional context in comments.

4 Comments

yeah, I know this.. May be I didn't explain properly.. let me explain with your example <ArrayOfString total="2"> <string>Michael Jackson</string> <string >Paris Hilton</string> </ArrayOfString> See the "total" attribute for ArrayOfString element.. How do I get this?
you'd have [XmlAttribute("total")] public int Total {get {return Names.Length;} set {}} or similar; note the "do nothing" setter.
(...using the same approach as codemeit has already shown to declare it)
Awesome example, but, how do I do this in a generic way?
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.