了解YAML

尽管在实际的项目中有许多现有项目的数据表达都是用 XML 组织的,然而 YAML 作为一种比 XML,或者 JSON 都更为简单易读的序列化语言,正越来越多地被人们所接受和喜欢,并应用于软件项目的开发中,比如:现实生活中的数据上程序中的序列化表示,以及系统中的配置文件的书写。众所周知,XML 的设计使得数据的表达几乎无所不能,那么是什么让 YAML 这个后来者抢占了其一席之地呢?

本文将首先简单介绍 YAML 的定义,语法及其与 XML 的不同之处,然后通过两方面的例子展示 YAML 在实际应用中的场景和方法,让读者在具体的例子中体会 YAML 的优势所在,并能通过对本文的学习建立应用 YAML 的基础。

一、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):http://www.yaml.org/refcard.html

清单一、用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 的使用方法和优越之处。

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

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

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


清单四、解析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 和 XML 只是有其不同的应用场景和使用范围,也许有人会质疑 YAML 在性能上是否同样可以超越 XML,而且这些争论一直都存在着,然后大家都不得不公认的是:YAML 凭借自己的易读性,易操控性已经成为 XML 的对手。

也许这对 XML 来说是不公平的,毕竟 XML 是由 SGML 演变来的,而 YAML 是全新设计的语言,并且其设计初衷就是为了使得数据的序列化更接近人类阅读习惯。然而我们可以从中看到的是 YAML 的出现反映了一种趋势,或者说是一种喜好。人们正在试图将规则复杂不易理解的编程方式通过某种努力去改变为更为简单方便,更为灵活好用的状态。真是 YAML 语言的这种特质,使得我们不得不说 YAML, 想要爱你很容易。

转载自:http://www.ibm.com/developerworks/cn/xml/x-1103linrr/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值