C# 无法反序列化包含 xsi:type 的 XML

C# can't deserialize XML containing xsi:type

我正在尝试反序列化以下 XML

<?xml version="1.0" encoding="UTF-8"?>
<GovTalkMessage xmlns="http://www.govtalk.gov.uk/CM/envelope">
  <EnvelopeVersion>2.0</EnvelopeVersion>
  <Header>
    <MessageDetails>
      <Class>DRUG_DATA</Class>
      <Qualifier>response</Qualifier>
      <Function>submit</Function>
      <CorrelationID>BD694DAAA26AA6068EAAAE5C7746CE54</CorrelationID>
      <Transformation>XML</Transformation>
    </MessageDetails>
    <SenderDetails>
      <IDAuthentication>
        <SenderID />
        <Authentication>
          <Method />
          <Role />
          <Value />
        </Authentication>
      </IDAuthentication>
    </SenderDetails>
  </Header>
  <GovTalkDetails>
    <Keys>
      <Key Type="SpokeName" />
    </Keys>
  </GovTalkDetails>
  <Body>
    <S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope">
      <S:Body>
        <ns2:getGenericDrugsResponse xmlns:ns2="http://webservice.sirkb/">
          <return>
            <DRUG xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:genericDrug">
              <GENERIC_DRUG_ID>147</GENERIC_DRUG_ID>
              <GENERIC_DRUG_NAME>Amoxicilline 125mg/5ml - 60ml</GENERIC_DRUG_NAME>
            </DRUG>
            <DRUG xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:genericDrug">
              <GENERIC_DRUG_ID>149</GENERIC_DRUG_ID>
              <GENERIC_DRUG_NAME>Amoxicilline 250mg/5ml - 60ml</GENERIC_DRUG_NAME>
            </DRUG>            
            <DRUG xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:genericDrug">
              <DOSAGE>10mg/5ml</DOSAGE>
              <GENERIC_DRUG_ID>2312</GENERIC_DRUG_ID>
              <GENERIC_DRUG_NAME>Vinorelbine (as vinorelbine tartrate)</GENERIC_DRUG_NAME>
              <PHARMACEUTICAL_FORM>concentrate for solution for infusion</PHARMACEUTICAL_FORM>
            </DRUG>
            <DRUG xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:genericDrug">
              <DOSAGE>100 u/ml (approximately 0.58mg)</DOSAGE>
              <GENERIC_DRUG_ID>2313</GENERIC_DRUG_ID>
              <GENERIC_DRUG_NAME>Laronidase</GENERIC_DRUG_NAME>
              <PHARMACEUTICAL_FORM>concentrate for solution for infusion</PHARMACEUTICAL_FORM>
            </DRUG>
            <RETURN_STATUS>SUCCESS</RETURN_STATUS>
          </return>
        </ns2:getGenericDrugsResponse>
      </S:Body>
    </S:Envelope>
  </Body>
</GovTalkMessage>

我通过 将 XML 粘贴为 Visual Studio 2017 的 类 功能生成了 类。(使用 xsd.exe是一样的)生成的类我没有改。

它们具有以下形式:

// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.govtalk.gov.uk/CM/envelope", IsNullable = false)]
public partial class GovTalkMessage
{

    private decimal envelopeVersionField;

    private GovTalkMessageHeader headerField;

    private GovTalkMessageGovTalkDetails govTalkDetailsField;

    private GovTalkMessageBody bodyField;

    /// <remarks/>
    public decimal EnvelopeVersion
    {
        get
        {
            return this.envelopeVersionField;
        }
        set
        {
            this.envelopeVersionField = value;
        }
    }

    /// <remarks/>
    public GovTalkMessageHeader Header
    {
        get
        {
            return this.headerField;
        }
        set
        {
            this.headerField = value;
        }
    }

    /// <remarks/>
    public GovTalkMessageGovTalkDetails GovTalkDetails
    {
        get
        {
            return this.govTalkDetailsField;
        }
        set
        {
            this.govTalkDetailsField = value;
        }
    }

