我正在使用Windows Phone 8应用程序,
我有一些看起来像这样的用户界面:
主要项目A ---将其desc和子项列表作为键值
主要项目B ---将其desc和子项列表作为键值
主要项目C ---将其desc和子项列表作为键值
现在单击A移动到下一页,将显示其描述及其子项。
点击主要项目A
主要项目A的描述
子项1 ---点击此显示其desc 子项目2 ---点击此显示其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);
}
在上面我能够得到除except MainTitle Description
之外的所有内容,你能不能帮我纠正一下。
答案 0 :(得分:1)
您正试图在数据模型中压缩3条信息(名称,描述和子项目列表),该数据模型只有两个项目(一个键和一个值)的空间。
我提供两种解决方案。一个“修复”代码中的问题,另一个是更灵活的解决方案。选择你喜欢的任何一个
最大的变化是字典不再返回字符串而是返回一个完整的Tricks
对象。
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项目,我使用下面的PlistParser
类来返回上面提到的类模型。
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;
}
}
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");