Yaml介绍及JYaml将数据写入yaml文件

来源:互联网 发布:淘宝中学生书包女韩版 编辑:程序博客网 时间:2024/05/29 08:06
一、简介
        "YAML Ain't a Markup Language"(YAML不是一种置标语言)的递归缩写,早先YAML的意思其实是:"Yet Another Markup Language"(另外一种置标语言),但为了强调这种语言以数据做为中心,而不是以置标语言为重点,而用返璞词重新命名。
        YAML的官方定义很简单,即“一种人性化的数据格式定义语言”,其主要功能用途类似于XML或JSON,YAML使用空白字符和分行来分隔数据,且巧妙避开各种封闭符号,如:引号、括号等,以避免这些符号在复杂层次结构中变得难以辨认。YAML的语法与高阶语言类似,可以很简单地表述*序列(java中的list)、杂凑表(java中的map)、标量(java中的基本类型等)数据结构,它重点强调可阅读性。和GNU一样,YAML是一个递归着说“不”的名字。不同的是,GNU对UNIX说不,YAML说不的对象是XML。


YAML vs XML:
YAML不是XML。为什么不是XML呢?因为:
- YAML的可读性好。
- YAML和脚本语言的交互性好。
- YAML使用实现语言的数据类型。
- YAML有一个一致的信息模型。
- YAML易于实现。


上面5条也就是XML不足的地方。同时,YAML也有XML的下列优点:
- YAML可以基于流来处理;
- YAML表达能力强,扩展性好。


YAML缺陷与不足:
YAML没有自己的数据类型的定义,而是使用实现语言的数据类型。一个YAML文件,在不同语言中解析后得到的数据类型可能会不同,由于其兼容性问题,不同语言间的数据流转不建议使用YAML。


总之,YAML试图用一种比XML更敏捷的方式,来完成XML所完成的任务。
更多的内容及规范参见http://www.yaml.org。


YAML vs JSON:
JSON的语法其实是YAML的子集,大部分的JSON文件都可以被YAML的剖析器剖析。虽然大部分的数据分层形式也可以使用类似JSON的格式,不过YAML并不建议这样使用,除非这样编写能让文件可读性增加,更重要的是,YAML的许多扩展在JSON是找不到的,如:进阶资料形态、关系锚点、字串不需要引号、映射资料形态会储存键值的顺序等。


二、用途
脚本语言
由于实现简单,解析成本很低,YAML特别适合在脚本语言中使用。列一下现有的语言实现:Ruby,Java,Perl,Python,PHP,OCaml,JavaScript,除了Java,其他都是脚本语言。


序列化
YAML比较适合做序列化。因为它是宿主语言数据类型直转的。


配置文件
YAML做配置文件也不错。写YAML要比写XML快得多(**无需关注标签或引号**),并且比ini文档功能更强。


调试
由于其很强的阅读性,用于调试过程中dump出信息供分析也是一种比较方便的做法。


二、下载
https://jaist.dl.sourceforge.net/project/jyaml/jyaml/jyaml-1.3/jyaml-1.3.jar

https://repo1.maven.org/maven2/org/jyaml/jyaml/1.3/jyaml-1.3.jar

http://www.java2s.com/Code/Jar/j/Downloadjyaml13dgujar.htm


三、YAML语法与范例
YAML包括Sequence和Map两种基本数据格式。对于Sequence,其每一项会以“-”开头。对于Map的每一项,key与value之间是用“:"来连接的。从属关系则用空格来表示。这基本上就是YAML的全部语法了。


一般YAML文件扩展名为.yaml。比如:John.yaml

name: John Smithage: 37spouse:    name: Jane Smith    age: 25children:    -   name: Jimmy Smith        age: 15    -   name: Jenny Smith        age 12
由于yaml的超强可读性,我们了解到:John今年37岁,两个孩子Jimmy 和Jenny活泼可爱,妻子Jane年轻美貌,而且年仅25岁,一个幸福的四口之家。

