3

I'm trying to deserialize following XML:

<nsMain:Parent xmlns:nsMain="http://main.com">
    <nsMain:Child xmlns:nsSub="http://sub.com" nsSub:value="foobar" />
</nsMain:Parent>

Notice the namespace of the attribute is different than namespaces of both elements.

I have two classes:

[XmlRoot(ElementName = "Parent", Namespace = "http://main.com")]
public class Parent
{
    [XmlElement(ElementName = "Child")]
    public Child Child{ get; set; }
}

[XmlType(Namespace = "http://sub.com")]
public class Child
{
    [XmlAttribute(AttributeName = "value")]
    public string Value { get; set; }
}

The XML comes as a HTTP POST request's body, inside HttpRequestMessage object. The function for deserializing is:

private Parent ExtractModel(HttpRequestMessage request)
{
    var serializer = new XmlSerializer(typeof(Parent));
    var model = (Parent)serializer.Deserialize(request.Content.ReadAsStreamAsync().Result);
    return model;
}

However, after calling this function it appears that model.Child.Value == null.

I tried to experiment a bit with the Namespace parameter of C# attributes on classes and properties (e.g. move it to [XmlAttribute], or put both in [XmlType] and [XmlAttribute]), but it didn't change anything. I can't seem to make this right. If I don't use namespace at all (both in request and in the model definition) then the value reads just fine.

What am I missing?

Sushi271
  • 544
  • 2
  • 8
  • 22

1 Answers1

1

You are applying your namespace "http://sub.com" element Child, not to its value attribute. In your XML, you specifically apply "http://main.com" to both, Parent and Child. You can fix your namespaces like this:

[XmlRoot(ElementName = "Parent", Namespace = "http://main.com")]
public class Parent
{
    [XmlElement(ElementName = "Child")]
    public Child Child{ get; set; }
}

[XmlType(Namespace = "http://main.com")]
public class Child
{
    [XmlAttribute(AttributeName = "value", Namespace = "http://sub.com")]
    public string Value { get; set; }
}
Sefe
  • 13,731
  • 5
  • 42
  • 55
  • Thanks, it worked. Somehow I had a misguided idea about how this works. I mean... that if you put a Namespace on an entire class, it becomes default for all of its members. This way I thought that Parent Namespace is default for its Child, and the Child Namespace actually works as default for the Value... But that is not the case apparently. The main confusion is... In which cases one should put Namespaces on members, and in which on classes? – Sushi271 Dec 18 '17 at 16:00
  • 1
    You put the namespaces where you have them in your XML. – Sefe Dec 18 '17 at 16:04
  • Does it mean that I could put the `http://main.com` namespace either on the Child class or the Child property in Parent (and it shouldn't matter)? They kinda represent the same. – Sushi271 Dec 18 '17 at 16:22
  • That is a very specific answer I can‘t answer from the top of my head. Maybe you try it out? – Sefe Dec 18 '17 at 19:45
  • 1
    @Sushi271 - XML elements are in their parents' namespace by default, but XML attributes are in no namespace by default. This is explained in the [XML standard]: *The namespace name for an unprefixed attribute name always has no value.* `XmlSerializer` respects this by default, so you need to set the namespace of the attribute explicitly. Though see [here](https://stackoverflow.com/a/36163079/3744182) for a problem that might arise if you do. – dbc Dec 19 '17 at 00:36