简体   繁体   中英

C# can't deserialize XML containing xsi:type

I am trying to deserialize the following 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>

I have generated the classes through Paste XML as Classes feature of Visual Studio 2017. (Using the xsd.exe is the same) I have not changed the generated classes.

They have the following form:

// 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;
        }
    }
}

I get the following error:

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'>.

I have noticed from this thread that if I remove xsi:type="ns2:genericDrug" from the XML file I can deserialize the XML. I can't modify the XML because it is the response I get for the request. It is not a good practice to do a string replace on XML, so I am looking for a better solution.

This might be a duplicate question from this one , but since I am not able to solve the problem I am posting it again because it is difficult to get help in the comment section.

Based on the above question I have tried to change the annotation of public partial class returnDRUG

from

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

to

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

but still cant parse the XML.

The parsing code is simple

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();

What can I do to deserialize the XML in the GovTalkMessage object?

You need to change the decoration on the returnDRUG class

from this

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

to this

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

Specify it's type as "genericDrug", and the crucial bit, correct it's namespace to " http://webservice.sirkb/ "

I've just used you code and managed to de-serialize using this change.

The explanation is that if you take a look at the definition of DRUG you can see that it's type is defined as "genericDRUG" in the namespace alias "ns2"

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

if you look at the definition of the ns2 alias you can see that it's " http://webservice.sirkb/ "

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

Some addition to prevent default values for DRUG objects

Every property of the returnDrug class should have the namespace http://www.govtalk.gov.uk/CM/envelope .

The complete class should have the following form:

[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;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM