Могу ли я избежать загромождения своего класса повторяющимися атрибутами XmlElement, даже если корневой узел находится в другом пространстве имен, чем его дочерние элементы?

#c# #xml #serialization

#c# #xml #сериализация

Вопрос:

Я извлекаю XML-документы из веб-службы, которую я не контролирую. XML форматируется аналогично следующему:

 <?xml version="1.0"?>
<ns:obj xmlns:ns="somenamespace">
     <address>1313 Mockingbird Lane</address>
     <residents>5</residents>
</ns:obj>
  

где корневой узел находится в пространстве имен «ns», но ни один из его дочерних элементов.

После некоторых проб и ошибок я обнаружил, что могу десериализовать документ в объект C #, выполнив следующее:

 [XmlRoot(Namespace="somenamespace", ElementName="obj")]
public class xmlObject
{
    [XmlElement(Namespace = "")]
    public string address { get; set; }

    [XmlElement(Namespace = "")]
    public int residents { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        string xml =
            "<?xml version="1.0"?>"  
            "<ns:obj xmlns:ns="somenamespace">"  
            "   <address>1313 Mockingbird Lane</address>"  
            "   <residents>5</residents>"  
            "</ns:obj>";

        var serializer = new XmlSerializer(typeof(xmlObject));

        using (var reader = new StringReader(xml))
        {
             var result = serializer.Deserialize(reader) as xmlObject;

             Console.WriteLine("{0} people live at {1}", result.residents, result.address);
             // Output: "5 people live at 1313 Mockingbird lane"
        }
    }
}
  

Если я опущу XmlElementAttribute on отдельных членов, я вместо этого получу пустой объект. Т.е. Вывод гласит

 0 people live at 
  

( result.address равно null .)

Я понимаю обоснование того, почему процесс десериализации работает именно так, но мне интересно, есть ли менее подробный способ сообщить XmlSerializer , что дочерние элементы объекта не находятся в том же пространстве имен, что и корневой узел.

Объекты, с которыми я работаю в рабочей среде, имеют десятки членов, и, ради чистоты, я бы хотел избежать пометки их всех [XmlElement(Namespace = "")] , если этого легко избежать.

Ответ №1:

Вы можете объединить XmlRootAttribute с XmlTypeAttribute , чтобы сделать так, чтобы корневой элемент и элементы корневого элемента имели разные пространства имен:

 [XmlRoot(Namespace="somenamespace", ElementName="obj")]
[XmlType(Namespace="")]
public class xmlObject
{
    public string address { get; set; }

    public int residents { get; set; }
}
  

Используя приведенный выше тип, если я десериализую и повторно сериализую ваш XML, я получаю:

 <q1:obj xmlns:q1="somenamespace">
  <address>1313 Mockingbird Lane</address>
  <residents>5</residents>
</q1:obj>
  

Пример скрипки.

Ответ №2:

Если вы знаете контракт с веб-службой, почему бы не использовать DataContractSerializer для десериализации XML в объекты?