XML文档中存在错误(2,2):尝试反序列化此SOAP xml时?

时间:2016-08-12 16:37:10

标签: c# xml web-services soap

我有一个肥皂消息如下所示。我想只获取request元素及其子节点。

<?xml version="1.0" encoding="UTF-8" ?>
<soap:envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap:header>
    <htngheader xmlns="http://htng.org/1.1/Header/">
      <From>
        <systemId>abc</systemId>
        <address>abc/rm12.12</address>
        <Credential>
          <userName>xyz002</userName>
          <password>xyz002</password>
        </Credential>
      </From>
      <To>
        <systemID>PMM1</systemID>
      </To>
      <timeStamp>2009-04-23T10:59:00-04:00</timeStamp>
      <echoToken>9715f855-bd64-8e3e-905b-aa7ff227af2f</echoToken>
      <transactionId>760873954047</transactionId>
      <action>Request</action>
    </htngheader>
  </soap:header>
  <soap:body>
    <OTA_HotelInvCountNotifRQ echotoken="8c26af40-d777-a21b-ec7e-8d4a8d548a2d" 
                              timestamp="2011-04-23T10:59:00-04:00"
                              target="Production" 
                              version="1.002" sequencenmbr="760871059"
                              xmlns="http://www.example.com/OTA/2003/05"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <Inventories HotelCode="ILP002" 
                   HotelName="Blue Lagoon Suites">
        <Inventory>
          <StatusApplicationControl Start="2011-08-03" End="2011-08-03"
                                    InvTypeCode="QU" Override="true"/>
          <InvCounts>
            <InvCount CountType="1" Count="0"/>
          </InvCounts>
        </Inventory>
      </Inventories>
    </OTA_HotelInvCountNotifRQ>
  </soap:body>
</soap:envelope>

当我尝试反序列化上面的消息时,它会给我以下异常:

  

发生了'System.InvalidOperationException'类型的异常   System.Xml.dll但未在用户代码中处理

     

其他信息:XML文档中存在错误(2,2)。

这是我的Deserealize方法:

private OTA_HotelInvCountNotifRQ DeserializeResXMl(string xmlbody)
{

    OTA_HotelInvCountNotifRQ ret = null;

    if (xmlbody != null && xmlbody != string.Empty)
    {
        try
        {
            long TimeStart = DateTime.Now.Ticks;

            XmlSerializer serializer;
            serializer = new XmlSerializer(typeof(OTA_HotelInvCountNotifRQ));
            ret = (OTA_HotelInvCountNotifRQ)serializer.Deserialize(new StringReader(xmlbody));
        }
        catch (Exception e)
        {
           ret = null;
        }
   }
   return ret;
}

代码更新:

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.example.org/OTA/2003/05")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.opentravel.org/OTA/2003/05", IsNullable = false)]
public partial class OTA_HotelInvCountNotifRQ
{
    private InvCountType inventoriesField;
    private string echoTokenField;
    private System.DateTime timeStampField;
    private OTA_HotelInvCountNotifRQTarget targetField;
    private decimal versionField;

    public OTA_HotelInvCountNotifRQ()
    {
        this.targetField = OTA_HotelInvCountNotifRQTarget.Production;
    }

    /// <remarks/>
    public InvCountType Inventories
    {
        get
        {
            return this.inventoriesField;
        }
        set
        {
            this.inventoriesField = value;
        }
    }     
    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string EchoToken
    {
        get
        {
            return this.echoTokenField;
        }
        set
        {
            this.echoTokenField = value;
        }
    }       
}

我该如何解决这个问题?

3 个答案:

答案 0 :(得分:0)