四、JYaml——YAML的Java实现
YAML已经有了不少实现,详细的实现列表参见http://www.yaml.org/download.html。
其中JYaml(http://jyaml.sourceforge.net)是YAML的Java实现。


JYaml简介
YAML的Java库,现在可以用Java来读取YAML。YAML是ruby常用的配置文件,对象序列化格式,比XML轻便,易读,比properties表达能力丰富。在ruby世界很受欢迎。现在有了Java的库了。我觉得值得好好看一下,说不定以后可以用YAML取代Java世界的XML配置文件了。
YAML使用实现语言的数据类型。我们看一下一些JYaml支持的Java数据类型:
- 原始数据和封装类(比如int,java.lang.Integer)
- JavaBean兼容对象(Structure支持)
- Collection(sequence支持)
# List
# Set
- Map(map支持)
- Arrays(sequence支持)
- BigInteger和BigDecimal
- Date


我们给出John.yaml的java描述:

package hehe;public class Person {      private String name;      private int age;      private Person spouse;    private Person[] children;      public Person(){    }      public void setName(String name) {          this.name = name;      }      public void setAge(int age) {          this.age = age;      }      public void setSpouse(Person spouse) {          this.spouse = spouse;      }      public void setChildren(Person[] children) {          this.children = children;      }      public String getName() {          return this.name;      }      public int getAge() {          return this.age;      }      public Person getSpouse() {          return this.spouse;      }      public Person[] getChildren() {          return this.children;      }  }
现在让我们装配一个Jone:
package hehe;import java.io.File;import java.io.FileNotFoundException;import org.ho.yaml.Yaml;public class TestYaml {    public static void main(String[] args) throws Exception {        /* Initialize data. */        Person michael = new Person();        Person floveria = new Person();        Person[] children = new Person[2];        children[0] = new Person();        children[1] = new Person();                michael.setName("Michael Corleone");        michael.setAge(24);        floveria.setName("Floveria Edie");        floveria.setAge(24);          children[0].setName("boy");        children[0].setAge(3);          children[1].setName("girl");          children[1].setAge(1);                    michael.setSpouse(floveria);          floveria.setSpouse(michael);                    michael.setChildren(children);          floveria.setChildren(children);                    /* Export data to a YAML file. */          File dumpFile = new File("John.yaml");        try {              Yaml.dump(michael, dumpFile);        } catch (FileNotFoundException e) {              e.printStackTrace();          }    }}
下面我们看看John.yaml是什么样子:
--- &0 !hehe.Personage: 24children: &2 !hehe.Person[]  - !hehe.Person    age: 3    name: boy  - !hehe.Person    age: 1    name: girlname: Michael Corleonespouse: !hehe.Person  age: 24  children: *2  name: Floveria Edie  spouse: *0
其中!yaml.test.internal.Person是一些类型的信息。load的时候需要用。
还可以用下面的代码dump出没有类型信息的John.yaml:
Yaml.dump(michael, dumpFile, true);

我们再来看看JYaml对流处理的支持。
为简便起见,我们只是把同一个john写2次:

import java.io.File;import java.io.FileOutputStream;import org.ho.yaml.Yaml;import org.ho.yaml.YamlEncoder;public class TestYaml {public static void main(String[] args) throws Exception {File dumpFile = new File("John.yaml");Person john2 = (Person) Yaml.loadType(dumpFile, Person.class);YamlEncoder enc = new YamlEncoder(new FileOutputStream(dumpFile));for(int i=0; i<2; i++){john2.setAge(37+i);enc.writeObject(john2);enc.flush();}enc.close();}}
再看下John.yaml成这样的了:
--- &0 !hehe.Personage: 37children: &2 !hehe.Person[]  - !hehe.Person    age: 3    name: boy  - !hehe.Person    age: 1    name: girlname: Michael Corleonespouse: !hehe.Person  age: 24  children: *2  name: Floveria Edie  spouse: *0--- &9 !hehe.Personage: 38children: &11 !hehe.Person[]  - !hehe.Person    age: 3    name: boy  - !hehe.Person    age: 1    name: girlname: Michael Corleonespouse: !hehe.Person  age: 24  children: *11  name: Floveria Edie  spouse: *9
下面再把这两个对象读出来(注意while循环退出的方式):
import java.io.EOFException;import java.io.File;import java.io.FileInputStream;import org.ho.yaml.Yaml;import org.ho.yaml.YamlDecoder;public class TestYaml {    public static void main(String[] args) throws Exception {        File dumpFile = new File("John.yaml");        Person john2 = (Person) Yaml.loadType(dumpFile, Person.class);        YamlDecoder dec = new YamlDecoder(new FileInputStream(dumpFile));        while(true){        try{        john2 = (Person) dec.readObject();        System.out.println(john2.getAge());        }catch(EOFException e){                break;            }        }    }}
运行结果:
37
38

五、YAML和Ruby
        Ruby和YAML的联系,甚至比Java与XML的联系还要紧密。Ruby把YAML用到了和数据相关的方方面面。配置文件的约定格式是YAML。同时YAML还是Ruby的文本序列化格式,就像XML是SDO的文本序列化格式一样。
        不夸张的说,YAML是Ruby中流动的血液。
        那,Ruby为什么不选XML呢?
        其一,XML对Ruby这样的脚本语言而言,解析起来比较困难。效率肯定是会有问题。Ruby的XML解析没有完全实现,走的是实用主义的路线,可能也缘于此。而YAML要轻快很多。
        另外,XML使用自定义类型。就算解析出来,也不能直接用,还要再转一次。而YAML不定义自己的类型,直接使用宿主语言本身类型,直截了当。
        YAML的Ruby实现出现的很早。但由于某些原因,YAML的Ruby实现是不严格的。随着其他语言的YAML实现慢慢出现,这个问题日益明显了。
        毕竟每个实现语言的类型不一样的,不同语言文化也不同。因此不同实现的YAML的交互是个问题。兼容性需要YAML规范来保证。而具体的实施还有很长的道路要走。
        但YAML在单一语言中,YAML的应用是没有问题的。
        YAML在Ruby On Rails中经常用作配置文件。比如数据库信息的配置:

test:  adapter: mysql  database: weblog_test  username: root  password:  host: localhost production:  adapter: mysql  database: weblog_production  username: root  password:   host: localhost
熟悉ROR的读者应该能看出这是`config/database.yml'文件。


六、YAML存在的意义

        无论多么完美的事物,都需要有对立面,有说“NO”的声音。XML也不例外。当然,站在主流的对立面,需要勇气和智慧。
        YAML和XML不同,没有自己的数据类型的定义,而是使用实现语言的数据类型。这一点,有可能是出奇制胜的地方,也可能是一个败笔。如果兼容性保证的不好的话,YAML数据在不同语言间流转会有问题。如果兼容性好的话,YAML就会成为不同语言间数据流通的桥梁。建议yaml.org设立兼容认证机制,每个语言的实现必须通过认证。
        假如兼容性没问题的话,YAML就太完美了。轻巧,敏捷,高效,简便,通用。这才是理想中的数据模型。当然就现在而言,这还只是个理想。


参考:(虽然我这里标明的是转载,但是我也把参考来的内容做了一些修改,费了我很大的工夫,尤其是一些代码按原文的方式来并不能成功运行,因为大部分内容是粘贴过来的,虽然排版修改什么的也花费了我大量的汗水但不想让人质疑是伪原创就把我这篇文章类型定义为转载,可是真是不甘心啊,因为我见网上标明转载的文章那可真是一字不差的粘贴过来啊。。。)
https://www.cnblogs.com/274914765qq/p/4483300.html
https://www.ibm.com/developerworks/cn/xml/x-cn-yamlintro/
http://blog.csdn.net/poechant/article/details/7017067


七、5分钟认识YAML(一下内容来自http://blog.csdn.net/ruby_cn/article/details/177567)
第一分钟:一个简单的列表
你的朋友给你寄了一封如下的信件:
- Memoirs Found in a Bathtub
- Snow Crash
- Ghost World
同时,他也要求你按照上面的顺序来阅读这些书,他想和你探讨关于这些书的内容。
在YAML中,这些有顺序的列表(list)叫做序列(sequence)。序列包括了一组有顺序的数据,当你在程序中载入这个序列,它们的顺序保持不变。
在很多比较灵活的语言中,你可以用指定索引的方式访问这个序列及其中的值。以0开头的表示这个序列的第一项。
在PHP, Perl, 或 Ruby中,可以这样:
print $book_list[0];
打印结果如下:
Memoirs Found in a Bathtub
这也是上面书籍列表的第一项。


其他列表
列表(Lists)可以包括各种数据:
---
- 1           # Numbers
- Snow Crash  # Strings
- 2003-07-24  # Dates
上面的列表以三个"-"开头,这三个"-"是文档分割符(document separator),它表示了一段YAML文档的开始。当然,你也可以划分多个文档,比如:

---- Harry Potter and the Prisoner of Azkaban- Harry Potter and the Goblet of Fire- Harry Potter and the Order of the Phoenix---- Memoirs Found in a Bathtub- Snow Crash- Ghost World
第二分钟:一个简单的字典
当你沉浸在阅读 Harry Potter 时,你的朋友又寄来了新的列表,这次列表包括了作者的名字:
Stanislaw Lem: Memoirs Found in a Bathtub
Neal Stephenson: Snowcrash
Daniel Clowes: Ghost World
上面的字典没有顺序,但是每个作者都对应一本书的名字。你的朋友希望你可以根据作者找到你想要的书。(注意前面没有"-")
在YAML中,这样的字典结构称为 map,map通常用来存放成对的数据,冒号左面的称为key,右面的叫做value。 
key 用作从map中取数据的索引。
在PHP 或 Ruby中,可以这样写:
print $books_by_author['Daniel Clowes'];
将打印如下内容:
Ghost World

Sequence中的Map
你的朋友寄给你了一份更新的列表,包括了作者,书名,并且有一定的顺序,希望你能按照这个顺序来阅读。
---
- Stanislaw Lem: Memoirs Found in a Bathtub
- Neal Stephenson: Snowcrash
- Daniel Clowes: Ghost World
上面的序列中,每一项都是一个map,当一种集合(collection )包括另一种集合时,称作嵌套(nesting)。


第三分钟:邮箱里的东西
第三分钟我们先放慢一下速度,老师让你朋友这么打扰你我想过不多久你肯定会被气疯的。
冉我们来看看你的信箱。你住在一个公寓里,你的信箱只有一个小口可以投信,旁边是其他的几百个信箱。
你检查一下自己的信箱发现了五封信。两封是给你的邻居Jim O'Connor的,一封是给一个叫做"Hank Bros.: the Car Wash!"的公司的,其他的两封信是你自己的。
你打算对自己邮箱里多出来的信进行投诉,你打算给邮局发送一封信,让他们看看这给你带来了多大的麻烦。
你开始了一个新的YAML文档,里面包括今天的日期,和你的信箱里的信件:
---
date: 2003-07-25
letters to:
  "Hank Bros.: the Car Wash!": 1
  Jim O'Connor: 2
  Myself: 2
这个例子里,一个map嵌套了另一个map,第一个MAP的key是,它的值是letters to  一个被嵌套的MAP,第二个MAP是缩进排列的。
在PHP或者RUBY中,可以这样访问:
print $mailbox['letters to']['Myself'];
将会打印:

你也发现了,"Hank Bros.: the Car Wash!"用双银号扩起来了,这是因为这里面包括了冒好。否则,会引起麻烦的,你将可能弄不清哪个是key 哪个是value。


第四分钟:更多消息
你从邮局得到了一些解释:

---Concerning Car Washes: >  We are sorry to have misplaced this letter.  We were told by a reliable source that you  were the owner of "Hank Bros.: the Car Wash!".  Sorry.
邮局工作有误,但这也向我们展示了YAML的另一个特点:块(block )。在他们的信息里,用到了block。
在YAML中,一个block是一段文本,它们缩进一个或多个空格。
注意这个大于号: >。它表示一个“folded block”的开始。所谓folded block,就是一行一行紧挨着句子将组成一个段落,这个段落就像我们读课文那样可以阅读的。
上面的消息在YAML 阅读器看来将分为两行,由一个回车换行分割。


Controlling Words
上面的消息还没完,这是后面的:

Concerning "Jim O'Connor": |  You are receiving Jim O'Connor's mail for several reasons:  - The nameplate on your mailbox still says his name.  - He has told our postman that you screen his mail.  - He is living in your ceiling.  - He held a raygun to the postmans head.
这看起来有点古怪,邮局的人用一个竖线,取代了原来的大于号,这有什么不同吗?
一个竖线(也称管道pipe),表示了一个literal block的开始。 literal block 表示每个句子自成一节,这个块将会像计算机读取那样,都是字面值。
YAML 阅读器会把上面的块当作5行(第一行是空行)。

第五分钟:这就是全部吗?
到现在,看起来YAML也就这么多东西而已,它只是一些列表和字典组成的集合而已?
这只是我们五分钟能谈论到的最基本的东西,在继续之前,来看最后一个概念。
这里是一个人读这个五分钟教程所用时间的纪录:

---name: Dirk Hockeybranchminutes spent:  - 1.02 - 1.34 - 0.7 - 0.89 - 0.94
上面我们用一个序列 (sequence)嵌套在了一个map中,序列中的每项代表了在第几步所用的时间。如果每个人都把自己阅读的时间像这样寄给我们,那我们需要给本教程准备一个更准确的名字,比如YAML in Five-Point-One-Two Minutes。这将有点华而不实。(我们可能需要很多的篇幅来写这样的文档。)
一个机灵的YAML用户可能会用 inline sequence来记录它们所用的时间:
---
name: Dirk Hockeybranch
minutes spent: [1.02, 1.34, 0.7, 0.89, 0.94]
对于短的列表,你可以把它们都房在一行里,各项之间用逗号分割,最后用中括号括起来。
Inline maps 也类似:
---
minutes spent: {one: 1.02, two: 1.34, three: 0.7,
                four: 0.89, five: 0.94}
以上也要谨慎使用,BLOCK在inline sequences 或 Inline maps 中不能使用。

原创粉丝点击