Parse nested YAML config

if you have a complex config schema, you may need to store it in a YAML or JSON format

having been used to .INI style configs, I recently had to store nested values and INI style gets very complex, very fast.

For instance in YAML:

--- person: Joe: age: 32 children: - Katie - Frank Bob: age: 43 children: - Lisa

to get the names of Joe’s children, in JSON or YAML would look something like this,

data['person']['Joe']['children'] ['Katie','Frank']

in INI, this would be something like,

[person] [person/joe] age=32 children=Katie,Frank

This is really ugly and not nested visually. To get an individual child’s name, you would need to additionally parse a comma separated string. Fugly.

Much better to use YAML. I prefer YAML over JSON because its much easier for human readability, although the language interpreter converts YAML into JSON during run-time

Heres a Python and Ruby example on how to parse this sample Config file

config.yaml

--- scanners: hostname: web01.nyc.mycorp.com: port: 9900 scans: - "cisco scan" - "network sec scan" - "windows sec scan" web05.tex.mycorp.com: port: 9923 scans: - "tex network" - "infra scan"

The Py and Rb parser scripts are structurally very similar,

Python

#!/usr/bin/env python# -*- coding: utf-8 -*-import yamldef get_config(*args): with open('config.yaml', 'r') as f: conf = yaml.load(f) # get section section = args[0] # check if Config file has Section if not conf.has_key(section): print "key missing" quit() # get values argList = list(args) # convert tuple to list argList.pop(0) # remove Section from list # create lookup path parsepath = "conf['" + section + "']" for arg in argList: parsepath = parsepath + "['" + arg + "']" return eval(parsepath) f.close()scans = get_config('scanners','hostname','web01.nyc.mycorp.com','scans')print scans

['cisco scan', 'network sec scan', 'windows sec scan']

or if you want a list of all hostnames,

scans = list(get_config('scanners','hostname'))

['web01.nyc.mycorp.com', 'web05.tex.mycorp.com']

or a simple one liner

for key, value in yaml.load(open('config.yaml'))['scanners']['hostname'].iteritems(): print key, value

web01.nyc.mycorp.com {'port': 9900, 'scans': ['cisco scan', 'network sec scan', 'windows sec scan']}web05.tex.mycorp.com {'port': 9923, 'scans': ['tex network', 'infra scan']}