2013-05-13 3 views
2

Я пытаюсь использовать XmlAttributeOverrides для управления свойствами класса, появляющимися в xml после того, как класс был сериализован. Он работает с свойствами, которые находятся в «корневом» классе, но не на вложенных свойствах. Вот простой пример, иллюстрирующий то, что я пытаюсь выполнить.Использование XmlAttributeOverrides для вложенных свойств

Мой класс иерархия выглядит следующим образом:

public class Main 
{ 
    public string Name { get; set; } 
    public Location Address { get; set; } 
} 

public class Location 
{ 
    public string StreetAddress { get; set; } 
    public Contact ContactInfo{ get; set; } 
} 

public class Contact 
{ 
    public string PhoneNumber { get; set; } 
    public string EmailAddr { get; set; } 
} 

Когда я сериализации Main(), я получаю что-то вроде этого:

<Main> 
    <Name></Name> 
    <Address> 
     <StreetAddress></StreetAddress> 
     <ContactInfo> 
      <PhoneNumber></PhoneNumber> 
      <EmailAddr></EmailAddr> 
     </ContactInfo> 
    </Address> 
</Main> 

Что я могу сделать, это держать Имя или адрес появляться при использовании этого:

XmlAttributeOverrides overrides = new XmlAttributeOverrides(); 
XmlAttributes attribs = new XmlAttributes(); 
attribs.XmlIgnore = true; 
attribs.XmlElements.Add(new XmlElementAttribute("Address")); 
overrides.Add(typeof(Main), "Address", attribs); 
xs = new XmlSerializer(typeof(Main), overrides); 

Что мне нужно, чтобы быть в состоянии сделать, это держать Main.Address.ContactInf o от сериализации ИНОГДА (если он пуст). Я попытался следующие, но они не работали:

XmlAttributeOverrides overrides = new XmlAttributeOverrides(); 
XmlAttributes attribs = new XmlAttributes(); 
attribs.XmlIgnore = true; 
attribs.XmlElements.Add(new XmlElementAttribute("ContactInfo ")); 
overrides.Add(typeof(Contact), "ContactInfo ", attribs); 
xs = new XmlSerializer(typeof(Contact), overrides); 

и ...

XmlAttributeOverrides overrides = new XmlAttributeOverrides(); 
XmlAttributes attribs = new XmlAttributes(); 
attribs.XmlIgnore = true; 
attribs.XmlElements.Add(new XmlElementAttribute("ContactInfo ")); 
overrides.Add(typeof(Main.Address.ContactInfo), "ContactInfo ", attribs); 
xs = new XmlSerializer(typeof(Main.Address.ContactInfo), overrides); 

Я на самом деле пытался многое другое, в том числе используя операторы XPath назначить имя атрибута целевому но не хотел заполнять эту страницу неудачными попытками. Является ли то, что я прошу даже по этому методу?

ответ

4

Есть более простые способы добиться того, что вы ищете.

Вы сказали, что вы пытаетесь не сериализовать /Main/Address/ContactInfo, если ContactInfo не содержит данных.

Если вы оставите свой код как есть, он будет сериализовать все свойства Main, независимо от того, являются ли они пустыми или пустыми или нет. На первом этапе вам нужно добавить свойство XmlSerializerNamespaces ко всем вашим объектам, или каждый пустой объект будет сериализован как <myElement xsi:nil="true" />. Это может быть достигнуто легко, следующим образом:

public MyXmlElement 
{ 
    public MyXmlElement() 
    { 
     // Add your own default namespace to your type to prevet xsi:* and xsd:* 
     // attributes from being generated. 
     this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] { 
      new XmlQualifiedName(string.Empty, "urn:myDefaultNamespace") }); 
    } 

    [XmlElement("MyNullableProperty", IsNullable=false)] 
    public string MyNullableProperty 
    { 
     get 
     { 
      return string.IsNullOrWhiteSpace(this._myNullableProperty) ? 
       null : this._myNullableProperty; 
     } 
     set { this._myNullableProperty = value; } 
    } 

    [XmlNamespacesDeclaration] 
    public XmlSerializerNamespaces Namespaces { get { return this._namespaces; } } 
    private XmlSerializerNamespaces _namespaces; 
} 

