博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
YAML
阅读量:5927 次
发布时间:2019-06-19

本文共 5934 字,大约阅读时间需要 19 分钟。

YAML 简介及其与 XML 的不同之处

自从有了递归定义,大家都爱上了这种起名方式,YAML 也是。YAML 的定义是:“YAML Ain ’ t a Markup Language”,即:YAML 不是一种标记语言的递归缩写。要问 YAML 到底是不是一种标记语言呢?答案:是的。有意思的是:在 YAML 开发的早期,YAML 其实参考了许多其他语言,如 XML, SDL 及电子邮件格式等等,并最终把自己定义为:“Yet Another Markup Language”。既然明明是标记语言,为什么后来又改名换姓,非说自己不是标记语言了呢?其实名字的更换正是为了强调 YAML 的与众不同:YAML 是以数据为设计语言的重点的,而不是像 XML 以标记为重点。实事上,正是因为这样一种设计理念使得 YAML 在后来的不少应用中取代 XML,成为一种可读性高,易于表达数据序列的编程语言。

YAML 的数据组织主要依靠的是空白,缩进,分行等结构。这使得 YAML 语言很容易上手。我们就以 YAML 官方网站上给出的一个例子来看看 YAML 文件的书写(如清单 1 所示)。相信熟悉 XML 的人都会感受到 YAML 是多么的简洁明了!

YAML 的语法十分简单:用“-”来表示一些序列的项(Sequence),如清单 1 里的产品(product)有两样东西(Basketball 和 Super Hoop)组织为一个序列;用“:”来表示一对项目(Map)里的栏目(Key)和其相应的值(Value),比如清单 1 发票里的时间(date)的值是 2001-01-23,这就是一个 Map。这些就是 YAML 里最重要的语法了。如果想知道其他语法的细节可以参看 YAML 官方网页里的参考卡片(reference card):


清单 1. 用 YAML 表达的一个购物发票

--- !clarkevans.com/^invoice  invoice: 34843  date : 2001-01-23  bill-to: &id001   given : Chris   family : Dumars   address:   lines: |   458 Walkman Dr.   Suite #292   city : Royal Oak   state : MI   postal : 48046  ship-to: *id001  product:   - sku : BL394D   quantity : 4   description : Basketball   price : 450.00   - sku : BL4438H   quantity : 1   description : Super Hoop   price : 2392.00  tax : 251.42  total: 4443.52  comments: >   Late afternoon is best.   Backup contact is Nancy   Billsmer @ 338-4338.

 

正因为 YAML 的语法和组织结构简单巧妙,YAML 很容易就可以插入另一个 YAML 文件,甚至其他类型的文件,包括 XML, SDL, JSON 等。相反,如果要在 XML 里插入 YAML,相信了解 XML 的朋友都知道,那是要加很多符号(Potential Sigils)才能完成。

通过上面的举例,我们可以看出,YAML 较 XML 而言可读性更好,也更易于实现。但 YAML 的优点远不止于此。当 YAML 诞生不久的时候,其应用还只在动态编程语言如 Perl,Python, Ruby,及当时还应用得不算广泛的 java 编程中。而现如今 YAML 的支持库已包括 C/C++,C#/.NET,PHP 等。可以说,几乎在如今流行的编程语言中,YAML 已经无处不在。

事实上,纵观程序语言的发展,从 C 到 C++,Java,再到动态脚本语言 Perl,Python,PHP, 直到如今相当之流行的 Ruby,人们越来越摈弃那些规则复杂,语法深奥的语言,取而代之的则是灵活简单,易读易写的,越来越趋近人类阅读书写习惯的程序语言。在数据的序列化上,这种趋势其实是一样的。YAML 作为可以和 XML 一样扩展性强,表达力强且基于流操作的语言,凭借着自身在可读性,易实现,与脚本语言易交互,于宿主语言的数据结构类型易使用等各方面优势,在数据序列化格式领域正成为越来越为人们喜爱的一种语言。

