献给跟我一样对yaml(雅美尓)有婶婶挫败感的同学!

开始第一个pylon工程,我们就跟yaml配置文件开始了不解之缘。yaml是什么?它有哪些规则?

大IBM的文章如是说:YAML 是一种比 XML 更为简单易读的序列化语言。Structure通过空格来展示,Sequence里的项用"-"来代表,Map里的键值对用":"分隔. 这几乎就是所有的语法了.

真的是这样简单吗?发布上线项目rigger却告诉我们mysql host没配置,配好再上线发现DOMAIN_PREFIX没配置,更一头雾水的是yaml里的各种符号"  ! &  * <<  ",看不懂,只能小心翼翼如履薄冰Ctrl+c , Ctrl+v,Ctrl+c , Ctrl+v ....

本文试图让你完全理解如下配置sample.yaml,并能通过一个小程序解析这个配置。需要大家动手跑一跑python程序,10分钟后,就再也不怕yaml的BT标记了。

5分钟workshop

sample.yaml:

reusable:
        - !R.vars  &common_setting
                REDIS_PORT:   16379
                BETA_REDIS:   6  
                ONLINE_REDIS: 7
                GIT_PATH:     "/usr/local/bin/git"
                PHP_ERROR:    "E_ERROR"
                SDK_PATH:     "/home/q/php/plato_sdk/"
                CONFSVC_URL:  "plato.svc.1360.com"
                XHPROF:       "OFF"
 
        - !R.vars  &sdk_deploy
                pkg     : "pkg"
                name    : "plato_sdk"
                root    : "./sdk" 
__env:
        cache:                 !R.env
            res:
                - !R.vars
                    API_PROXY: "http://127.0.0.1:8086"
        debug:                 !R.vars  &debug_support
            PHP_ERROR:         "E_ALL & ~E_NOTICE"
            DEBUG:             "ON"
            PYL_LOG_MODE:      "DEBUG" 
        dev:                   !R.env
            res:
                - !R.using
                    refs:
                        - *common_setting
                        - *debug_support
                - !R.vars
                    ENV:           "dev"
                    DOMAIN_PREFIX: "${USER}."
beta_sdk: !P.publish
        <<: *sdk_deploy
        host: "127.0.0.1"

现在看到了这样一个文件,怎么读懂它?处理它?

基本语法:

- 列表
: 哈希对
& 表示一个"锚点标记",其它节点可以使用"*""<<: *"来引用它的值
* 引用,指node4的内容与node3完全一致
<<: * 的作用,指node5的内容包含但不完全相同于node3的值。
!  tag标记,可以注册自己指定的类型

语法知道了,怎么解析?下面来一个简单易懂小例子, 为了省事儿,yaml.add_multi_constructor(u"!R.env", construct_object) 用map指代 !R.xxx 代表的自定义类

yaml_simple.py :

import sys
import yaml
from yaml import load, dump
def construct_object(loader, suffix, node):
    return loader.construct_yaml_map(node)
 
yaml.add_multi_constructor(u"!R.env", construct_object)
yaml.add_multi_constructor(u"!P.publish", construct_object)
yaml.add_multi_constructor(u"!R.using", construct_object)
yaml.add_multi_constructor(u"!P.pkg", construct_object)
yaml.add_multi_constructor(u"!R.vars", construct_object)
 
 
txt  = file("sample.yaml").read()
data = load(txt)
print data   
print data['__env']['dev']['res'][0]['refs'][0]['SDK_PATH']

找台测试服务器,把两个文件放上去,命令行执行:python yaml_simple.py

输出:

{'beta_sdk': {'host''127.0.0.1''root''./sdk''pkg''pkg''name''plato_sdk'}, '__env': {'debug': {'DEBUG''ON''PHP_ERROR''E_ALL & ~E_NOTICE''PYL_LOG_MODE''DEBUG'}, 'cache': {'res': [{'API_PROXY''http://127.0.0.1:8086'}]}, 'dev': {'res': [{'refs': [{'SDK_PATH''/home/q/php/plato_sdk/''ONLINE_REDIS'7'BETA_REDIS'6'GIT_PATH''/usr/local/bin/git''CONFSVC_URL''plato.svc.1360.com''PHP_ERROR''E_ERROR''REDIS_PORT'16379'XHPROF''OFF'}, {'DEBUG''ON''PHP_ERROR''E_ALL & ~E_NOTICE''PYL_LOG_MODE''DEBUG'}]}, {'DOMAIN_PREFIX''${USER}.''ENV''dev'}]}}, 'reusable': [{'SDK_PATH''/home/q/php/plato_sdk/''ONLINE_REDIS'7'BETA_REDIS'6'GIT_PATH''/usr/local/bin/git''CONFSVC_URL''plato.svc.1360.com''PHP_ERROR''E_ERROR''REDIS_PORT'16379'XHPROF''OFF'}, {'root''./sdk''pkg''pkg''name''plato_sdk'}]}
/home/q/php/plato_sdk/

5分钟进阶

YAML(IPA: /ˈjæməl/,尾音类似camel骆驼)是一个可读性高,用来表达资料序列的格式。

