XmlSerializer Deserializing Array/List of Multiple Objects at Root

15.8k views Asked by At

I'm trying to deserialize the following XML output:

<?xml version="1.0" encoding="ISO-8859-1"?>
<Foo>
   <Val>Data1</Val>
</Foo>
<Foo>
   <Val>Data2</Val>
</Foo>

(This is output from a hardware device, and cannot be changed)

I have an XML type defined as:

    [XmlType(AnonymousType=true, Namespace="")]
    public class Foo
    {
        public string Val { get; set; }
    }

I've tried to deserialize this array by creating a serializer like:

  var s = new XmlSerializer(typeof(Foo[]));
  //or
  var s = new XmlSerializer(typeof(List<Foo>);

But every call to s.Deserialize() causes an InvalidOperaitonException:

 System.InvalidOperationException: <Foo xmlns=''> was not expected.

Note

 var s = new XmlSerializer(typeof(Foo));
 // Only deseralizes the first Foo (Data1).

Thanks for your help.

6

There are 6 answers

3
Adriaan Stander On BEST ANSWER

I think the issue is with your provided xml.

Test app says

List<Foo> list = new List<Foo> {new Foo {Val = "Data1"}, new Foo {Val = "Data2"}};
var s = new XmlSerializer(typeof(List<Foo>));
StringBuilder sb = new StringBuilder();
XmlWriter wr = XmlWriter.Create(sb);
s.Serialize(wr, list);

string ss = sb.ToString();

var s2 = new XmlSerializer(typeof(List<Foo>));
StringReader sr = new StringReader(ss);
List<Foo> returnList = (List<Foo>)s2.Deserialize(sr);

And the XML should be

<?xml version="1.0" encoding="utf-16"?>
<ArrayOfFoo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Foo>
        <Val>Data1</Val>
    </Foo>
    <Foo>
        <Val>Data2</Val>
    </Foo>
</ArrayOfFoo>

If you can remove the inital line

<?xml version="1.0" encoding="ISO-8859-1"?>

And minipulate the string into

string s = "<ArrayOfFoo><Foo>   <Val>Data1</Val></Foo><Foo>   <Val>Data2</Val></Foo></ArrayOfFoo>";
var s2 = new XmlSerializer(typeof(List<Foo>));
StringReader sr = new StringReader(s);
List<Foo> list = (List<Foo>)s2.Deserialize(sr);

That could work.

0
Gopi On

Xstream for .Net could be a useful API

1
cjk On

That isn't valid Xml. There needs to be a core root element for it to work properly.

0
Marcel On

As the other posters say, this XML that the hardware device produces is not compatible to the way .NET serializes/deserializes object. Valid XML, and .NET requires valid XML, has a root element.

I suggest:

  • either you modify your obtained XML to match the way astander presents in his xml code snippet.
  • or you write a simple xml parser for your file that deserializes the file like you need

br, Marcel

0
Numenor On

this is not a valid xml so you can not deserialize it like a valid xml. You need some kind of hack to make this work. i'd suggest to insert at beginning of the xml and inserting at the end of xml. then you can deserialize it, since you cant make this change at xml side, do it in your code.

String ss; 
// lets assume this holds your xml data in string.
ss.append("</ArrayOfFoo>");
ss.replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>", "<?xml version=\"1.0\" encoding=\"utf-16\"?> <ArrayOfFoo>")

var s2 = new XmlSerializer(typeof(List<Foo>));
StringReader sr = new StringReader(ss);
List<Foo> returnList = (List<Foo>)s2.Deserialize(sr); 

now this shall return you the correct list.

0
Kevin Reid On

Technically, what you have there is not a well-formed XML document (which has exactly one root element), but rather an well-formed external parsed entity (which can have any number of elements not contained in other elements, as well as text not contained in any elements). Therefore, it should parse if your XML parser has an entry point for parsing EPEs rather than documents. You could also create a stub document which includes by reference your EPE and parse that document.