Код выше объявляет Namespaces свойства, которое содержит все соответствующие пространства имен для объекта XML. Вы должны предоставить пространство имен по умолчанию для всех ваших объектов (смоделированных после кода выше). Это предотвращает вывод атрибутов xsi:* и xsd:* для ваших объектов при их сериализации. Кроме того, укажите, что элемент не имеет значения NULL, используя System.Xml.Serialization.XmlElementAttribute.

Кроме того, путем проверки на string.IsNullOrWhiteSpace(someVariable) и возврата нулевого значения, то свойство не будет сериализовано, если вышеуказанное было сделано.

Итак, положив все это вместе для вашего Location класса:

public class Location 
{ 
    // You should have a public default constructor on all types for (de)sereialization. 
    public Location() 
    { 
     this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] { 
      new XmlQualifiedName(string.Empty, "urn:myNamespace"); // Default namespace -- prevents xsi:nil="true" from being generated, as well as xsd:* attributes. 
     }); 
    } 

    public string StreetAddress 
    { 
     // If you don't want <StreetAddress xsi:nil="true" /> to be generated, do this: 
     get { return string.IsNullOrEmpty(this._streetAddress) ? null : this._streetAddress; } 

     // Otherwise, if you don't care, just do 
     // get; 

     // Only need to implement setter if you don't want xsi:nil="true" to be generated. 
     set { this._streetAddress = value; } 

     // Otherwise, just 
     // set; 
    } 
    private string _streetAddress; 

    [XmlElement("ContactInfo", IsNullable=false)] 
    public Contact ContactInfo 
    { 
     // You must definitely do this to prevent the output of ContactInfo element 
     // when it's null (i.e. contains no data) 
     get 
     { 
      if (this._contactInfo != null && string.IsNullOrWhiteSpace(this._contactInfo.PhoneNumber) && string.IsNullOrWhiteSpace(this._contactInfo.EmailAddr)) 
       return null; 

      return this._contactInfo; 
     } 

     set { this._contactInfo = value; } 
    } 
    private Contact _contactInfo; 

    [XmlNamespacesDeclarations] 
    public XmlSerializerNamespaces Namespaces 
    { 
     get { return this._namespaces; } 
    } 
    private XmlSerializerNamespaces _namespaces; 
} 

С этими изменениями в вашем Location класса, пустое ContactInfo свойство больше не должно быть сериализовать в XML, когда ни одно из свойств не равны нулю, пустой , или пробел, или если ContactInfo сам по себе является нулевым.

Вы должны внести аналогичные изменения в свои другие объекты.

Смотрите другие мои ответы StackOverflow больше на .NET XML сериализации:

+0

Это замечательно! Большое вам спасибо за усилия, которые вы вложили в этот ответ! – user1437872

+0

@ user1437872: Я рад, что вы нашли этот ответ полезным. Не могли бы вы отметить этот ответ как ответ, если это решило ваш вопрос? Отметив этот вопрос как ответ, он увеличивает мою репутацию на сайте. Это помогает другим знать, как хорошая (или не) информация может быть на сайте. Еще раз спасибо за положительный комментарий! – fourpastmidnight

+0

Спасибо за ответ! – fourpastmidnight

1

Для тех, кто еще пытается сделать это с XmlAttributeOverrides, оказывается что @ user1437872 был очень близок к поиску ответа. Вот код переопределения для игнорирования вложенного элемента ContactInfo.

XmlAttributeOverrides overrides = new XmlAttributeOverrides(); 
XmlAttributes attribs = new XmlAttributes(); 
attribs.XmlIgnore = true; 
attribs.XmlElements.Add(new XmlElementAttribute("ContactInfo")); 
overrides.Add(typeof(Address), "ContactInfo ", attribs); 
xs = new XmlSerializer(typeof(Main), overrides); 
Смежные вопросы