zoukankan      html  css  js  c++  java
  • 雅美尓(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}=>[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 要翻墙,翻墙设置见附录。

    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

  • 相关阅读:
    PHP is_numeric 检测变量是否为数字或数字字符串
    CSS texttransform实现首个或全部字母大写或小写
    To be a true man
    前辈的话
    做好你自己
    PHP mysql_real_escape_string() 函数
    这些事,我们早就该知道……
    Win7 如何更改用户名
    js或css文件后面跟参数的原因说明
    网页优化插件 YSlow
  • 原文地址:https://www.cnblogs.com/shenguanpu/p/5378450.html
Copyright © 2011-2022 走看看