本文的后续两个章节将从开发应用和配置文件两个方面以及 C++ 和 Ruby 这两种语言的角度,以实例介绍 YAML 的使用方法和优越之处。

 

YAML 在开发应用中的使用及实例(C++)

我们还以清单 1 里的发票数据为例。假如你有一个 C++ 开发的应用,其中的发票数据需要用一种语言来做序列化。选择 YAML,我们现在就把发票信息数据用 YAML 写在一个文件里的(具体请参考附件里的 invoice.yaml),然后下载并安装 yaml-cpp 库文件包,详细的方法和步骤可以参考 yaml-cpp 的官方网址上的说明:。接着我们就可以开始设计相应的 C++ 代码里的数据结构了。具体定义可以参看下面的清单 2.


清单 2. 发票数据在 C++ 中的数据结构表示

struct Product {   std::string sku;   int quantity;   std::string description;   float price;  };  struct Address {   std::string lines;   std::string city;   std::string state;   int postal;  };  struct Bill {   std::string given;   std::string family;   Address address;  };  struct Invoice {   int invoice;   std::string date;   Bill bill;   std::vector 
products; float tax; float total; std::string comments; };

 

虽然 C++ 在标准模板库(STL)里有 Map,List 等与 YAML 相对应的数据类型,但是本例中为了更清晰看出 YAML 的用法,只简单构建了一些结构体与之对应。(从另一角度说,如果 YAML 用在像 Ruby 一样的脚本语言中,那么数据类型的对应将更加简单。在下一节的内容中将给出相关的实例。)另外,在 C++ 里,为了能够使用操作符“>>”(stream extraction operator)帮组我们完成 YAML 数据和 C++ 数据之间的赋值,我们需要对该操作符进行重载(overload)。具体实现可参考清单 3。


清单 3. 重载运算符“>>”

void operator >> (const YAML::Node& node, Product& p) {   node["sku"] >> p.sku;   node["quantity"] >> p.quantity;   node["description"] >> p.description;   node["price"] >> p.price;  }  void operator >> (const YAML::Node& node, Address& a) {   node["lines"] >> a.lines;   node["city"] >> a.city;   node["state"] >> a.state;   node["postal"] >> a.postal;  }  void operator >> (const YAML::Node& node, Bill& b) {   node["given"] >> b.given;   node["family"] >> b.family;   node["address"] >> b.address;  }  void operator >> (const YAML::Node& node, Invoice& invoice) {   node["invoice"] >> invoice.invoice;   node["date"] >> invoice.date;   node["bill-to"] >> invoice.bill;   const YAML::Node& products = node["product"];   for(unsigned i=0;i
> p; invoice.products.push_back(p); } node["tax"] >> invoice.tax; node["total"] >> invoice.total; node["comments"] >> invoice.comments; }

 

在对 Product 的实现中,这里使用了 C++ 标准模板库里的 vector 容器以完成对多个 product 的赋值。

有了数据结构,有了“>>”,那么当我们需要使用 YAML 数据的时候,只需读入 YAML 文件,交给 YAML 库的解析器(Parser)便高枕无忧了。相应的代码示例请参看清单 4。


清单 4. 解析 YAML 数据

std::ifstream fin("invoice.yaml");  YAML::Parser parser(fin);  YAML::Node doc;  parser.GetNextDocument(doc);  Invoice invoice;  doc >> invoice;

 

完整的代码示例请参考附件里的“invoice.cpp”和“invoice.yaml”。对于例子中的数据结构和方法,读者也可以构建更加完美的实现,这里仅是一简单示例。

 

YAML 在配置文件中的使用及实例(Ruby)

假设你在开发一个分布式系统,系统中有不同的节点(node)。那么配置文件里需要写明各种不同角色的节点各自的配置信息。如果你打算用 Ruby 语言来解析这种配置文件,那么用 YAML 来书写配置文件一定是你的不二选择。其实不仅仅是 Ruby,YAML 对于几乎所有的脚本语言来说,它的解析都比 XML 来得容易得多。

