2013-06-20 110 views
1

我收到一個xml消息,將其轉換爲不同的格式,然後發送它。消息範圍從40行到600行或更多行,平均在100行左右。我可以每秒收到多封郵件,但在繁忙的時間裏平均每分鐘有15到20分鐘。通用XML到對象映射

由於xml爲現有的應用程序提供了新的信息,我創建了一個模仿輸出xml結構的類。該對象將創建輸出xml,僅包含已更改的項目,並且會將輸入術語轉換爲消費應用程序將理解的語言。我難以理解的是如何輕鬆地將傳入的xml映射到對象。

傳入的XML使用幾個不同的模板來確定每個節點的格式。我試圖創建一個映射,可以確定如果該節點被命名爲n,那麼它需要去對象m。以下是我想要做的一個簡化例子。

消息1

<Incoming> 
    <Name>Bob</Name> 
    <City>Seattle</City> 
    <Hobby>Fishing</Hobby> 
</Incoming> 

消息2

<Incoming> 
    <Name>Bob</Name> 
    <Employment> 
     <JobTitle>Sales</JobTitle> 
     <Manager>Jessica</Manager> 
    </Employment> 
    <Hobby>Reading</Hobby> 
</Incoming> 

這將進入類似這樣的對象:

public Customer 
{ 
    public String Name{get; set;} 
    public Address CustomerAddress{get;set;} 
    public Employer CustomerEmployer{get;set;} 
    public List<String> Hobbies{get;set;} 
} 

public Address 
{ 
    public String StreetAddress{get;set;} 
    public String City{get;set;} 
    public String State{get;set;} 
    public String Zip{get;set;} 
} 

public Employer 
{ 
    public String Company{get;set;} 
    public String Position{get;set;} 
    public String Manager{get;set;} 
    public Address CompanyAddress{get;set;} 
} 

,而無需創建一個長的開關盒,沒有任何人有想法關於如何最好地從xml獲取信息到對象?由於信息量大,我對於處理的時間成本有了更多的意識。

我想過想出一個映射;類似於

<Name>Customer:Name</Name> 
<City>Customer:Address:City</City> 

但是,存在如何映射列表中的項目(如Hobby)的問題。還有如何快速消費映射的問題。我能想到的唯一事情就是每個對象處理地圖的一部分以確定路徑,儘管這聽起來很昂貴。

我不擔心在不同級別的重複地址。這個數據就是一個例子。在我的實際XML中,我不認爲我有任何重複。

我很欣賞任何人的幫助或想法。先謝謝你。

+0

內置XML序列化不會有什麼原因嗎?請參閱System.Xml.Serialization上的MSDN。 http://msdn.microsoft.com/en-us/library/system.xml.serialization.aspx –

+0

您是否擁有用於XML的XSD?如果是這樣,請將該XSD與System.Xml.Serialization用作@MarcL。建議。 XSD允許您指定必需的和不需要的字段等。您的對象將填充指定的字段,其他將爲空。您還可以應用自定義規則來確定要序列化的內容以及何時傳遞對象。 – Anton

+0

謝謝你的迴應。我不從對象序列化到傳出xml的原因是,我只包含已更改的值(或對象),以節省處理消耗對象的時間。至於從傳入XML序列化,我試圖保持轉換類通用,所以它可以接受任何格式的XML使用任意的命名約定。這就是爲什麼我認爲使用映射xml爲每個應用程序的xml轉換器將消耗是一個好方法。這只是證明比我預期的更棘手。 – Tim

回答

2

我能夠使用反射和遞歸來訪問使用地圖的屬性。我設置了這樣的映射路徑:

map = new Dictionary<string, string>(); 
map.Add("Name", "Name"); 
map.Add("Street", "Address.Address"); 
map.Add("City", "Address.City"); 
map.Add("State", "Address.State"); 
map.Add("Zip", "Address.Zip"); 
map.Add("Activity", "*Hobbies.Hobby"); 
map.Add("Years", "*Hobbies.Years"); 

星號表示這是一個列表並需要一個密鑰。我在處理中添加了關鍵字,因此我發送的完整路徑類似於「* Hiking.Hobbies.Years」,徒步旅行是關鍵。處理這個方法如下:

private void SetValue(object source, String path, String value) 
{ 
    if (path.Contains('.')) 
    { 
     // If this is not the ending Property, continue recursing 
     int index = path.IndexOf('.'); 
     String property = path.Substring(0, index); 

     object nextSource; 
     if(property.Contains("*")) 
     { 
      path = path.Substring(index + 1); 
      index = path.IndexOf('.'); 
      String dictionaryName = path.Substring(0, index); 
      property = property.Substring(1); 

      IDictionary list = source.GetType().GetProperty(dictionaryName).GetValue(source, null) as IDictionary; 
      if (!list.Contains(property)) 
      { 
       Type[] arguments = list.GetType().GetGenericArguments(); 
       list.Add(property, Activator.CreateInstance(arguments[1])); 
      } 

      nextSource = list[property];      
     } 
     else 
      nextSource = source.GetType().GetProperty(property).GetValue(source, null); 

     SetValue(nextSource, path.Substring(index + 1), value); 
    } 
    else 
    { 
     PropertyInfo pi = source.GetType().GetProperty(path); 
     pi.SetValue(source, Convert.ChangeType(value, pi.PropertyType), null); 
    } 
} 

我希望這可以幫助別人。