尝试以下

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

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            try
            {
                OTA_HotelInvCountNotifRQ ota_HotelInvCountNotifRQ = new OTA_HotelInvCountNotifRQ();
                string envelope = File.ReadAllText(FILENAME);

                OTA_HotelInvCountNotifRQ  serializedData =  ota_HotelInvCountNotifRQ.DeserializeResXMl(envelope);
            }
            catch (Exception e)
            {
                string message = e.Message;
                string stacktrace = e.StackTrace;
            }
        }
    } 
    [XmlRoot( ElementName = "envelope")]
    public class Envelope
    {
        [XmlElement(ElementName = "body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
        public Body body { get; set; }
    }
    [XmlRoot(ElementName = "body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
    public class Body
    {
        [XmlElement(ElementName = "OTA_HotelInvCountNotifRQ", Namespace = "http://www.example.com/OTA/2003/05")]
        public OTA_HotelInvCountNotifRQ ota_HotelInvCountNotifRQ { get; set; }
    }

    [XmlRoot(ElementName = "OTA_HotelInvCountNotifRQ", Namespace = "http://www.example.com/OTA/2003/05")]
    public partial class OTA_HotelInvCountNotifRQ
    {
        private InvCountType inventoriesField;
        private string echoTokenField;
        private System.DateTime timeStampField;
        private OTA_HotelInvCountNotifRQTarget targetField;
        private decimal versionField;

        public OTA_HotelInvCountNotifRQ()
        {
            this.targetField = OTA_HotelInvCountNotifRQTarget.Production;
        }

        /// <remarks/>
        public InvCountType Inventories
        {
            get
            {
                return this.inventoriesField;
            }
            set
            {
                this.inventoriesField = value;
            }
        }
        /// <remarks/>
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string EchoToken
        {
            get
            {
                return this.echoTokenField;
            }
            set
            {
                this.echoTokenField = value;
            }
        }
        public OTA_HotelInvCountNotifRQ DeserializeResXMl(string envelopeStr)
        {

            OTA_HotelInvCountNotifRQ ret = null;

            if (envelopeStr != null && envelopeStr != string.Empty)
            {
                try
                {
                    long TimeStart = DateTime.Now.Ticks;

                    XmlSerializer serializer;
                    //serializer = new XmlSerializer(typeof(OTA_HotelInvCountNotifRQ));
                    serializer = new XmlSerializer(typeof(Envelope));
                    Envelope  envelope =  (Envelope)serializer.Deserialize(new StringReader(envelopeStr));
                    ret = envelope.body.ota_HotelInvCountNotifRQ;
                }
                catch (Exception e)
                {
                    ret = null;
                }
            }
            return ret;
        }
    }
    public class InvCountType
    {
    }
    public class OTA_HotelInvCountNotifRQTarget
    {
        public static OTA_HotelInvCountNotifRQTarget Production { get; set; }
    }
}

我对xml进行了一些更改

<?xml version="1.0" encoding="UTF-8" ?>
<envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope" 
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap:header>
    <htngheader xmlns="http://htng.org/1.1/Header/">
      <From>
        <systemId>abc</systemId>
        <address>abc/rm12.12</address>
        <Credential>
          <userName>xyz002</userName>
          <password>xyz002</password>
        </Credential>
      </From>
      <To>
        <systemID>PMM1</systemID>
      </To>
      <timeStamp>2009-04-23T10:59:00-04:00</timeStamp>
      <echoToken>9715f855-bd64-8e3e-905b-aa7ff227af2f</echoToken>
      <transactionId>760873954047</transactionId>
      <action>Request</action>
    </htngheader>
  </soap:header>
  <soap:body>
    <OTA_HotelInvCountNotifRQ echotoken="8c26af40-d777-a21b-ec7e-8d4a8d548a2d" 
                              timestamp="2011-04-23T10:59:00-04:00"
                              target="Production" 
                              version="1.002" sequencenmbr="760871059"
                              xmlns="http://www.example.com/OTA/2003/05"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <Inventories HotelCode="ILP002" 
                   HotelName="Blue Lagoon Suites">
        <Inventory>
          <StatusApplicationControl Start="2011-08-03" End="2011-08-03"
                                    InvTypeCode="QU" Override="true"/>
          <InvCounts>
            <InvCount CountType="1" Count="0"/>
          </InvCounts>
        </Inventory>
      </Inventories>
    </OTA_HotelInvCountNotifRQ>
  </soap:body>
</envelope>

答案 1 :(得分:0)

以下是使用XML Linq的解决方案

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

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);
            var ota_HotelInvCountNotifRQ = doc.Descendants().Where(x => x.Name.LocalName == "OTA_HotelInvCountNotifRQ").Select(y => new OTA_HotelInvCountNotifRQ()
            {
                echotoken = (string)y.Attribute("echotoken"),
                timeStampField = DateTime.Parse((string)y.Attribute("timestamp")),
                versionField = (decimal)y.Attribute("version"),
                sequencenmbr = (int)y.Attribute("sequencenmbr"),
                hotelCode = (string)y.Descendants().Where(z => z.Name.LocalName == "Inventories").FirstOrDefault().Attribute("HotelCode"),
                hotelName = (string)y.Descendants().Where(z => z.Name.LocalName == "Inventories").FirstOrDefault().Attribute("HotelName"),
                start = (DateTime)y.Descendants().Where(z => z.Name.LocalName == "StatusApplicationControl").FirstOrDefault().Attribute("Start"),
                end = (DateTime)y.Descendants().Where(z => z.Name.LocalName == "StatusApplicationControl").FirstOrDefault().Attribute("End"),
                invTypeCode = (string)y.Descendants().Where(z => z.Name.LocalName == "StatusApplicationControl").FirstOrDefault().Attribute("InvTypeCode"),
                _override = (Boolean)y.Descendants().Where(z => z.Name.LocalName == "StatusApplicationControl").FirstOrDefault().Attribute("Override"),
                countType = (int)y.Descendants().Where(z => z.Name.LocalName == "InvCount").FirstOrDefault().Attribute("CountType"),
                count = (int)y.Descendants().Where(z => z.Name.LocalName == "InvCount").FirstOrDefault().Attribute("Count"),
            }).FirstOrDefault();
        }
    }
    public class OTA_HotelInvCountNotifRQ
    {
        public string echotoken { get; set; }
        public DateTime timeStampField { get; set; }
        public decimal versionField { get; set; }
        public int sequencenmbr { get; set; }
        public string hotelCode { get; set; }
        public string hotelName { get; set; }

        public DateTime start { get; set; }
        public DateTime end { get; set; }
        public string invTypeCode { get; set; }
        public Boolean _override { get; set; }

        public int count { get; set; }
        public int countType { get; set; }
    }
}

