2013-05-13 5 views
2

XmlAttributeOverrides를 사용하여 클래스를 serialize 한 후 xml에 표시 할 클래스 속성을 제어하려고합니다. "루트"클래스에는 있지만 중첩 된 속성에는없는 속성에서 작동합니다. 다음은 내가 성취하려는 것을 보여주기위한 간단한 예입니다. 난 할 수 있어요하는 이름이나 주소 중 하나를 유지중첩 된 속성에 XmlAttributeOverrides 사용

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

이다 : 나는 홈페이지()를 직렬화 할 때

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

, 나는 이런 식으로 뭔가를 얻을 다음과 같이

내 클래스 계층 구조입니다

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을 직렬화하지 않는 것이 좋습니다.

코드를 그대로두면 null이거나 비어 있는지 여부에 상관없이 모든 Main 속성이 직렬화됩니다. 첫 번째 단계는 XmlSerializerNamespaces 속성을 모든 개체에 추가해야하며 그렇지 않은 경우 각 빈 개체는 <myElement xsi:nil="true" />으로 serialize됩니다. 다음과 같이 쉽게 수행 할 수 있습니다

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

위의 코드는 XML 객체의 모든 관련 네임 스페이스를 보유하고 Namespaces 속성을 선언합니다. 모든 객체에 대해 기본 네임 스페이스를 제공해야합니다 (위 코드를 모델로 함). 이렇게하면 xsi:*xsd:* 특성이 직렬화 될 때 개체에 출력되지 않습니다. 또한 System.Xml.Serialization.XmlElementAttribute을 사용하여 요소가 Nullable이 아닌 것으로 지정하십시오.

또한 string.IsNullOrWhiteSpace(someVariable)을 확인하고 null을 반환하면 위의 작업을 수행 할 때 속성이 직렬화되지 않습니다.

그래서, 당신의 Location 클래스 모두 함께이 퍼팅 : 당신의 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; 
} 

, 빈 ContactInfo 속성은 더 이상 속성 중 어느 것도 빈, null이 없을 때 XML로 직렬화되어서는 안된다 , 또는 공백, 또는 ContactInfo 자체가 null의 경우

다른 개체를 비슷하게 변경해야합니다.

.NET의 XML 직렬화에 대한 자세한 내용은 내 다른 유래의 답변을 참조하십시오 : XmlAttributeOverrides이 작업을 수행하려고 다른 사람들을위한

+0

완벽합니다. 이 답변에 대한 귀하의 노력에 감사드립니다! – user1437872

+0

@ user1437872 :이 답변이 도움이 되었기 때문에 기쁩니다. 이것이 당신의 질문을 해결했다면이 대답을 답으로 표시해 주시겠습니까? 이 질문을 대답으로 표시하면 사이트에서의 평판이 높아집니다. 이것은 다른 사람들이 사이트에 얼마나 좋은 (또는 아님) 정보가 있는지 알 수있게 도와줍니다. 긍정적 인 코멘트에 다시 한번 감사드립니다 !! – fourpastmidnight

+0

답변 해 주셔서 감사합니다! – fourpastmidnight

1

이 밝혀 @ 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);