YAML是"YAML Ain't a Markup Language"(YAML不是一种置标语言)的递回缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种置标语言),但为了强调这种语言以数据做为中心,而不是以置标语言为重点,而用返璞词重新命名。

以下为可能用到的各种符号的解释和示例:

---
#
# > 的作用,以缩进对齐来判断是否为一段文字,也就是说,一旦缩进与上一行不一致,则认为是一个新行。
# node1的例子中,第一行"Ther... door"
#                第二行"  "Please... floor""
#                第三行"So...So2"
node1: >
  Ther once was a man from Darjeeling
  Who got on a bus bound for Ealing
  It said on the door
    "Please don't spit on the floor"
  So he carefully spat on the ceiling
  So2
# | 的作用,它表示之后的文字,每一行均为一个新行。
node2: |
  Ther once was a man from Darjeeling
  Who got on a bus bound for Ealing
  It said on the door
  "Please don't spit on the floor"
  So he carefully spat on the ceiling
# & 的作用,它表示一个"锚点标记",其它节点可以使用"*""<<: *"来引用它的值
node3: &node3
  a: 001
  b: 002
# * 的作用,指node4的内容与node3完全一致
node4:
  *node3
   
# <<: * 的作用,指node5的内容包含但不完全相同于node3的值。
node5:
  <<: *node3
  c: 003
# !! 的作用,强迫转换类型。
#输出:
#{"node6"=>{
#    "a"=>#<YAML::PrivateType:0x9df6d40 @value="123"@type_id="float">,
#    "b"=>#<YAML::PrivateType:0x9df6ae8 @value="true"@type_id="str">,
#    "c"=>true
#}
#注意:c的值为布尔型。
node6:
  a: !!float 123
  b: !!str true
  c: True
# 二进制内容的表示
node7: !!binary |
  xxxxxxxxxxxxx
  xxxxxxxxx
  xxxxx
node8_value: &node8_value {id: 10000, code: item_manager, name: 项目经理}
#自定解析类型,YAML某Key的Value一般为Array或Hash,但如果需要将Value解析为其它的自定义类型,可以使用该方法。
#步骤:
1、首先定义 MyCustClass 类,如:
#    class MyCustClass
#      attr_accessor :id
#      attr_accessor :code
#      def initialize v_hash
#        @id = v_hash["id"]
#        @code = v_hash["code"]
#      end
#    end
2、向YAML注册解释类型,如:
#  YAML::add_domain_type("yaml.org,2002"'MyCustClass'do |type, val|
#    MyCustClass.new(val)
#  end
3、OK,当YAML文件加载时,YAML将自动将"node8"的值解析为MyCustClass类型。
4、测试一下,x["node8"] >> #<MyCustClass:0x9df1c88 @code="item_manager"@id=10000>
#              x["node8"].code >> "item_manager"
node8: !MyCustClass
  <<: *node8_value
# ? 的作用,用来明确的表示多个词汇组成的键值
# a["node9"] => {{"a"=>1"b"=>2}=>[12], "c"=>3}
node9:
  ? {a: 01, b: 02}
  : [12]
  c: 3

want more?

有兴趣的同学可以进一步了解rigger源码,会发现诸如!P.publish、!R.using,其实都是写的一个python类,会有自定义的属性,所以某些属性未定义,就会报错了。更有兴趣的可以把 yaml_simple.py  扩展为小工具,结合rigger,随时检查自己的配置文件是否有错误。

推荐yaml在线验证工具 https://yaml-online-parser.appspot.com/  可以提前发现格式问题,but 要FQ,FQ设置见附录。

yaml提示不够友好,对齐错误有可能提示为“yaml.parser.ParserError: while parsing a block mapping“  ” expected <block end>, but found '<block mapping start>'   需要小心注意

总结

为什么不是XML呢?因为:

  • YAML的可读性好。
  • YAML和脚本语言的交互性好。
  • YAML使用实现语言的数据类型。
  • YAML有一个一致的信息模型。
  • YAML易于实现。

上面5条也就是XML不足的地方。同时,YAML也有XML的下列优点:

  • YAML可以基于流来处理;
  • YAML表达能力强,扩展性好。

总之,YAML试图用一种比XML更敏捷的方式,来完成XML所完成的任务。当然简单的工具用深入之后就成了开篇那种样子,门槛有点高,但也体现深入研究一个小玩意的有趣之处。

参考文章:

http://zh.wikipedia.org/wiki/YAML

http://www.ibm.com/developerworks/cn/xml/x-cn-yamlintro/

http://www.yaml.org/spec/1.2/spec.html

http://pyyaml.org/wiki/PyYAMLDocumentation

http://sqycyl.iteye.com/blog/859589

