将 Web 服务调用的结果反序列化到子元素类型
Posted
技术标签:
【中文标题】将 Web 服务调用的结果反序列化到子元素类型【英文标题】:Deserializing result from Web Service call to a child element type 【发布时间】:2021-04-10 03:21:00 【问题描述】:我已连接到 Web 服务并下载我正在尝试反序列化的 XML。但是,XML 的***元素与我尝试序列化的子元素类型不同。
<ServiceResponse xmlns="namespace1">
<ServiceResult xmlns:i="namespace2">
...lots of elements
</ServiceResult>
</ServiceResponse>
我写了以下代码:
public MyData ConvertXmlToMyData(string filepath)
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "ServiceResponse";
xRoot.Namespace = @"namespace1";
xRoot.IsNullable = true;
XmlSerializer reader = new XmlSerializer(typeof(MyData), xRoot);
StreamReader file = new StreamReader(filepath);
MyData result = (MyData)reader.Deserialize(file);
file.Close();
return result;
代码无异常执行,但所有底层元素均为空。我知道这是因为ServiceResponse
与ServiceResult
不一样,但我不知道如何指定我希望反序列化发生在子元素上,而不是整个对象上(没有其他元素,只是ServiceResult
类型的单个孩子)。
我见过的唯一解决方案是我应该编辑类型的声明,但在我的情况下,我是从 Web 服务获取它们,所以我不能这样做。
有人知道我应该怎么做吗?
编辑:从服务参考中添加了 MyData 注释的详细信息
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="MyData", Namespace="namespace2")]
[System.SerializableAttribute()]
public partial class MyData: object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged
编辑 2:
将代码更改为:
public MyData ConvertXmlToMyData(string filepath)
DataContractSerializer reader = new DataContractSerializer(typeof(MyData));
StreamReader file = new StreamReader(filepath);
file.BaseStream.Position = 0;
MyData result = (MyData)reader.ReadObject(file.BaseStream); <- error thrown here
file.Close();
return result;
现在看到错误:
第 1 行位置 73 出错。需要来自命名空间“namespace1”的元素“MyData”。 遇到名为“ServiceResponse”、命名空间“namespace1”的“元素”。
【问题讨论】:
目前还不清楚(至少对我而言)您到底在寻找什么。是否只想反序列化ServiceResult
节点?
也请与我们分享MyData
类是如何声明和xml注解的。
@PeterCsala 是的,我只需要 ServiceResult 部分。 MyData 类由服务引用提供,不是我声明的。
注解在这里非常重要。 ServiceResponse
上面有 XmlRootAttribute
吗? ServiceResponse
的 ServiceResult
属性是否有 XmlElementAttribute
?如果没有映射,我们将无法为您提供帮助。
@PeterCsala感谢您的意见,但我不太明白您在问什么。我已将服务参考中的 MyData 定义信息添加到上面的原始问题中。 ServiceResult 和 ServiceResponse 是 XML 标签。我对它们的了解都在问题中发布的 XML 中。我可以从成员那里得知 ServiceResult 与 MyData 的数据类型相同,这就是我尝试将其反序列化为该类型的原因。希望对您有所帮助。
【参考方案1】:
假设您的 xml 文件如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<ServiceResponse xmlns="namespace1">
<ServiceResult xmlns:i="namespace2">
<desc>1</desc>
</ServiceResult>
</ServiceResponse>
我刚刚在您的示例中添加了 xml
和 desc
。
然后为了跳过***实体,我们需要对 xml 进行半解析。一种方法:
Load
将FileStream
转换为XDocument
查找***实体
查找二级实体
//Step #1
var xml = File.OpenRead("sample.xml");
var semiParsedData = XDocument.Load(xml);
//Step #2
const string topNamespace = "namespace1", firstNode = "ServiceResponse";
const StringComparison comparison = StringComparison.InvariantCultureIgnoreCase;
var topLevelEntity = semiParsedData.Descendants().FirstOrDefault(element =>
string.Equals(element.Name.Namespace.NamespaceName, topNamespace, comparison)
&& string.Equals(element.Name.LocalName, firstNode, comparison));
//Step #3
const string secondNode = "ServiceResult";
var secondLevelEntity = topLevelEntity?.Descendants().FirstOrDefault(element =>
string.Equals(element.Name.Namespace.NamespaceName, topNamespace, comparison)
&& string.Equals(element.Name.LocalName, secondNode, comparison));
if (secondLevelEntity == null)
return;
希望有一个名为CreateReader
的方法,它是在XNode
类上定义的。
secondLevelEntity
是一个XElement
实例。
XElement
继承自 XContainer
。
XContainer
继承自 XNode
。
所以,我们可以在secondLevelEntity
上拨打CreateReader
:
using var resultReader = secondLevelEntity.CreateReader();
resultReader
是一个XmlReader
实例,希望DataContractSerializer
的ReadObject
有一个接受XmlReader
的重载:
var deserializer = new DataContractSerializer(typeof(MyData));
var myData = (MyData)deserializer.ReadObject(resultReader);
Console.WriteLine(myData.Description);
最后数据模型应该是这样的:
[DataContract(Name = "ServiceResult", Namespace = "namespace1")]
public class MyData
[DataMember(Name = "desc")]
public string Description get; set;
【讨论】:
以上是关于将 Web 服务调用的结果反序列化到子元素类型的主要内容,如果未能解决你的问题,请参考以下文章
Json.net 从 HTTPClient 结果反序列化 DateTime
通过 Web 传输实体框架对象并通过 JSON 返回的最佳方式