雅美尓(yaml)实战

献给跟我一样对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}=>[1, 2], "c"=>3} node9:   ? {a: 01, b: 02}   : [1, 2]   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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程之旅

2.24

oc中的内存管理机制:使用一种叫做引用计数的机制来管理内存中的对象。OC中每个对象都对应着他的引用计数,引用计数可以理解为一个整数计数器,当使用alloc方法创...

1283
来自专栏Python爱好者

Java基础笔记11

1384
来自专栏CDA数据分析师

深入解读Python解析XML的几种方式

本文将介绍深入解读利用Python语言解析XML文件的几种方式,并以笔者推荐使用的ElementTree模块为例,演示具体使用方法和场景。文中所使用的Pytho...

2937
来自专栏企鹅号快讯

如何深入 Python 虚拟机追查 HTTP 服务 core dump 导致 502 的问题

作者 今日头条技术团队 概述 今日头条目前大部分 Python 的 HTTP 服务都是用 uWSGI 托管 Python 多进程的 Django 或者 Fla...

2127
来自专栏全沾开发(huā)

EJS[0]-如何使用EJS

EJS[0]-如何使用EJS 最近做的一个新项目,所以想着换一个新的模版引擎尝试一下。(之前我们一直在使用handlebars) ...

3868
来自专栏小特工作室

基于Lodop控件的Web打印示例(含源码)

      最近项目组的打印控件有所改变,已经换成Lodop控件,使用以后发现,功能确实非常强大.可以打印Web页面内某个控件的内容.下面,还是通过一个实例来说...

2738
来自专栏企鹅号快讯

NPM酷库:vm2,安全的沙箱环境

NPM酷库,每天两分钟,了解一个流行NPM库。 今天我们要了解的库是 vm2,这是一个Node.js 官方 vm 库的替代品,主要解决了安全问题。 不安全的vm...

3265
来自专栏落影的专栏

研读《程序员的自我修养—链接、装载与库》

前言 《编译与链接过程的思考》 《静态库与动态库的思考》 在写完上面两篇思考之后,仔细研读《程序员的自我修养—链接、装载与库》,对编译、链接、装载、静态库和...

4507
来自专栏企鹅号快讯

培养这10个习惯,你就离UNIX高手更进一步了

来自:IBM developerWorks 链接:https://www.ibm.com/developerworks/cn/aix/library/au-un...

2046
来自专栏云计算教程系列

如何在Ubuntu 16.04上设置Jupyter Notebook以运行IPython

IPython是Python的交互式命令行界面。Jupyter Notebook提供了多种语言的交互式Web界面,包括IPython。

5874

扫码关注云+社区

领取腾讯云代金券