提问人:philippe 提问时间:9/1/2023 最后编辑:marc_sphilippe 更新时间:9/3/2023 访问量:52
如果在我的类中声明为属性并显示为元素,则无法反序列化元素
Can't deserialize an element if declared as attribute in my class and appears as element
问:
我收到具有不同布局的 XML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<PInstrument>
<Type>myType</Type>
<Data>
<PB>blabla</PB>
<MP>blabla</MP>
<Mode>blabla</Mode>
</Data>
</PInstrument>
</Response>
或
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<PInstrument>
<Type>myType</Type>
<Data PB="blabla" MP="blabla" Mode="blabla" />
</PInstrument>
</Response>
在XML中,两者都是完全正确的,但这里的数据要么包含属性,要么包含元素。
在 .NET 中,若要检索对象中的 XML,我必须声明它,但必须指定这是元素还是属性。事实上,XSD 将数据内部的内容定义为属性,因此 XSD 将它们创建为属性。
但是当我阅读XML时,它们只是没有填充,就好像它们有所作为一样,尽管W3C规范中没有在标准中指出。XmlDeserialize
为什么 .NET 强制元素是元素,属性是属性?
有没有办法反序列化文件,无论表示形式(属性或元素)如何?
答:
1赞
Serge
9/1/2023
#1
例如,我会使用json
using Newtonsoft.Json;
var x = XElement.Parse(xml);
var response = JsonConvert
.DeserializeObject<Root>(JsonConvert.SerializeXNode(x)
.Replace("\"@", "\""));
C# 类
public class Root
{
public Response Response { get; set; }
}
public class Data
{
public string PB { get; set; }
public string MP { get; set; }
public string Mode { get; set; }
}
public class PInstrument
{
public string Type { get; set; }
public Data Data { get; set; }
}
public class Response
{
public PInstrument PInstrument { get; set; }
}
评论
0赞
philippe
9/1/2023
考虑使用 JSON 来处理 XML 很有趣,但这里确实有一点。我要调查一下
1赞
dbc
9/2/2023
#2
XML 元素的属性和子元素可以具有相同的名称,这可能是 .NET 强制元素为元素而强制属性为属性的原因之一。[1] 也就是说,以下是一个格式完美的 XML
<Data PB="foo">
<PB>bar</PB>
</Data>
XmlSerializer
允许您将属性和子元素绑定到不同的 .NET 属性。PB
事实上,这为您的问题提供了一种解决方法:您可以为每个属性创建代理项属性,将每个属性的值重定向到绑定到相应元素的属性,如下所示:
[XmlRoot("Data")]
public class Data
{
[XmlElement("PB")] public string PB { get; set; }
[XmlElement("MP")] public string MP { get; set; }
[XmlElement("Mode")] public string Mode { get; set; }
[XmlAttribute("PB")] public string PBAttribute { get => PB; set => PB = value; }
[XmlAttribute("MP")] public string MPAttribute { get => MP; set => MP = value; }
[XmlAttribute("Mode")] public string ModeAttribute { get => Mode; set => Mode = value; }
// Prevent the elements from being re-serialized.
public bool ShouldSerializePB() => false;
public bool ShouldSerializeMP() => false;
public bool ShouldSerializeMode() => false;
}
[XmlRoot("PInstrument")]
public class PInstrument
{
public string Type { get; set; }
public Data Data { get; set; }
}
[XmlRoot("Response")]
public class Response
{
public PInstrument PInstrument { get; set; }
}
在这里演示小提琴。
此版本始终将值重新序列化为属性。如果需要跟踪值是否被反序列化为属性或元素并相应地重新序列化,则可以使用 {PropertyName}Specified
模式:<Data>
[XmlRoot("Data")]
public class Data
{
[XmlElement("PB")] public string PB { get; set; }
[XmlElement("MP")] public string MP { get; set; }
[XmlElement("Mode")] public string Mode { get; set; }
[XmlAttribute("PB")] public string PBAttribute { get => PB; set => PB = value; }
[XmlAttribute("MP")] public string MPAttribute { get => MP; set => MP = value; }
[XmlAttribute("Mode")] public string ModeAttribute { get => Mode; set => Mode = value; }
[XmlIgnore] public bool PBSpecified { get; set; } = false; // Serialize as attributes unless specified.
[XmlIgnore] public bool MPSpecified { get; set; } = false;
[XmlIgnore] public bool ModeSpecified { get; set; } = false;
[XmlIgnore] public bool PBAttributeSpecified { get => !PBSpecified; set => PBSpecified = !value; }
[XmlIgnore] public bool MPAttributeSpecified { get => !MPSpecified; set => MPSpecified = !value; }
[XmlIgnore] public bool ModeAttributeSpecified { get => !ModeSpecified; set => ModeSpecified = !value; }
}
在这里演示小提琴 #2。
[1] 元素和属性在 XSD 架构中的显示方式也不同,并且对它们可以包含的值类型有不同的限制。
评论
0赞
philippe
9/3/2023
哇,这是一个令人印象深刻的答案,我要试一试。实际上,我的类是用我自己的 XSD.exe 的修改版本创建的,以从...XSD。我将按照您的指示更新类生成器,因为它们看起来很整洁
评论