使用多个命名空间反序列化肥皂响应

Posted

技术标签:

【中文标题】使用多个命名空间反序列化肥皂响应【英文标题】:Deserialize soap response with multiple namespaces 【发布时间】:2020-01-11 20:10:04 【问题描述】:

我很难反序列化下面的肥皂响应。 我假设它是因为多个命名空间或者可能是因为复杂类型(序列化数组)

Soapformatter 抛出一个对象引用异常,其他更多手动反序列化返回一个空对象。在这一点上,我只能假设我没有正确标记我的对象。构建下面的 BatchResponse 对象以便它可以从此响应反序列化的正确方法是什么?

    <?xml version="1.0" encoding="UTF-8"?>
<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">https://example.com/operations/fetch/BatchResponse</a:Action>
   </s:Header>
   <s:Body>
      <BatchResponse xmlns="https://example.com/operations">
         <BatchResult xmlns:b="https://example.com/responses" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <b:FailureMessages xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:nil="true" />
            <b:FailureType i:nil="true" />
            <b:ProcessedSuccessfully>true</b:ProcessedSuccessfully>
            <b:SessionId>1961810</b:SessionId>
            <b:TotalPages>38</b:TotalPages>
         </BatchResult>
      </BatchResponse>
   </s:Body>
</s:Envelope>

还假设 Soapformatter 继续抛出异常 - “xpath”到 BatchResponse 对象以便我可以提取和反序列化的正确方法是什么?

谢谢

【问题讨论】:

下面的解决方案有效,但当命名空间包含两个句点和一个破折号时 - 例如 example.test-site.com - 不知道为什么! 【参考方案1】:

尝试以下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace ConsoleApplication131

    class Program
    
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        
            XmlReader reader = XmlReader.Create(FILENAME);

            XmlSerializer serializer = new XmlSerializer(typeof(Envelope));
            Envelope envelope = (Envelope)serializer.Deserialize(reader);
        
    
    [XmlRoot(ElementName = "Envelope", Namespace = "http://www.w3.org/2003/05/soap-envelope")]
    public class Envelope
    
        [XmlElement(ElementName = "Header", Namespace = "http://www.w3.org/2003/05/soap-envelope")]
        public Header header  get; set; 

        [XmlElement(ElementName = "Body", Namespace = "http://www.w3.org/2003/05/soap-envelope")]
        public Body body  get; set; 
    
    [XmlRoot(ElementName = "Header", Namespace = "http://www.w3.org/2003/05/soap-envelope")]
    public class Header
    
        [XmlElement(ElementName = "Action", Namespace = "http://www.w3.org/2005/08/addressing")]
        public Action action  get; set; 
    
    [XmlRoot(ElementName = "Action", Namespace = "http://www.w3.org/2005/08/addressing")]
    public class Action
    
        [XmlAttribute(AttributeName = "mustUnderstand", Namespace = "http://www.w3.org/2003/05/soap-envelope")]
        public int mustUnderstand  get; set;
        [XmlText]
        public string value  get;set;
    
    [XmlRoot(ElementName = "Body", Namespace = "")]
    public class Body
    
        [XmlElement(ElementName = "BatchResponse", Namespace = "https://example.com/operations")]
        public BatchResponse batchResponse  get; set; 
    
    [XmlRoot(ElementName = "BatchResponse", Namespace = "https://example.com/operations")]
    public class BatchResponse
    
        [XmlElement(ElementName = "BatchResult", Namespace = "https://example.com/operations")]
        public BatchResult batchResult  get; set; 
    
    [XmlRoot(ElementName = "BatchResult", Namespace = "https://example.com/operations")]
    public class BatchResult
    
        [XmlElement(ElementName = "FailureMessages", Namespace = "https://example.com/responses")]
        public string failureMessages  get; set; 

        [XmlElement(ElementName = "FailureType", Namespace = "https://example.com/responses")]
        public string failureType  get; set; 

        [XmlElement(ElementName = "ProcessedSuccessfully", Namespace = "https://example.com/responses")]
        public Boolean  processedSuccessfully  get; set; 

        [XmlElement(ElementName = "SessionId", Namespace = "https://example.com/responses")]
        public string sessionId  get; set; 

        [XmlElement(ElementName = "TotalPages", Namespace = "https://example.com/responses")]
        public int totalPages  get; set; 

    

【讨论】:

效果太棒了!谢谢你。有没有一种方法可以仅从 Body(即实际对象本身)反序列化而不处理整个信封? XML 序列化不需要所有属性都可以工作。只有公共属性被序列化和反序列化。您需要身体的所有父母,但不是每个父母中的所有属性。 感谢您的澄清。我想问这是否有必要。但是我发现它仍然不适合我。出于隐私原因,我在示例中修改了命名空间域名。用我的域名它不起作用。这似乎与拥有更复杂的域名有关。我重建了整个示例,当使用 example.com/operations 时(如上所述)它可以工作。但是,如果我用example.test-site.com/operations 切换它,它会在 BatchResponse 对象上序列化为 NULL!为什么会这样?我能做什么? 它看起来像是产生问题的“子域”。 test-site.com 有效。 example.test-site.com 不起作用 我无法看到您提供的链接,因为我被阻止了。直到稍后才能查看链接。没有得到对象的五个原因 1)命名空间是错误的。 2) 元素名称错误。它区分大小写 3) 属性不公开。 4)您使用了错误的类型元素/属性 5)您有数组。【参考方案2】:

您可以使用local-name() 忽略xpath 中的命名空间

//*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='BatchResponse']

【讨论】:

以上是关于使用多个命名空间反序列化肥皂响应的主要内容,如果未能解决你的问题,请参考以下文章

如何反序列化肥皂响应?

XmlSerializer c++ 使用多个命名空间反序列化

C# 使用多个可能的命名空间反序列化 xml

c# XmlSerializer 反序列化器缺少默认命名空间

使用 XmlDictionaryReader 反序列化肥皂消息

WCF - 反序列化时控制命名空间