Ruby 有着丰富灵活的数据结构,这使得 YAML 加 Ruby 的组合仿佛天生一对。比如:YAML 里的序列(Sequence)对应 Ruby 里的数组(Array);YAML 的一对项(Map)对应着 Ruby 里的 Hash 等等。详细的对应关系可见:。

假设我们的配置文件如清单 5 所示。


清单 5. 配置文件示例

#  # Config file example  #  node_a:   conntimeout: 300   external:   iface: eth0   port: 556   internal:   iface: eth0  port: 778   broadcast:   client: 1000   server: 2000  node_b:   0:   ip: 10.0.0.1   name: b1   1:   ip: 10.0.0.2   name: b2

 

该配置文件定义了两种不同角色的节点(node),节点 node_a 是一个负责内外通信的节点。它的配置信息包括:其连接的 timeout 时间为 300 秒,外部及内部连接使用的接口(interface)及端口号(port),其中,内部连接还配置了广播的客户端和服务器端的端口。而 node_b 类型的节点共有两个节点组成,分别是 b1 和 b2,其配置信息包括 IP 地址和主机名。实际的配置当然会比这个文件复杂一些,这里仅仅是一个示例。当我们用 Ruby 语言解析该数据后(解析方法如清单 6 所示),就可以得到清单 7 里的数据结果。


清单 6. 用 Ruby 解析 YAML 数据

#!/usr/bin/ruby  require 'yaml' yml = YAML::load(File.open('t.yml'))  p yml

 

大家可以看到,Ruby 语言解析 YAML 只需了了四行代码。其实我们完全可以打印行省掉,改写为“p YAML::load(File.open('t.yml'))”。也就是说,真正需要的就两行,require 和 YAML::load。再看结果,由于清单 7 里的结果在结构上比较复杂,也为了能和清单 5 中的 YAML 数据“看”起来相对应,这里做了一些缩进上的修改。由此我们可以更清晰得看出 YAML 数据在 Ruby 中的组织。


清单 7. 数据解析结果

{"node_a"=>{   "internal"=>{   "broadcast"=>{   "client"=>1000,   "server"=>2000   },   "port"=>778,   "iface"=>"eth0"  },   "conntimeout"=>300,   "external"=>{   "port"=>556,   "iface"=>"eth0"  }  }, "node_b"=>{   0=>{   "name"=>"b1",   "ip"=>"10.0.0.1"   },   1=>{   "name"=>"b2",   "ip"=>"10.0.0.2"  }  }  }

 

在 Ruby 中使用 YAML 就是这么简单,你只有 require 了 YAML 的库,一切数据到 Ruby 数据结构的转换都轻而易举。其实 Ruby 的数据也可以 dump 为 YAML。感兴趣的朋友可以参看 YAML for Ruby 的文档:。

 

YAML 的官方网址为

转载地址:http://jvhvx.baihongyu.com/

你可能感兴趣的文章
LOL:各服务器王者段位人数改动,越南菲律宾与韩国并列共300人
查看>>
你用不惯 RxJava,只因缺了这把钥匙
查看>>
黑洞路由配置
查看>>
佛LOGO - 佛标志 - 佛商标 - 设计和创意欣赏
查看>>
建筑论文发表流程
查看>>
JqueryEasyUi1.32组件combogrid的setValue方法有时候无法赋值及解决方法
查看>>
extjs的问题
查看>>
Tomcat详解
查看>>
LVS DR 下 tomcat 扩容问题
查看>>
linux内核优化
查看>>
hadoop伪分布式环境搭建
查看>>
初探hibernate
查看>>
Locking
查看>>
关于散列那些事
查看>>
七天LLVM零基础入门(Linux版本)------第七天
查看>>
微搜索时代 谁会是下一个霸主?
查看>>
perl 压力测试脚本
查看>>
Simware 使用指南
查看>>
自动加入域
查看>>
JavaScript中有两种常用的修改HTML节点文本的方法
查看>>