我正在尝试将XML数据转换为字典。我遇到了相同节点名称的问题。 C#.Net 3.5
示例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 :(得分:0)
除非您提供唯一的,不可为空的密钥,否则您将无法导入到字典结构中。我能想到的几个选项:
答案 1 :(得分: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 或 valName ?
考虑到您的示例,dict["a1"]
和dict["Parameter"]
之间的唯一区别就在于此
参数在同一个父项下不止一次出现,它应该被认为是一个数组而不是一个数组
单个元素。
DynamicXml尝试解决这些问题。当然有 有很大的改进空间,但它应该适合基本需求。
答案 2 :(得分: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
*/
答案 3 :(得分: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;
}