Parsing plist file

Hello

I’m trying to access data that are in a .plist file which has the content :

<array>
<dict>
<key>AKey</key>
Value1
<key>AnotherKey</key>
Value2
<key>YetAnother</key>
Value3
…
</dict>
…
</array>

Where value can be different things :

<string>aString</string>
<integer>anInteger</integer>
<false/> or <true/>
<array> <dict>….</dict></array>

I’m sofar working on the playground

import PlaygroundSupport
let path = playgroundSharedDataDirectory.appendingPathComponent("input.pfile")
nsArray = try NSArray(contentsOf: path, error: ())

brings the Data in a array. So far so good

var item0 = nsArray![0]

gives me the content of 1rst item of the array. Looks like a dictionary

//(key "AKey", value Value1)
//…

But I can’t find how to handle item0. It is said to be of type __NSDictionaryM

let t = type(of: item0)
// __C.__NSDictionaryM.Type

But can’t be accessed by

var test = item0["AKey"]
//error: Value of type 'Any' has no subscripts

Tried Type casting to no avail. So I’m stucked

with plist file

<?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">
<array>
	<dict>
		<key>AKey</key>
		<string>Value1</string>
		<key>AnotherKey</key>
		<string>Value2</string>
	</dict>
</array>
</plist>

this code works for me

import Foundation
import PlaygroundSupport

let path = playgroundSharedDataDirectory.appendingPathComponent("input.plist")
let nsArray = try NSArray(contentsOf: path, error: ())
var item0 = nsArray[0]
var test = (item0 as! NSDictionary)["AKey"]
print(test)

The only thing I added except fixing the code you posted is type casting to NSDictionary

P.S. don't use as! in a real project, it's better to gracefully handle the errors

1 Like

Thanks !!!

My mistake was trying to coerce type into a Dictionary, and not to a NSDictionary, getting cryptic error message.
I still have a lot to learn before handling gracefully errors...

FYI, it is probably more elegant to parse the property list using PropertyListDecoder. Look up the documentation for Codable for more information on how to do it.

1 Like

I figured so also, but since my .pfile has irregularities (no same keys, arrays in value,...) I needed to fix first my type casting errors, before assimilating PropertyListDecoder.
Thanks for confirming the hint.

You can still use Codable in these cases, but you'll need to do some more custom handling compared to just writing types. If you can share a full sample plist, we can step through the necessary code. The end result will probably be cleaner than messing around with NS-typecasting stuff.

Actually, I am trying to clean up my Mail.app rules that are now a 5500 lines file with all the mail adresses I want to direct to specific mail boxes, that have been accumulated for a decade or two. So the plist file is the syncedRules.plist that can be found in Library/Mail/V7/SyncedRules.plist.
It's an array of rules, each rule being a dict of keys, with one being for criteria used, itself being a array of conditions, each condition a dictionary where you can find domain names. The (sofar) vague idea is to identify which domain names conditions are redundants (can be performed automatically), and maybe also obsolete (with a manual glance).
The objective is to accelerate the everyday filtering, but also to make my first real swift program :)