答案 2 :(得分:0)

我试图使用以下结构反序列化XML:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <GetCategoryFeaturesResponse xmlns="urn:ebay:apis:eBLBaseComponents">
[...]
    </GetCategoryFeaturesResponse>
  </soapenv:Body>
</soapenv:Envelope>

问题似乎是xmlns声明,导致XmlSerializer导致所描述的错误。

我添加了一个XmlRootAttribute作为构造函数的参数,并删除了不需要的元素。可能不是最干净但快速的解决方案。

public GetCategoryFeaturesResponseType GetCategoryFeatures(int categoryId)
        {
            var apiCall = new GetCategoryFeaturesCall(ApiContext)
            {
                CategoryID = categoryId.ToString()
            };

            try
            {
                apiCall.GetCategoryFeatures();
            }
            catch (Exception e)
            {
                return null;
            }

            var response = apiCall.SoapResponse;

            if (response == null)
                return null;

            response = TrimXml(response, "<GetCategoryFeaturesResponse xmlns=\"urn:ebay:apis:eBLBaseComponents\">",
                "</GetCategoryFeaturesResponse>");

            var responseStream = Helpers.Serialization.CreateStream(response);

            var rootAttribute = new XmlRootAttribute()
            {
                ElementName = "GetCategoryFeaturesResponse",
                Namespace = "urn:ebay:apis:eBLBaseComponents",
                IsNullable = true
            };


            GetCategoryFeaturesResponseType categoryFeatures;
            try
            {
                categoryFeatures =
                    Helpers.Serialization.SerializeToModel<GetCategoryFeaturesResponseType>(responseStream,
                        rootAttribute);
            }
            catch (Exception e)
            {
                return null;
            }

            return categoryFeatures;
        }


private static string TrimXml(string origin, string begin, string end)
        {
            var startIndex = origin.IndexOf(begin, StringComparison.Ordinal);
            var endLength = origin.IndexOf(end, StringComparison.Ordinal);
            endLength = endLength - startIndex + end.Length;

            return origin.Substring(startIndex, endLength);
        }