将XML从Soap调用反序列化为对象数组

时间:2018-03-27 17:41:15

标签: c# xml soap xml-deserialization

我正在尝试拨打肥皂,并将我收到的答案反序列化。肥皂调用是正确的,但到目前为止我还没有管理将答案反序列化为对象。具体来说,答案中包含的XML是一系列重复数据。你猜我想要创建一个对象数组。我检查了其他类似的问题,但到目前为止还没有成功。让我们从定义整个XML开始。

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
    <a:Action s:mustUnderstand="1">ThisIsATry/RetrieveResponse</a:Action>
  </s:Header>
  <s:Body>
    <RetrieveResponse xmlns="ThisIsATry">
      <RetrieveInsurersResult xmlns:b="http://schemas.datacontract.org/2004/07/ThisIsATry" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <b:Errors xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
        <b:Message>Selected 2 records</b:Message>
        <b:Results xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
          <c:ArrayOfKeyValueOfstringstring>
            <c:KeyValueOfstringstring>
              <c:Key>PersonId</c:Key>
              <c:Value>1</c:Value>
            </c:KeyValueOfstringstring>
            <c:KeyValueOfstringstring>
              <c:Key>Name</c:Key>
              <c:Value>Mike</c:Value>
            </c:KeyValueOfstringstring>
          </c:ArrayOfKeyValueOfstringstring>
          <c:ArrayOfKeyValueOfstringstring>
            <c:KeyValueOfstringstring>
              <c:Key>PersonId</c:Key>
              <c:Value>2</c:Value>
            </c:KeyValueOfstringstring>
            <c:KeyValueOfstringstring>
              <c:Key>Name</c:Key>
              <c:Value>Henry</c:Value>
            </c:KeyValueOfstringstring>
          </c:ArrayOfKeyValueOfstringstring>
        </b:Results>
        <b:Warnings xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
      </RetrieveInsurersResult>
    </RetrieveResponse>
  </s:Body>
</s:Envelope>

我需要使用的部分是:

    <b:Results xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
      <c:ArrayOfKeyValueOfstringstring>
        <c:KeyValueOfstringstring>
          <c:Key>PersonId</c:Key>
          <c:Value>1</c:Value>
        </c:KeyValueOfstringstring>
        <c:KeyValueOfstringstring>
          <c:Key>Name</c:Key>
          <c:Value>Mike</c:Value>
        </c:KeyValueOfstringstring>
      </c:ArrayOfKeyValueOfstringstring>
      <c:ArrayOfKeyValueOfstringstring>
        <c:KeyValueOfstringstring>
          <c:Key>PersonId</c:Key>
          <c:Value>2</c:Value>
        </c:KeyValueOfstringstring>
        <c:KeyValueOfstringstring>
          <c:Key>Name</c:Key>
          <c:Value>Henry</c:Value>
        </c:KeyValueOfstringstring>
      </c:ArrayOfKeyValueOfstringstring>
    </b:Results>

正如你所看到的,有2个对象&#34;类型 c:ArrayOfKeyValueOfstringstring&gt; 。每个对象包含2个 c:KeyValueOfstringstring 类型的属性。最后,这些属性中的每一个都包含。我需要的是一个 c:ArrayOfKeyValueOfstringstring 数组,包含一个 c:KeyValueOfstringstring 数组和相关信息。我尝试使用以下类在我的c#代码中表示这些数据:

public class ArrayOfKeyValueOfstringstring
{
    [XmlElement("ArrayOfKeyValueOfstringstring")]
    public KeyValueOfstringstring[] Value { get; set; }

}

public class KeyValueOfstringstring
{
    [XmlElement("KeyValueOfstringstring")]
    public KeyValue Pair { get; set; }

}

public class KeyValue
{
    [XmlElement("Key")]
    public string Key { get; set; }
    [XmlElement("Value")] 
    public string Value { get; set; }
}

到目前为止我处理回复的方式是:

var result = client.UploadString(dataBaseConnectionString, soapTemplate); //calls the serive and brings back the XML
var document = XDocument.Parse(result); //gives back the first XML I posted in this question
var results = document.Descendants().FirstOrDefault(x => x.Name.LocalName == "Results"); //gives back the 2nd XML I posted

xmlNamespaceManager.AddNamespace("c", "http://schemas.microsoft.com/2003/10/Serialization/Arrays");
var oXmlSerializer = new XmlSerializer(typeof(SoapResponse[]));

//this part is wrong..
using (var mem = new MemoryStream(Encoding.UTF8.GetBytes(results.ToString())))
{
      var responseObj = (ArrayOfKeyValueOfstringstring)oXmlSerializer.Deserialize(mem);
}

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

正如所发生的那样,ArrayOfKeyValueOfstringstringDataContractSerializer在序列化Dictionary<string, string>时选择的元素名称,因此您可以更轻松地使用该序列化程序对您进行反序列化XML。

首先,介绍以下扩展方法:

public static partial class DataContractSerializerExtensions
{
    public static T ToContractObject<T>(this XContainer doc, DataContractSerializer serializer = null)
    {
        if (doc == null)
            throw new ArgumentNullException();
        using (var reader = doc.CreateReader())
        {
            return (T)(serializer ?? new DataContractSerializer(typeof(T))).ReadObject(reader);
        }
    }
}

现在您可以将XML解析为List<Dictionary<string, string>>,如下所示:

var dictionaries = document.Descendants()
    .Where(d => d.Name.LocalName == "ArrayOfKeyValueOfstringstring")
    .Select(d => d.ToContractObject<Dictionary<string, string>>())
    .ToList();

之后您可以将字典列表映射到您首选的模型。

但是,如果出于某种原因必须使用XmlSerializer,请引入以下扩展方法和数据模型:

public static partial class XmlSerializerExtensions
{
    public static T ToObject<T>(this XContainer doc, XmlSerializer serializer = null)
    {
        if (doc == null)
            throw new ArgumentNullException();
        using (var reader = doc.CreateReader())
        {
            return (T)(serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader);
        }
    }
}

[XmlRoot(ElementName = "KeyValueOfstringstring", Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
public class KeyValueOfstringstring
{
    [XmlElement(ElementName = "Key", Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
    public string Key { get; set; }
    [XmlElement(ElementName = "Value", Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
    public string Value { get; set; }
}

[XmlRoot(ElementName = "ArrayOfKeyValueOfstringstring", Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
public class ArrayOfKeyValueOfstringstring
{
    [XmlElement(ElementName = "KeyValueOfstringstring", Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
    public List<KeyValueOfstringstring> KeyValueOfstringstring { get; set; }
}

反序列化如下:

var results = document.Descendants()
    .Where(d => d.Name.LocalName == "ArrayOfKeyValueOfstringstring")
    .Select(d => d.ToObject<ArrayOfKeyValueOfstringstring>())
    .ToList();

注意:

  • 我使用XNode.CreateReader()返回XmlReaderXNode可以直接反序列化<b:Results>。这避免了将所选节点转换回字符串表示然后重新解析的要求。

  • "http://schemas.datacontract.org/2004/07/ThisIsATry"节点的命名空间为#include<stdio.h> int main() { int i; if (i <= 10) { for (scanf("%d", &i);i<=10;i++) { printf("%d\n",i); } } else { printf("Please enter a valid number"); } } 。这个命名空间感觉......是临时的...所以我在答案中避免使用它。

所有这些都说,既然XML似乎可能是由wcf service生成的,那么服务是否有可能提供WSDL Metadata?如果是这样,您可以自动生成客户端。见

有关如何完成此操作的文档。

答案 1 :(得分:0)

试试xml linq

    pieChart.getLegend().setPosition(Legend.LegendPosition.ABOVE_CHART_LEFT);
    pieChart.getLegend().setOrientation(Legend.LegendOrientation.VERTICAL);