这是我试图反序列化的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; }
}
我希望将Voltage,Units_Length,Unit_Height,... Apparent_Load等元素反序列化为Parameters类的实例。 我怎么能做到这样的事情?它甚至可能吗?
更新
参数(标题下面的XML元素)实际上是无限的,所以我无法考虑所有这些参数,因此我必须手动指定XmlElement名称的所有算法都不可用。
答案 0 :(得分:1)
如果您不想在您的课程上实施IXmlSerializable
,则可以选择添加XElement []
元素的代理属性标记为[XmlAnyElement]
,并序列化参数并根据需要修改名称。
假设您的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
更容易。
答案 1 :(得分:0)
执行此操作的一种(丑陋)方式可能是在对其进行反序列化之前修改XML。只需将所有“Voltage”,“Unit_height”等字符串替换为“YourParameterClassName”。然后他们应该很好地反序列化,并且我猜你的“typeOfParameter”仍将为你提供在替换之前最初存在于节点中的相同信息。
答案 2 :(得分:0)
一个解决方案可能是指定了不同名称的多个XmlElementAttribute
。如下所示:
[XmlElement("Voltage")]
[XmlElement("Unit_Height")]
[XmlElement("Supply_Air_Height")]
[XmlElement("CFU_Material")]