2013-05-13 87 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

有更簡單的方法來實現你要找的東西。

你說你試圖實現的是,如果ContactInfo不包含數據,則不要序列化/Main/Address/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:*屬性。此外,通過使用System.Xml.Serialization.XmlElementAttribute指定元素不可爲空。

此外,通過檢查string.IsNullOrWhiteSpace(someVariable)並返回null,那麼 屬性將不會在完成上述操作時序列化。

因此,把所有這一切共同爲您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本身爲空。

您應該對其他對象進行類似的更改。

看我其他計算器解答更多關於.NET XML序列化:

+0

很完美!非常感謝您爲此付出的努力! – user1437872 2013-05-13 18:11:04

+0

@ user1437872:很高興您發現此答案有幫助。如果這能解決您的問題,您能否將這個答案標記爲答案?通過將此問題標記爲答案,它可以提高我在網站上的聲譽。這有助於他人知道網站上的信息可能有多好(或不是)。再次感謝您的積極評價! – fourpastmidnight 2013-05-13 18:18:06

+0

感謝您的回答! – fourpastmidnight 2013-05-16 19:08:53

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);