ChatGPT
ChatGPT

Reputation: 5617

How to deserialize XML into an object?

I'm trying to convert an XML doc (invoiceList) into an object. Ideally I'd like to convert it into a collection of objects ("Invoices").

Below is a fragment of the XML. I've also included a fragment off my INVOICE object. And finally my attempt at deserialization. The error message I get is so useless that I don't know where to start.

<?xml version="1.0" encoding="utf-8"?>
    <invoiceListResponse>
       <invoiceList>
         <invoiceListItem>
            <invoiceUid>39165890</invoiceUid>
            <lastUpdatedUid>AAAAADrKwis=</lastUpdatedUid>
            <ccy>JPY</ccy>
            <autoPopulateFXRate>false</autoPopulateFXRate>
            <fcToBcFxRate>1.0000000000</fcToBcFxRate>
            <transactionType>S</transactionType>
            <invoiceDate>2013-12-26</invoiceDate>
            <utcFirstCreated>2013-12-26T08:12:22</utcFirstCreated>
            <utcLastModified>2013-12-26T08:12:22</utcLastModified>
            <summary />
            <invoiceNumber>W101010101</invoiceNumber>

fragment of Invoice object code

[XmlRoot(ElementName = "invoice")]
public class InvoiceDto : TransactionDto
{
    public InvoiceDto()
    {
        TradingTerms = new TradingTermsDto();
        QuickPayment = new QuickPaymentDto();
    }

    public InvoiceDto(string transactionType, string layout)
    {
        Layout = layout;
        TransactionType = transactionType;
        TradingTerms = new TradingTermsDto();
        QuickPayment = new QuickPaymentDto();
    }

    [XmlElement(ElementName = "transactionType")]
    public string TransactionType;

    [XmlElement(ElementName = "invoiceType")]
    public string InvoiceType;

    [XmlElement(ElementName = "contactUid")]
    public int          ContactUid;

    [XmlElement(ElementName = "shipToContactUid")]
    public int ShipToContactUid;

    [XmlElement(ElementName = "externalNotes")]
    public string ExternalNotes;

My code:

Dim list As XmlDocument = proxy.Find(queries)
'Deserialize text file to a new object. 
    Using reader As XmlReader = XmlReader.Create(New StringReader(list.InnerXml))
      reader.MoveToContent()
      reader.Read()
      reader.Read()
      theinv = DirectCast(New XmlSerializer(GetType(Dto.InvoiceDto)).Deserialize(reader), Dto.InvoiceDto)
      Debug.Write(theinv.InvoiceNumber)

Error is:

An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.dll

Additional information: There is an error in XML document (1, 74).

Upvotes: 1

Views: 2192

Answers (1)

Steven Doggart
Steven Doggart

Reputation: 43743

The easiest thing to do is to create a class that matches the entire XML document from its root level down. It doesn't need to contain a property for every node, but it needs to at least contain a property for each element in the path to get from the root element down to the ones that you care about. For instance, the following class will work to load the document in your example:

[XmlRoot("invoiceListResponse")]
public class InvoiceListResponse
{

    [XmlArray("invoiceList")]
    [XmlArrayItem("invoiceListItem")]
    public InvoiceDto[] InvoiceList;
}

Then, you can deserialize into it like this:

XmlSerializer s = new XmlSerializer(typeof(InvoiceListResponse));
using (FileStream f = new FileStream("Test.xml", System.IO.FileMode.Open))
{
    InvoiceListResponse response = (InvoiceListResponse)s.Deserialize(f);
}

Edit

Based on your comments, below, it appears that what you need to do is to deserialize into that exact DTO class, without making any modifications to it. If that is the case, and you don't want to create a wrapper class as I demonstrated in my first example, you could always do something like this:

Dim invoices As New List(Of InvoiceDto)()
Dim serializer As New XmlSerializer(GetType(InvoiceDto))
For Each i As XmlNode In doc.SelectNodes("/invoiceListResponse/invoiceList/invoiceListItem")
    Using reader As New StringReader("<invoice>" & i.InnerXml & "</invoice>")
        invoices.Add(DirectCast(serializer.Deserialize(reader), InvoiceDto))
    End Using
Next

Upvotes: 1

Related Questions