I am trying to deserialize a given piece of XML that looks like this:
<?xml version="1.0" encoding="utf-8"?>
<tst:myRootElement xmlns:tst="myGivenNamespace">
<tst:myList>
<tst:myListItem>
<tst:myElementName tst:value="element1" />
</tst:myListItem>
<tst:myListItem>
<tst:myElementName tst:value="element2" />
</tst:myListItem>
</tst:myList>
</tst:myRootElement>
My classes (VS 2022 professional, target-framework .NET 8.0):
public static class Namespaces
{
public const string tst = "myGivenNamespace";
}
[XmlRoot("myRootElement", Namespace = Namespaces.tst)]
public class MyRootElement
{
[XmlArray("myList"), XmlArrayItem(typeof(MyListItem), Namespace = Namespaces.tst)]
public List<MyListItem>? MyList { get; set; }
}
[XmlRoot("myListItem", Namespace = Namespaces.tst)]
public class MyListItem
{
[XmlElement("myElementName", Namespace = Namespaces.tst)]
public MyElementName? ElementName { get; set; }
}
[XmlRoot("myElementName", Namespace = Namespaces.tst)]
public class MyElementName
{
[XmlAttribute("value", Namespace = Namespaces.tst)]
public string? Value { get; set; }
}
My code for serialization and deserialization:
var namespaces = new XmlSerializerNamespaces();
namespaces.Add("tst", "myGivenNamespace");
var serializer = new XmlSerializer(typeof(MyRootElement));
var root1 = new MyRootElement();
root1.MyList = new List<MyListItem>();
root1.MyList.Add(new MyListItem { ElementName = new MyElementName { Value = "element1" } });
root1.MyList.Add(new MyListItem { ElementName = new MyElementName { Value = "element2" } });
// serialization
using (var fstream = new FileStream(@"c:\temp\serializertestOut.xml", FileMode.Create))
{
serializer.Serialize(fstream, root1, namespaces);
}
// deserialization
MyRootElement? root2 = null;
using (var fstream = new FileStream(@"c:\temp\serializertestIn.xml", FileMode.Open))
{
root2 = (MyRootElement?)serializer.Deserialize(fstream);
}
MyRootElement? root3 = null;
using (var fstream = new FileStream(@"c:\temp\serializertestOut.xml", FileMode.Open))
{
root3 = (MyRootElement?)serializer.Deserialize(fstream);
}
What happens when I run this code is:
root1 is serialized to this:
<?xml version="1.0" encoding="utf-8"?> <tst:myRootElement xmlns:tst="myGivenNamespace"> <tst:myList> <tst:MyListItem> <tst:myElementName value="element1" /> </tst:MyListItem> <tst:MyListItem> <tst:myElementName value="element2" /> </tst:MyListItem> </tst:myList> </tst:myRootElement>Note the missing
tst:-prefix of the XmlAttributevalue.root2 is created as a MyRootElement-Instance with an empty list of MyListElements.
root3 is created correctly, as expected, since it gets the formerly created XML from the serializer as input.
So, is there something wrong with my code? Or is there a bug in XmlSerializer, and if so, is there a way to work around this?
the missing "tst:"-prefixit's not missing at all.tstisn't a prefix, it's the namespace of the element and doesn't have to be repeated in every attribute. All deserializers will work fine with this.is there something wrong with my codealmost - the expectation is wrong. With something that was built in 2000 to support XML from the very start and is used by millions of developers and applications, the chances of a basic bug are almost zero. As Jon Skeet wrote, No, the bug is in your code (and mine)<tst:MyListItem>. But XML is case sensitive, and the list element name is camel-cased in the required XML, so you must modify yourXmlArrayattribute application as follows:[XmlArray("myList"), XmlArrayItem("myListItem", Namespace = Namespaces.tst)].XmlSerializer, namely that when an attribute is supposed to be in the same namespace as its element, the serializer will ignore the attribute specified viaXmlAttributeAttribute.Namespaceunless you also setXmlAttributeAttribute.Form = XmlSchemaForm.Qualified. See my answer to XML attribute not getting namespace prefix for details.