2012-12-06 82 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; 
    }