雅美尓(yaml)实战的更多相关文章

  1. 《1Q84》--[日]村上春树

    <1Q84>,作者是:村上春树(村长) 故事梗概: 1984年,青豆与天吾皆为30岁,青豆为健身教练但另一面则是暗杀者,将受到极度暴力 的妇女们的丈夫们送至死亡的世界.天吾的职业为升大学的 ...

  2. 解决Javascript大数据列表引起的网页加载慢/卡死问题。

    在一些网页应用中,有时会碰到一个超级巨大的列表,成千上万行,这时大部份浏览器解析起来就非常痛苦了(有可能直接卡死). 也许你们会说可以分页或动态加载啊?但是有可能需求不允许分页,动态加载?网络的延迟也 ...

  3. Disjoint Sets

    Disjoint Sets Disjoint Sets的意思是一堆集合們,它們相互之間都沒有交集.沒有交集是指:各個集合之間沒有擁有共同.相同的元素.中文稱作「分離集」. Disjoint Sets的 ...

  4. 线程进阶:多任务处理(17)——Java中的锁(Unsafe基础)

    在网络层,互联网提供所有应用程序都要使用的两种类型的服务,尽管目前理解这些服务的细节并不重要,但在所有TCP/IP概述中,都不能忽略他们: 无连接分组交付服务(Connectionless Packe ...

  5. Python识别璇玑图中诗的数量

    一.璇玑图简介 璇玑图的读法有很多,这里我使用七七棋盘格的读法,在璇玑图中分离出一个七七棋盘格,如下表 吏 官 同 流 污 合 玩 痞 悍 蒙 骗 造 假 蛋 鸡 宴 请 客 友 朋 远 戚 偏 正 ...

  6. 利用Javascript解决HTML大数据列表引起的网页加载慢/卡死问题。

    在一些网页应用中,有时会碰到一个超级巨大的列表,成千上万行,这时大部份浏览器解析起来就非常痛苦了(有可能直接卡死). 也许你们会说可以分页或动态加载啊?但是有可能需求不允许分页,动态加载?网络的延迟也 ...

  7. Java开发者职业生涯要看的200+本书

    作者:老刘链接:https://www.zhihu.com/question/29581524/answer/684872838来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  8. 最强 Java 书单推荐,附学习方法

    技术大佬用1w+字来告诉你该读什么书,循序渐进,并提供百度云盘下载地址.重要的是还有学习方法. 请肆无忌惮地点赞吧,微信搜索[沉默王二]关注这个在九朝古都洛阳苟且偷生的程序员.本文 GitHub gi ...

  9. 本溪6397.7539(薇)xiaojie:本溪哪里有xiaomei

    本溪哪里有小姐服务大保健[微信:6397.7539倩儿小妹[本溪叫小姐服务√o服务微信:6397.7539倩儿小妹[本溪叫小姐服务][十微信:6397.7539倩儿小妹][本溪叫小姐包夜服务][十微信 ...

随机推荐

  1. 关于AngularJs,数据绑定与自定义验证

    最近开始着手学起了Angular,抱着好奇的心情开始研究了起来.忽然发现angular可以巧妙而方便的进行数据的绑定验证啊什么的.(当然,我只是刚开始学,所有可能有更强大的功能,只是我还没有看到) 那 ...

  2. Unity四元数小问题整理

    1.Unity中,四元数不能保存超过360度的旋转,所以如此大范围的旋转不能直接两个四元数做插值(当你用0度和721度的四元数做插值,它只会转1度,而不会转两圈). 2.要把旋转设置成某个方向,用Lo ...

  3. Android卸载程序之后跳转到指定的反馈页面

    一个应用被用户卸载肯定是有理由的,而开发者却未必能得知这一重要的理由,毕竟用户很少会主动反馈建议,多半就是用得不爽就卸,如果能在被卸载后获取到用户的一些反馈,那对开发者进一步改进应用是非常有利的.目前 ...

  4. Android多媒体--MediaCodec 中文API文档

    *由于工作需要,需要利用MediaCodec实现Playback及Transcode等功能,故在学习过程中翻译了Google官方的MediaCodec API文档,由于作者水平限制,文中难免有错误和不 ...

  5. 一篇说尽Excel常见函数用法

    一篇说尽Excel常见函数用法 Word,PPT,Excel这三个Office软件是职场办公里最常用的三个软件,但是我发现简书上写PPT的教程多,Excel的少,即使有,也是零零散散.因为Excel的 ...

  6. angularJS: shop chart

    <!DOCTYPE html> <html ng-app="app">   <head>     <meta charset=" ...

  7. 「 JavaScript 篇 」

    一.JavaScript 里有哪些数据类型,解释清楚 null 和 undefined,解释清楚原始数据类型和引用数据类型.比如讲一下 1 和 Number(1)的区别js中有5种数据类型:Undef ...

  8. 写在OpenFire

    首先,确保你已经关掉了openfire打开终端 (在应用程序-->实用工具-->)输入以下命令sudo rm -rf /Library/PreferencePanes/Openfire.p ...

  9. C# 只移除最后一个字符

    string str = "|||"; Console.WriteLine(str.Substring(0, str.Length - 1)); Console.WriteLine ...

  10. 将JSON对象带有格式的写出到文件中

    需求:将一个JSON对象写出到文件中,要求文件中的JSON数据带有简单的格式.代码的实现参考了Java算法中的栈处理括号匹配问题.好了,不多说了,下面是代码的实现. 代码: package gemu. ...