1

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 XmlAttribute value.

  • 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?

7
  • 4
    the missing "tst:"-prefix it's not missing at all. tst isn'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 code almost - 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) Commented Nov 3 at 9:33
  • 2
    stackoverflow.com/a/46865/1136211 Commented Nov 3 at 10:27
  • 1
    PanagiotisKanavos is not quite correct—attributes are not in the same namespace as their element. The answer linked by Clemens explains it well; your code is changing the data. I’m not familiar with XmlSerializer, so I can’t say what the specific problem is, sorry. Commented Nov 3 at 13:43
  • The duplicate here isn't correct. You have two problems. Firstly, you are capitalizing your list element names like so: <tst:MyListItem>. But XML is case sensitive, and the list element name is camel-cased in the required XML, so you must modify your XmlArray attribute application as follows: [XmlArray("myList"), XmlArrayItem("myListItem", Namespace = Namespaces.tst)] . Commented Nov 3 at 15:09
  • Secondly, with apologies to @PanagiotisKanavos, you really have encountered what appears to be a known bug in XmlSerializer, namely that when an attribute is supposed to be in the same namespace as its element, the serializer will ignore the attribute specified via XmlAttributeAttribute.Namespace unless you also set XmlAttributeAttribute.Form = XmlSchemaForm.Qualified. See my answer to XML attribute not getting namespace prefix for details. Commented Nov 3 at 15:12

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.