我正在将iOS应用转换为WP7。我想要做的是使用我在WP7应用程序中为iOS应用程序创建的plist文件,而不对其进行任何更改。我尝试使用这里的库http://codetitans.codeplex.com/,但我只能解析一个级别,我的plist有多个级别。这是我正在尝试解析的plist文件的示例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>section0</key>
<dict>
<key>key0</key>
<dict>
<key>name</key>
<string>Title</string>
<key>type</key>
<string>text</string>
<key>filter</key>
<false/>
</dict>
<key>key1</key>
<dict>
<key>name</key>
<string>Season</string>
<key>type</key>
<string>text</string>
<key>filter</key>
<false/>
</dict>
</dict>
</dict>
答案 0 :(得分:4)
第1部分:您要求的内容
WP目前对动态类型没有很好的支持,所以解析它并不困难,消耗它会很难看。
该类将使用LINQ to XML解析PList:
public class PropertyListParser
{
public IDictionary<String, Object> Parse(string plistXml)
{
return Parse(XDocument.Parse(plistXml));
}
public IDictionary<String, Object> Parse(XDocument document)
{
return ParseDictionary(document.Root.Elements("plist")
.Elements("dict")
.First());
}
private IDictionary<String, Object> ParseDictionary(XElement dictElement)
{
return dictElement
.Elements("key")
.ToDictionary(
el => el.Value,
el => ParseValue(el.ElementsAfterSelf("*").FirstOrDefault())
);
}
private object ParseValue(XElement element)
{
if (element == null)
{
return null;
}
string valueType = element.Name.LocalName;
switch (valueType)
{
case "string":
return element.Value;
case "dict":
return ParseDictionary(element);
case "true":
return true;
case "false":
return false;
default:
throw new NotSupportedException("Plist element not supported: " + valueType);
}
}
}
以下是如何使用它的示例(基于您的示例):
var parsedPlist = new PlistParser().Parse(Plist);
var section0 = (IDictionary<string, object>)parsedPlist["section0"];
var key0 = (IDictionary<string, object>)parsedPlist["key0"];
string type = (string)key0["type"];
bool filter = (bool)key0["filter"];
第2部分:您可能需要的内容
话虽如此,实际上编写以这种方式使用它的代码会非常难看。根据您的架构,我会说以下实际上是您的应用程序所需要的。
// I'm not sure what your domain object is, so please rename this
public class ConfigEntry
{
public string Name { get; set; }
public string Type { get; set; }
public bool Filter { get; set; }
}
public class ConfigEntryLoader
{
private PropertyListParser plistParser;
public ConfigEntryLoader()
{
plistParser = new PropertyListParser();
}
public ICollection<ConfigEntry> LoadEntriesFromPlist(string plistXml)
{
var parsedPlist = plistParser.Parse(plistXml);
var section0 = (IDictionary<string, object>)parsedPlist["section0"];
return section0.Values
.Cast<IDictionary<string,object>>()
.Select(CreateEntry)
.ToList();
}
private ConfigEntry CreateEntry(IDictionary<string, object> entryDict)
{
// Accessing missing keys in a dictionary throws an exception,
// so if they are optional you should check if they exist using ContainsKey
return new ConfigEntry
{
Name = (string)entryDict["name"],
Type = (string)entryDict["type"],
Filter = (bool)entryDict["filter"]
};
}
}
现在,当您使用ConfigEntryLoader
时,您将获得一个ConfigEntry对象列表,这将使您的代码更容易维护,以便传递字典。
ICollection<ConfigEntry> configEntries = new ConfigEntryLoader()
.LoadEntriesFromPlist(plistXml);
答案 1 :(得分:1)
实际上CodeTitans Libraries解析所有级别。 这是我今天添加的单元测试,其中显示了您实际可以访问嵌套项目的方式:
[TestMethod]
public void LoadMultilevelItems()
{
var input = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
<plist version=""1.0"">
<dict>
<key>section0</key>
<dict>
<key>key0</key>
<dict>
<key>name</key>
<string>Title</string>
<key>type</key>
<string>text</string>
<key>filter</key>
<false/>
</dict>
<key>key1</key>
<dict>
<key>name</key>
<string>Season</string>
<key>type</key>
<string>text</string>
<key>filter</key>
<false/>
</dict>
</dict>
</dict>
</plist>";
var data = PropertyList.Read(input);
Assert.IsNotNull(data);
Assert.IsTrue(data.Contains("section0"));
var section0 = data["section0"];
Assert.IsNotNull(section0);
Assert.IsTrue(section0.Contains("key0"));
var key0 = section0["key0"];
Assert.IsNotNull(key0);
Assert.AreEqual("Title", key0["name"].StringValue);
Assert.AreEqual("text", key0["type"].StringValue);
Assert.IsFalse(key0["filter"].BooleanValue);
key0.Add("filter", true);
}
默认情况下,所有项目都可以使用括号访问“词典”或“数组”。 当您下到该值时,只需使用专用属性'StringValue'或'BooleanValue',以避免在您自己的代码中进行类型转换。
还有更多的支持属性,例如:Type(允许您检查项目的本机plist类型)或ArrayItems和DictionaryItems(如果plist结构格式是动态的,则允许您枚举内容)。