这是我尝试反序列化的XML文件的一部分:
<entry>
...
<A:family type="user">
<A:variationCount>7</A:variationCount>
<A:part type="user">
<title>94 LPS</title>
<Voltage type="custom" typeOfParameter="Electrical Potential" units="V">120 V</Voltage>
<Unit_Length displayName="Unit Length" type="custom" typeOfParameter="Length" units="mm">540</Unit_Length>
<Unit_Height displayName="Unit Height" type="custom" typeOfParameter="Length" units="mm">222</Unit_Height>
<Total_Cooling_Capacity displayName="Total Cooling Capacity" type="custom" typeOfParameter="Power" units="W">1758 W</Total_Cooling_Capacity>
<Supply_Air_Width displayName="Supply Air Width" type="custom" typeOfParameter="Duct Size" units="mm">400 mm</Supply_Air_Width>
<Supply_Air_Height displayName="Supply Air Height" type="custom" typeOfParameter="Duct Size" units="mm">150 mm</Supply_Air_Height>
<Sensible_Cooling_Capacity displayName="Sensible Cooling Capacity" type="custom" typeOfParameter="Power" units="W">1348 W</Sensible_Cooling_Capacity>
<Return_Air_Width displayName="Return Air Width" type="custom" typeOfParameter="Duct Size" units="mm">475 mm</Return_Air_Width>
<Number_of_Poles displayName="Number of Poles" type="custom" typeOfParameter="Number of Poles">1</Number_of_Poles>
<Load_Classification displayName="Load Classification" type="custom" typeOfParameter="Load Classification">Cooling</Load_Classification>
<CFU_Material displayName="CFU Material" type="custom" typeOfParameter="Material"><By Category></CFU_Material>
<C2_Offset_1 displayName="C2 Offset 1" type="custom" typeOfParameter="Length" units="mm">108</C2_Offset_1>
<C1_Offset_1 displayName="C1 Offset 1" type="custom" typeOfParameter="Length" units="mm">108</C1_Offset_1>
<Apparent_Load displayName="Apparent Load" type="custom" typeOfParameter="Apparent Power" units="VA">50 VA</Apparent_Load>
</A:part>
<A:part type="user">
...
</A:part>
...
</A:family>
</entry>
这些是我用来反序列化它的类:
[XmlType(AnonymousType = true)]
[XmlRoot("entry", Namespace="http://www.w3.org/2005/Atom")]
public class PartAtom
{
...
[XmlElement("family", Namespace="urn:schemas-autodesk-com:partatom")]
public Family Family { get; set; }
}
public class Family
{
[XmlAttribute("type")]
public string Type { get; set; }
[XmlElement("variationCount")]
public int VariationCount { get; set; }
[XmlElement("part")]
public FamilyType[] Parts { get; set; }
}
[XmlRoot(Namespace = "http://www.w3.org/2005/Atom")]
public class FamilyType
{
[XmlAttribute("type")]
public string Type { get; set; }
[XmlElement("title")]
public string Title { get; set; }
[XmlArray]
public Parameter[] Parameters { get; set; }
}
[XmlRoot(Namespace = "http://www.w3.org/2005/Atom")]
public struct Parameter
{
[XmlAttribute("displayName")]
public string Name { get; set; }
[XmlAttribute("type")]
public string Type { get; set; }
[XmlAttribute("typeOfParameter")]
public string DataType { get; set; }
[XmlText]
public string Value { get; set; }
[XmlAttribute("units")]
public string Units { get; set; }
}
我想要电压、Units_Length、Unit_Height等元素,...Apparent_Load等要反序列化为参数类的实例。我怎样才能完成这样的事情?甚至可能吗?
更新:
参数(标题下方的 XML 元素)实际上是无限的,所以我无法考虑所有这些参数,因此我必须手动指定 XmlElement 名称的所有算法都无法使用。
如果您不想在类上实现IXmlSerializable
,一种选择是添加标有 [XmlAnyElement]
XElement []
元素的代理属性,并序列化此列表之间的参数,并根据需要修复名称。
假设您的 XML 在根元素上具有命名空间声明,如下所示,这些问题中省略了这些声明:
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:A="urn:schemas-autodesk-com:partatom">
那么以下内容应该有效:
[XmlType(Namespace = "http://www.w3.org/2005/Atom")]
public class FamilyType
{
[XmlAttribute("type")]
public string Type { get; set; }
[XmlElement("title")]
public string Title { get; set; }
[XmlIgnore]
public Parameter[] Parameters { get; set; }
[XmlAnyElement]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
public XElement[] XmlParameters
{
get
{
return XmlKeyValueListHelper.SerializeAttributeNameValueList(Parameters, "name");
}
set
{
Parameters = XmlKeyValueListHelper.DeserializeAttributeNameValueList<Parameter>(value, "name");
}
}
}
请注意,序列化程序会自动反序列化 Title
和 Type
属性,而不是传递给 AnyElement
数组。 然后,在 Parameter
中,我将Name
更改为 DisplayName
并添加了一个 ElementName
属性来保存元素名称:
[XmlRoot(Namespace = "http://www.w3.org/2005/Atom")]
public struct Parameter
{
[XmlAttribute("name")]
public string ElementName { get; set; } // Added property.
[XmlAttribute("displayName")]
public string DisplayName { get; set; } // Changed from Name to DisplayName
[XmlAttribute("type")]
public string Type { get; set; }
[XmlAttribute("typeOfParameter")]
public string DataType { get; set; }
[XmlText]
public string Value { get; set; }
[XmlAttribute("units")]
public string Units { get; set; }
}
使用扩展和帮助程序方法:
public static class XmlKeyValueListHelper
{
public static XElement[] SerializeAttributeNameValueList<T>(IEnumerable<T> items, string nameAttributeName)
{
if (items == null)
return null;
var ns = new XmlSerializerNamespaces();
ns.Add("", typeof(T).RootXmlElementNamespace());
var query = items
.Select(p => p.SerializeToXElement(ns))
.Select(e =>
{
var attr = e.Attribute(nameAttributeName);
e.Name = e.Name.Namespace + XmlConvert.EncodeLocalName((string)attr);
attr.Remove();
return e;
});
return query.ToArray();
}
public static T[] DeserializeAttributeNameValueList<T>(IEnumerable<XElement> elements, string nameAttributeName)
{
if (elements == null)
return null;
var query = elements
.Select(e => new XElement(e)) // Do not modify the input values.
.Select(e =>
{
e.Add(new XAttribute(nameAttributeName, XmlConvert.DecodeName(e.Name.LocalName)));
e.Name = e.Name.Namespace + typeof(T).RootXmlElementName();
return e;
})
.Select(e => e.Deserialize<T>());
return query.ToArray();
}
}
public static class XmlTypeExtensions
{
public static string RootXmlElementName(this Type type)
{
var xmlRoot = type.GetCustomAttribute<XmlRootAttribute>();
if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.ElementName))
return xmlRoot.ElementName;
return type.Name;
}
public static string RootXmlElementNamespace(this Type type)
{
var xmlRoot = type.GetCustomAttribute<XmlRootAttribute>();
if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.Namespace))
return xmlRoot.Namespace;
return string.Empty;
}
}
public static class XObjectExtensions
{
static XmlSerializerNamespaces NoStandardXmlNamespaces()
{
var ns = new XmlSerializerNamespaces();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
return ns;
}
public static XElement SerializeToXElement<T>(this T obj)
{
return obj.SerializeToXElement(null, NoStandardXmlNamespaces());
}
public static XElement SerializeToXElement<T>(this T obj, XmlSerializerNamespaces ns)
{
return obj.SerializeToXElement(null, ns);
}
public static XElement SerializeToXElement<T>(this T obj, XmlSerializer serializer, XmlSerializerNamespaces ns)
{
var doc = new XDocument();
using (var writer = doc.CreateWriter())
(serializer ?? new XmlSerializer(obj.GetType())).Serialize(writer, obj, ns);
var element = doc.Root;
if (element != null)
element.Remove();
return element;
}
public static T Deserialize<T>(this XContainer element)
{
return element.Deserialize<T>(new XmlSerializer(typeof(T)));
}
public static T Deserialize<T>(this XContainer element, XmlSerializer serializer)
{
using (var reader = element.CreateReader())
{
object result = serializer.Deserialize(reader);
if (result is T)
return (T)result;
}
return default(T);
}
}
不过,比自定义IXmlSerializable
容易。
一个解决方案可能是多个指定了不同名称的XmlElementAttribute
。像这样:
[XmlElement("Voltage")]
[XmlElement("Unit_Height")]
[XmlElement("Supply_Air_Height")]
[XmlElement("CFU_Material")]
一种(丑陋的)方法可能是在反序列化 XML 之前修改它。只需将所有"电压","Unit_height"等替换为"您的参数类名称"即可。然后它们都应该很好地反序列化,我猜你的"typeOfParameter"仍然会为你提供替换之前最初存在于节点中的相同信息。