在WP7中解析iOS .plist文件

问题描述:

我正在将iOS应用程序转换为WP7。我想要做的就是使用我为我的WP7应用中的iOS应用创建的plist文件,而无需对其进行任何更改。我尝试使用这里的库http://codetitans.codeplex.com/,但我只能解析一个级别,我的plist有多个级别。下面是例子plist文件,我试图解析的:在WP7中解析iOS .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

你需要这些部分还是只需要嵌套的名称/值对? – 2012-02-08 21:22:12

第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); 

其实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结构格式为动态时枚举内容)。