2014-11-16 4 views
2

나는 다음과 같은 XML 구조가 있습니다직렬화 복원 중복 된 XML 요소

<Response> 
    <Value Name="ID">1</Value> 
    <Value Name="User">JSmith</Value> 
    <Value Name="Description">Testing 123</Value> 
</Response> 

내가 값 이름이 클래스의 속성, 그리고 텍스트 값이 속성의 값을 확인하기 위해 본을 직렬화 수있는 방법을 ?

값 이름은 절대로 변경되지 않으므로 Name="ID"이 항상 존재한다는 점에 유의하십시오. 여기

지금까지 내 클래스 :

[Serializable] 
[XmlRoot("Response")] 
public class ReportingResponse 
{ 
    // [What goes here?] 
    public string ID { get; set; } 

    // [...] 
    public string User { get; set; } 

    // [...] 
    public string Description { get; set; } 
} 
+0

['XmlSerializer'] (http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer%28v=vs.110%29.aspx)를 사용하고 있다고 가정합니다. 그 맞습니까? – dbc

+0

@dbc 네, 맞습니다. – qJake

답변

3

XML 이름/값 쌍의 컬렉션으로보다는 미리 정의 된 특성을 가진 클래스로 구성되어, 그것은 쉽고 직렬화하는 것이 더 자연 것이라고 그렇게. 당신은 당신이 XmlSerializer를 사용하는 가정, 클래스에 직렬화하기로 결정 경우

, 당신과 같이, 그 목적을 위해 이름/값 쌍의 프록시 배열을 소개 할 수 : 다음 몇 가지

public class NameValuePair 
{ 
    [XmlAttribute] 
    public string Name { get; set; } 

    [XmlText] 
    public string Value { get; set; } 

    public override string ToString() 
    { 
     return string.Format("Name={0}, Value=\"{1}\"", Name, Value); 
    } 
} 

[Serializable] 
[XmlRoot("Response")] 
public class ReportingResponse 
{ 
    [XmlElement(ElementName="Value")] 
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
    [DebuggerBrowsable(DebuggerBrowsableState.Never)] 
    public NameValuePair[] XmlNameValuePairs 
    { 
     get 
     { 
      return NameValuePairExtensions.GetNamedValues(this).ToArray(); 
     } 
     set 
     { 
      NameValuePairExtensions.SetNamedValues(this, value); 
     } 
    } 

    [XmlIgnore] 
    public string ID { get; set; } 

    [XmlIgnore] 
    public string User { get; set; } 

    [XmlIgnore] 
    public string Description { get; set; } 
} 

과 반사를 사용하여 배열을 자동으로로드합니다.

public static class NameValuePairExtensions 
{ 
    public static List<NameValuePair> GetNamedValues<T>(T obj) 
    { 
     if (obj == null) 
      throw new ArgumentNullException(); 
     var type = obj.GetType(); 
     var properties = type.GetProperties(); 
     List<NameValuePair> list = new List<NameValuePair>(); 
     foreach (var prop in properties) 
     { 
      if (prop.PropertyType == typeof(string)) 
      { 
       var getter = prop.GetGetMethod(); 
       var setter = prop.GetSetMethod(); 

       if (getter != null && setter != null) // Confirm this property has public getters & setters. 
       { 
        list.Add(new NameValuePair() { Name = prop.Name, Value = (string)getter.Invoke(obj, null) }); 
       } 
      } 
     } 
     return list; 
    } 

    public static void SetNamedValues<T>(T obj, IEnumerable<NameValuePair> values) 
    { 
     if (obj == null || values == null) 
      throw new ArgumentNullException(); 
     var type = obj.GetType(); 
     foreach (var value in values) 
     { 
      var prop = type.GetProperty(value.Name); 
      if (prop == null) 
      { 
       Debug.WriteLine(string.Format("No public property found for {0}", value)); 
       continue; 
      } 
      try 
      { 
       prop.SetValue(obj, value.Value, null); 
      } 
      catch (Exception ex) 
      { 
       Debug.WriteLine("Exception setting " + value.ToString() + " : \n" + ex.ToString()); 
      } 
     } 
    } 
} 

이렇게하면 배열에 모든 문자열 값 속성 이름과 값이 채워집니다. 좀 더 지능적인 것을 원할 수도 있습니다. 수동으로 배열을 채우거나 내보낼 변수를 나타내는 사용자 지정 속성으로 속성에 레이블을 붙이는 등 더 적절할 수 있습니다.

+0

그건 내가 생각한 종류의 사건입니다. 감사. 이 작품을, 그러나, 나는 (적어도 내 구현에 대한) 더 쉬운 방법은 그냥 "값"클래스를 만들고 배열에 결과를 저장하고 속성 참조의 Getter Linq (예 : public string ID {get {return myValues.FirstOrDefault (v => v.Name == "ID");}}'). – qJake

+0

[XmlText]가 내 문제를 해결하는 열쇠였습니다. 이것은 변수 이름을 새 요소로 가지지 않고 요소에 값을 넣을 수있게합니다. – redwards510