问题描述
我正在使用Windows Phone 8应用程序,
I am working on Windows Phone 8 application,
我有一些看起来像这样的UI:
I have some UI which looks like this :
主要项目A ---具有其desc和子项目列表作为键值
Main Item A --- has its desc and list of subitems as key value
主要项目B ---具有其desc和子项目列表作为键值
Main Item B --- has its desc and list of subitems as key value
主要项目C ---具有其desc和子项目列表作为键值
Main Item C --- has its desc and list of subitems as key value
现在,单击A移至下一页,将显示其说明及其子项.
Now on click of A move to next page which will display its Description and its sub items.
点击主条目A
主要项目A的描述
子项目1 ---单击此显示时其描述子项目2 ---单击此显示时,其说明
sub item 1 --- On click of this display its desc sub item 2 --- On click of this display its desc
这是Xml的样子:
<plist version="1.0">
<dict>
<key>Category</key>
<array>
<dict>
<key>Name</key>
<string>A</string>
<key>Description</key>
<string>Some data</string>
<key>SubItems</key>
<array>
<dict>
<key>Description</key>
<string>Some data</string>
<key>Name</key>
<string>One</string>
</dict>
<dict>
<key>Name</key>
<string>Two</string>
<key>Description</key>
<string>Some data</string>
</dict>
</array>
</dict>
<dict>
<key>Name</key>
<string>B</string>
<key>Description</key>
<string>Some data</string>
<key>SubItems</key>
<array>
<dict>
<key>Description</key>
<string>Some data</string>
<key>Name</key>
<string>One</string>
</dict>
<dict>
<key>Name</key>
<string>Two</string>
<key>Description</key>
<string>Some data</string>
</dict>
</array>
</dict>
如何解析此示例?
更新
我已经这样解决了:
Dictionary<string, List<Tricks>> plistData =
doc.Root.Element("dict").Element("array").Elements("dict")
.Select(GetValues)
.ToDictionary(v => (string)v["Name"],
v => v["SubItems"]
.Elements("dict").Select(Parse).ToList());
static Tricks Parse(XElement dict)
{
var values = GetValues(dict);
return new Tricks
{
SubTitle = (string)values["Name"],
SubTitleDescription = (string)values["Description"]
};
}
static Dictionary<string, XElement> GetValues(XElement dict)
{
return dict.Elements("key")
.ToDictionary(k => (string)k, k => (XElement)k.NextNode);
}
在上面,我可以得到除MainTitle Description之外的所有其他代码,请您帮我改正.
In the above i am able to get everything but except MainTitle Description
, can you please help me to correct it.
推荐答案
您正试图在一个只能容纳两个项目(a的空间)的数据模型中压缩3条信息(名称,描述和子项目列表)键和一个值).
You are trying to squeeze 3 pieces of information (a Name, a Description and a list of subitems) in an datamodel that only has room for two items (a key and a value).
我提供两种解决方案.一种是解决"代码中的问题,另一种是更灵活的解决方案.选一个你喜欢的人
I provide two solutions. One that 'fixes' the problem in your code and one that is a more flexible solution. Pick either one you like
最大的变化是字典不再返回字符串,而是完整的 Tricks
对象.
The biggest change is that the dictionary no longer returns a string but a fullfledge Tricks
object.
public Dictionary<Tricks, List<Tricks>> Clumsy(XDocument doc)
{
var plistData =
doc
.Root
.Element("dict")
.Element("array")
.Elements("dict")
.Select( ele => new
{
key = Parse(ele),
val = ele.Element("array")
.Elements("dict")
.Select(Parse).ToList()
}).ToDictionary(pair => pair.key,
pair => pair.val);
return plistData;
}
static Tricks Parse(XElement dict)
{
var values = GetValues(dict);
return new Tricks
{
SubTitle = (string)values["Name"],
SubTitleDescription = (string)values["Description"]
};
}
static Dictionary<string, XElement> GetValues(XElement dict)
{
return dict.Elements("key")
.ToDictionary(k => (string)k, k => (XElement)k.NextNode);
}
更灵活的解决方案
假设您像MenuRoot类那样冒充,该类包含Menu项目的集合,而这些Menu项目又可以容纳Menu项目的集合,我使用了以下 PlistParser
类来返回上述的类模型./p>
More flexible solution
Assuming you have soming like a MenuRoot class which holds a collection of Menu items that in turn can also hold a collecion of Menu items I used the following PlistParser
class to return th mentioned class model.
public class PListParser
{
public T Deserialize<T>(Stream stream) where T : new()
{
return Deserialize<T>(XDocument.Load(stream));
}
public T Deserialize<T>(string xml) where T:new()
{
return Deserialize<T>(XDocument.Parse(xml));
}
private T Deserialize<T>(XDocument doc) where T : new()
{
return DeserializeObject<T>(
doc.Document.
Element("plist").
Element("dict"));
}
// parse th xml for an object
private T DeserializeObject<T>(XElement dict) where T:new()
{
var obj = new T();
var objType = typeof (T);
// get either propertty names or XmlElement values
var map = GetMapping(objType);
// iterate over the key elements and match them against
// the names of the properties of ther class
foreach (var key in dict.Elements("key"))
{
var pi = map[key.Value];
if (pi != null)
{
// the next node is the value
var value = key.NextNode as XElement;
if (value != null)
{
// what is the type of that value
switch (value.Name.ToString())
{
case "array":
// assume a generic List for arrays
// process subelements
object subitems = InvokeDeserializeArray(
pi.PropertyType.GetGenericArguments()[0],
value);
pi.SetValue(obj, subitems, null);
break;
case "string":
// simple assignment
pi.SetValue(obj, value.Value, null);
break;
case "integer":
int valInt;
if (Int32.TryParse(value.Value, out valInt))
{
pi.SetValue(obj, valInt, null);
}
break;
default:
throw new NotImplementedException(value.Name.ToString());
break;
}
}
else
{
Debug.WriteLine("value null");
}
}
else
{
Debug.WriteLine(key.Value);
}
}
return obj;
}
// map a name to a properyinfo
private static Dictionary<string, PropertyInfo> GetMapping(Type objType)
{
// TODO: Cache..
var map = new Dictionary<string, PropertyInfo>();
// iterate over all properties to find...
foreach (var propertyInfo in objType.GetProperties())
{
// .. if it has an XmlElementAttribute on it
var eleAttr = propertyInfo.GetCustomAttributes(
typeof (XmlElementAttribute), false);
string key;
if (eleAttr.Length == 0)
{
// ... if it doesn't the property name is our key
key = propertyInfo.Name;
}
else
{
// ... if it does the ElementName given the attribute
// is the key.
var attr = (XmlElementAttribute) eleAttr[0];
key = attr.ElementName;
}
map.Add(key, propertyInfo);
}
return map;
}
//http://stackoverflow.com/a/232621/578411
private object InvokeDeserializeArray(Type type, XElement value)
{
MethodInfo method = typeof(PListParser).GetMethod(
"DeserializeArray",
BindingFlags.Instance |
BindingFlags.InvokeMethod |
BindingFlags.NonPublic);
MethodInfo generic = method.MakeGenericMethod(type);
return generic.Invoke(this, new object[] {value});
}
// array handling, returns a list
private List<T> DeserializeArray<T>(XElement array) where T:new()
{
var items = new List<T>();
foreach (var dict in array.Elements("dict"))
{
items.Add(DeserializeObject<T>(dict));
}
return items;
}
}
Classmodel
public class MenuRoot
{
public List<Tricks> Category { get; set; }
}
public class Tricks
{
[XmlElementAttribute("Name")]
public string SubTitle { get; set; }
[XmlElementAttribute("Description")]
public string SubTitleDescription { get; set; }
public List<Tricks> SubItems { get; set; }
}
用法
var parser = new PListParser();
var menu = parser.Deserialize<MenuRoot>(@"c:\my\path\to\the\plist.xml");
这篇关于用相同的键值解析Xml的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!