XML-атрибут с пространством имен, отличным от родительского, десериализуется как null

Я пытаюсь десериализовать следующий XML:

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

Обратите внимание, что пространство имен атрибута отличается от пространств имен обоих элементов.

У меня есть два класса:

[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; }
}

XML представляет собой тело запроса HTTP POST внутри объекта HttpRequestMessage. Функция для десериализации:

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

Однако после вызова этой функции оказывается, что model.Child.Value == null.

Я попытался немного поэкспериментировать с параметром Namespace атрибутов C# в классах и свойствах (например, переместить его в [XmlAttribute] или поместить оба в [XmlType] и [XmlAttribute]), но это ничего не изменило. Кажется, я не могу сделать это правильно. Если я вообще не использую пространство имен (как в запросе, так и в определении модели), то значение читается просто отлично.

Что мне не хватает?


person Sushi271    schedule 18.12.2017    source источник


Ответы (1)


Вы применяете свое пространство имен "http://sub.com" элемент Child, а не к его атрибуту value. В вашем XML вы специально применяете "http://main.com" к обоим, Parent и Child. Вы можете исправить свои пространства имен следующим образом:

[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; }
}
person Sefe    schedule 18.12.2017
comment
Спасибо, это сработало. Как-то у меня было ошибочное представление о том, как это работает. Я имею в виду... что если вы поместите пространство имен для всего класса, оно станет значением по умолчанию для всех его членов. Таким образом, я думал, что родительское пространство имен используется по умолчанию для его дочернего элемента, а дочернее пространство имен фактически работает по умолчанию для значения... Но, очевидно, это не так. Основная путаница... В каких случаях следует помещать пространства имен в члены, а в каких - в классы? - person Sushi271; 18.12.2017
comment
Вы помещаете пространства имен там, где они есть в вашем XML. - person Sefe; 18.12.2017
comment
Означает ли это, что я могу поместить пространство имен http://main.com либо в класс Child, либо в свойство Child класса Parent (и это не имеет значения)? Они представляют собой одно и то же. - person Sushi271; 18.12.2017
comment
Это очень конкретный ответ, на который я не могу ответить сразу. Может, ты попробуешь? - person Sefe; 18.12.2017
comment
@ Sushi271 - элементы XML по умолчанию находятся в пространстве имен своих родителей, но атрибуты XML по умолчанию не находятся в пространстве имен. Это объясняется в [стандарте XML]: Имя пространства имен для имени атрибута без префикса всегда не имеет значения. XmlSerializer учитывает это по умолчанию, поэтому вам необходимо явно задать пространство имен атрибута. Хотя см. здесь проблему, которая может возникнуть, если вы это сделаете. - person dbc; 19.12.2017