如何在序列化对象时向XmlArray元素(而不是XmlArrayItem)添加属性?
答案 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);
}
}
}