    /// <remarks/>
    public GovTalkMessageBody Body
    {
        get
        {
            return this.bodyField;
        }
        set
        {
            this.bodyField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
public partial class GovTalkMessageHeader
{

    private GovTalkMessageHeaderMessageDetails messageDetailsField;

    private GovTalkMessageHeaderSenderDetails senderDetailsField;

    /// <remarks/>
    public GovTalkMessageHeaderMessageDetails MessageDetails
    {
        get
        {
            return this.messageDetailsField;
        }
        set
        {
            this.messageDetailsField = value;
        }
    }

    /// <remarks/>
    public GovTalkMessageHeaderSenderDetails SenderDetails
    {
        get
        {
            return this.senderDetailsField;
        }
        set
        {
            this.senderDetailsField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
public partial class GovTalkMessageHeaderMessageDetails
{

    private string classField;

    private string qualifierField;

    private string functionField;

    private string correlationIDField;

    private string transformationField;

    /// <remarks/>
    public string Class
    {
        get
        {
            return this.classField;
        }
        set
        {
            this.classField = value;
        }
    }

    /// <remarks/>
    public string Qualifier
    {
        get
        {
            return this.qualifierField;
        }
        set
        {
            this.qualifierField = value;
        }
    }

    /// <remarks/>
    public string Function
    {
        get
        {
            return this.functionField;
        }
        set
        {
            this.functionField = value;
        }
    }

    /// <remarks/>
    public string CorrelationID
    {
        get
        {
            return this.correlationIDField;
        }
        set
        {
            this.correlationIDField = value;
        }
    }

    /// <remarks/>
    public string Transformation
    {
        get
        {
            return this.transformationField;
        }
        set
        {
            this.transformationField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
public partial class GovTalkMessageHeaderSenderDetails
{

    private GovTalkMessageHeaderSenderDetailsIDAuthentication iDAuthenticationField;

    /// <remarks/>
    public GovTalkMessageHeaderSenderDetailsIDAuthentication IDAuthentication
    {
        get
        {
            return this.iDAuthenticationField;
        }
        set
        {
            this.iDAuthenticationField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
public partial class GovTalkMessageHeaderSenderDetailsIDAuthentication
{

    private object senderIDField;

    private GovTalkMessageHeaderSenderDetailsIDAuthenticationAuthentication authenticationField;

    /// <remarks/>
    public object SenderID
    {
        get
        {
            return this.senderIDField;
        }
        set
        {
            this.senderIDField = value;
        }
    }

    /// <remarks/>
    public GovTalkMessageHeaderSenderDetailsIDAuthenticationAuthentication Authentication
    {
        get
        {
            return this.authenticationField;
        }
        set
        {
            this.authenticationField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
public partial class GovTalkMessageHeaderSenderDetailsIDAuthenticationAuthentication
{

    private object methodField;

    private object roleField;

    private object valueField;

    /// <remarks/>
    public object Method
    {
        get
        {
            return this.methodField;
        }
        set
        {
            this.methodField = value;
        }
    }

    /// <remarks/>
    public object Role
    {
        get
        {
            return this.roleField;
        }
        set
        {
            this.roleField = value;
        }
    }

    /// <remarks/>
    public object Value
    {
        get
        {
            return this.valueField;
        }
        set
        {
            this.valueField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
public partial class GovTalkMessageGovTalkDetails
{

    private GovTalkMessageGovTalkDetailsKeys keysField;

    /// <remarks/>
    public GovTalkMessageGovTalkDetailsKeys Keys
    {
        get
        {
            return this.keysField;
        }
        set
        {
            this.keysField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
public partial class GovTalkMessageGovTalkDetailsKeys
{

    private GovTalkMessageGovTalkDetailsKeysKey keyField;

    /// <remarks/>
    public GovTalkMessageGovTalkDetailsKeysKey Key
    {
        get
        {
            return this.keyField;
        }
        set
        {
            this.keyField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
public partial class GovTalkMessageGovTalkDetailsKeysKey
{

    private string typeField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string Type
    {
        get
        {
            return this.typeField;
        }
        set
        {
            this.typeField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
public partial class GovTalkMessageBody
{

    private Envelope envelopeField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.w3.org/2003/05/soap-envelope")]
    public Envelope Envelope
    {
        get
        {
            return this.envelopeField;
        }
        set
        {
            this.envelopeField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2003/05/soap-envelope")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.w3.org/2003/05/soap-envelope", IsNullable = false)]
public partial class Envelope
{

    private EnvelopeBody bodyField;

    /// <remarks/>
    public EnvelopeBody Body
    {
        get
        {
            return this.bodyField;
        }
        set
        {
            this.bodyField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2003/05/soap-envelope")]
public partial class EnvelopeBody
{

    private getGenericDrugsResponse getGenericDrugsResponseField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://webservice.sirkb/")]
    public getGenericDrugsResponse getGenericDrugsResponse
    {
        get
        {
            return this.getGenericDrugsResponseField;
        }
        set
        {
            this.getGenericDrugsResponseField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://webservice.sirkb/")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://webservice.sirkb/", IsNullable = false)]
public partial class getGenericDrugsResponse
{

    private @return returnField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
    public @return @return
    {
        get
        {
            return this.returnField;
        }
        set
        {
            this.returnField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.govtalk.gov.uk/CM/envelope", IsNullable = false)]
public partial class @return
{

    private returnDRUG[] dRUGField;

    private string rETURN_STATUSField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("DRUG")]
    public returnDRUG[] DRUG
    {
        get
        {
            return this.dRUGField;
        }
        set
        {
            this.dRUGField = value;
        }
    }

    /// <remarks/>
    public string RETURN_STATUS
    {
        get
        {
            return this.rETURN_STATUSField;
        }
        set
        {
            this.rETURN_STATUSField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
public partial class returnDRUG
{

    private string dOSAGEField;

    private ushort gENERIC_DRUG_IDField;

    private string gENERIC_DRUG_NAMEField;

    private string pHARMACEUTICAL_FORMField;

    /// <remarks/>
    public string DOSAGE
    {
        get
        {
            return this.dOSAGEField;
        }
        set
        {
            this.dOSAGEField = value;
        }
    }

    /// <remarks/>
    public ushort GENERIC_DRUG_ID
    {
        get
        {
            return this.gENERIC_DRUG_IDField;
        }
        set
        {
            this.gENERIC_DRUG_IDField = value;
        }
    }

    /// <remarks/>
    public string GENERIC_DRUG_NAME
    {
        get
        {
            return this.gENERIC_DRUG_NAMEField;
        }
        set
        {
            this.gENERIC_DRUG_NAMEField = value;
        }
    }

    /// <remarks/>
    public string PHARMACEUTICAL_FORM
    {
        get
        {
            return this.pHARMACEUTICAL_FORMField;
        }
        set
        {
            this.pHARMACEUTICAL_FORMField = value;
        }
    }
}

我收到以下错误:

System.InvalidOperationException: 'There is an error in XML document (33, 14).'

Inner Exception

InvalidOperationException: The specified type was not recognized: name='genericDrug', namespace='http://webservice.sirkb/', at http://www.govtalk.gov.uk/CM/envelope'>.

我从 线程中注意到,如果我从 XML 文件中删除 xsi:type="ns2:genericDrug",我可以反序列化 XML。我无法修改 XML,因为它是我针对请求获得的响应。在 XML 上进行字符串替换不是一个好的做法,所以我正在寻找更好的解决方案。

这可能是来自 this one 的重复问题,但由于我无法解决问题,所以我再次发布它,因为很难在评论部分获得帮助。

基于上述问题,我尝试更改 public partial class returnDRUG

的注释

来自

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]

[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.w3.org/2001/XMLSchema-instance", TypeName = "genericDrug")]

但仍然无法解析 XML。

解析代码简单

var deserializer = new XmlSerializer(typeof(GovTalkMessage));
TextReader textReader = new StreamReader("drug.xml"); //saved response in file for simplicity
GovTalkMessage response;
response = (GovTalkMessage)deserializer.Deserialize(textReader);
textReader.Close();

如何反序列化 GovTalkMessage 对象中的 XML?

需要在returnDRUG上换装饰class

由此

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
public partial class returnDRUG

至此

[System.Xml.Serialization.XmlTypeAttribute(TypeName = "genericDrug", Namespace = "http://webservice.sirkb/")]
public partial class returnDRUG

将其类型指定为 "genericDrug",关键位,将其命名空间更正为“http://webservice.sirkb/

我刚刚使用了您的代码并设法使用此更改反序列化。

解释是,如果您查看 DRUG 的定义,您会发现它的类型在命名空间别名 "ns2"

中定义为 "genericDRUG"
<DRUG xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:genericDrug">

如果您查看 ns2 别名的定义,您会发现它是“http://webservice.sirkb/

<ns2:getGenericDrugsResponse xmlns:ns2="http://webservice.sirkb/">

添加一些内容以防止 DRUG 对象的默认值

returnDrug class 的每个 属性 都应该有命名空间 http://www.govtalk.gov.uk/CM/envelope.

完整的 class 应具有以下形式:

[System.Xml.Serialization.XmlTypeAttribute(TypeName = "genericDrug", Namespace = "http://webservice.sirkb/")]
public partial class returnDRUG
{

    private string dOSAGEField;

    private ushort gENERIC_DRUG_IDField;

    private string gENERIC_DRUG_NAMEField;

    private string pHARMACEUTICAL_FORMField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
    public string DOSAGE
    {
        get
        {
            return this.dOSAGEField;
        }
        set
        {
            this.dOSAGEField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
    public ushort GENERIC_DRUG_ID
    {
        get
        {
            return this.gENERIC_DRUG_IDField;
        }
        set
        {
            this.gENERIC_DRUG_IDField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
    public string GENERIC_DRUG_NAME
    {
        get
        {
            return this.gENERIC_DRUG_NAMEField;
        }
        set
        {
            this.gENERIC_DRUG_NAMEField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.govtalk.gov.uk/CM/envelope")]
    public string PHARMACEUTICAL_FORM
    {
        get
        {
            return this.pHARMACEUTICAL_FORMField;
        }
        set
        {
            this.pHARMACEUTICAL_FORMField = value;
        }
    }
}