2012-12-06 122 views
1

我想將XML數據轉換爲字典。我遇到了相同節點名稱的問題。 C#.Net 3.5嵌套XML到字典

示例XML =問題是我無法控制這一點。我只需要處理它。

<?xml version="1.0" encoding="utf-8"?> 
<Root> 
    <a1>val1</a1> 
    <a2>val2</a2> 
    <Parameter> 
    <ParameterName>param1</ParameterName> 
    <ParameterValue>paramval1</ParameterValue> 
    </Parameter> 
    <Parameter> 
    <ParameterName>param2</ParameterName> 
    <ParameterValue>paramval2</ParameterValue> 
    </Parameter> 
</Root> 

我嘗試:

XMLStream.Position = 0; 
     XElement xmlDetails2 = XElement.Load(new System.IO.StreamReader(XMLStream)); 
     var x = xmlDetails2.Elements().ToDictionary(
      e => e.Name.LocalName, 
      e => e.Elements() 
         .ToDictionary(
          f => f.Name.LocalName, 
          f => f.Value)); 

錯誤我收到(這使得課程的意義上):

An item with the same key has already been added. 

預期結果(從示例XML):

a1 => val1 
a2 => val2 
param1 => paramval1 
param2 => paramval2 
... 

我根據@ L.B的建議創建了我自己的。這不是最好的解決方案,但它現在起作用。

public void XMLTODictionary(XElement xmlDetails, ref Dictionary<string, string> dic) 
{ 
    foreach (var node in xmlDetails.Elements()) 
    { 
     if (node.Name.LocalName.Equals("parameter", StringComparison.CurrentCultureIgnoreCase)) 
     { 
       dic.Add(node.Element("ParameterName").Value, node.Element("ParameterValue").Value); 
     } 
     else 
     { 
      dic.Add(node.Name.LocalName, node.Value); 
     } 
    } 
} 
+0

您預期的結果有時使用'name'和某個時候使用'value'這使得它很難處理xml..you首先應該收集所有名稱值對列表中的 – Anirudha

回答

0

如何使用DynamicXml here

dynamic root = DynamicXml.Load("a.xml"); 

Console.WriteLine(root.a1); 
foreach (var p in root.Parameter) 
{ 
    Console.WriteLine("{0}:{1}",p.ParameterName, p.ParameterValue); 
} 
Console.WriteLine(root.Parameter[0].ParameterValue); 

編輯

一個通用的辦法是得到一個字典Dictionary<string,object> 但也存在一些問題,而一個XML轉換字典。例如

<a1>val1</a1> 

dict["a1"]將返回VAL1,但你會這個XML返回

<a1 name="valAttr"><name>valName</name><a1> 

dict["a1"]["name"]valAttr or valName

並考慮你的榜樣,dict["a1"]dict["Parameter"]之間的唯一區別是, 參數同一母公司下存在一次以上,它應該被看作是一個數組,而不是 單個元素。

DynamicXml試圖解決這些問題。當然, 有很大的改進空間,但它應該滿足基本需求。

+0

感謝您的想法。我只是創建了自己的:看看我的OP –

0

除非您提供了唯一的非空值鍵,否則您將無法導入字典結構。一對夫婦的選擇,我能想到的:

  • 進口
  • 中創建一個人工鍵利用ToLookup()擴展方法來代替。這不會返回字典,但可能適合您的需求。給出一個更好的想法,爲什麼你需要一本字典,我可能會有更多的幫助。
+0

我能做到不使用詞典但字典似乎是最有效和最快捷的方法。我總是可以做xmlDetails.Descendants(「Parameter」)..然後再次foreach它來獲取值和節點名稱。我只是認爲必須有一個更簡單,更有效的方法。目的是將此字典分配給類成員,而不是手動創建類成員。例如,object.xml [「key」]更簡單,爲每個參數創建單獨的類成員。 (希望我可以理解) –

0

這裏是一個將數據提取成元組然後輸出字典的方法。請注意,它不檢查重複的密鑰,但可以添加:

string data = @"<?xml version=""1.0"" encoding=""utf-8""?> 
<Root> 
    <a1>val1</a1> 
    <a2>val2</a2> 
    <Parameter> 
    <ParameterName>param1</ParameterName> 
    <ParameterValue>paramval1</ParameterValue> 
    </Parameter> 
    <Parameter> 
    <ParameterName>param2</ParameterName> 
    <ParameterValue>paramval2</ParameterValue> 
    </Parameter> 
</Root>"; 

var elements = XDocument.Parse(data) 
         .Element("Root") 
         .Descendants(); 

var asTupleChildren = elements.Where (e => e.HasElements) 
           .Select (e => new Tuple<string,string>(e.Element("ParameterName").Value, e.Element("ParameterValue").Value)); 

var asTupleElements = elements.Where (e => e.HasElements == false) 
           .Where (e => e.Name != "ParameterName" && e.Name != "ParameterValue") 
           .Select (e => new Tuple<string,string>(e.Name.ToString(), e.Value)); 


var asDictionary = asTupleElements.Concat(asTupleChildren) 
            .ToDictionary (te => te.Item1, te => te.Item2); 


/* asDictionary is a Dictionary<String,String> (4 items) 

a1 val1 
a2 val2 
param1 paramval1 
param2 paramval2 

*/ 
0

只是做了這個,適合我。有點笨重。用它作爲模板。

 public static Dictionary<string, dynamic> RecDis(string ThisXML) 
    { 
     Dictionary<string, dynamic> ThisBlock = new Dictionary<string, dynamic>(); 

     XElement doc = XElement.Parse(ThisXML); 

     XNode[] ThisNoideArray = doc.Nodes().ToArray(); 

     foreach (XNode park in ThisNoideArray) 
     { 
      XElement parker = XElement.Parse(park.ToString()); 

      if (parker.HasElements) 
      { 
       ThisBlock.Add(parker.Name.ToString(), RecDis(parker.ToString())); 
      } 
      else 
      { 
       ThisBlock.Add(parker.Name.ToString(), parker.Value.ToString()); 
      } 
     } 

     return ThisBlock; 
    }