Yaml是一种不错的格式,无论是作为配置文件还是小量数据的存储都是一种不错的选择。ruby和它结合的比较好,但是其它语言,目前的parser还不完善。

C#就没有比较好的Yaml的Parser,在nuGet上找了半天,找到一个parse,但是貌似有问题,yaml文件缩进一定要两个空格,不能是Tab,我狂晕。

后来自己想了一个办法来解决这个问题。就是C#调用用IronRuby来解析,然后再返回给C#。因为IronRuby完美的实现了Ruby 1.9的大部分,用它来分析Yaml应该是比较合适的。

新建一个工程YLab.Yaml 加入对Ironruby的dll的引用 下载了ironruby就知道了引用哪些了

建立一个文件夹YLab.Yaml

下面建立一个config.rb文件

# 作者 虞  
# 时间 2011-6-6
# Path 变量定义了IronRuby的SearchPath

# rb文件中的require就是在SearchPath中查找的

# 这里的路径都是相对于应用程序根目录的相对路径

Path = 
[

      "RubyLib/ironruby",    
"RubyLib/ruby/1.9.1"
,
     "RubyLib/ruby/site_ruby/1.9.1"
]

def
 SearchPath    
Path
end

 

 再建立一个YLabYAML.rb文件

 

# 作者 虞  
# 时间 2011-6-6

require "yaml"
class
 YYAML    
def
 load(file)        
YAML::load_file(file)    
end
   

def
 parse(file)        
YAML::parse_file(file)    
end
end
 然后是YAML.cs文件

 

 

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 using System.IO;
 7 
 8 using Microsoft.Scripting.Hosting;
 9 using IronRuby;
10 
11 namespace YLab.YAML
12 {
13     public class YAML
14     {
15         private ScriptRuntime irb;
16         private ICollection<string> searchPath = new List<string>();
17         private dynamic yyaml;
18 
19         public YAML()
20         {
21             irb = Ruby.CreateRuntime();
22             searchPath.Add(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory));
23             searchPath.Add(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"YLab.YAML"));
24             irb.GetRubyEngine().SetSearchPaths(searchPath);
25 
26             dynamic rbCfg = irb.UseFile("config.rb");
27             var cfgSearchPath = rbCfg.SearchPath();
28             foreach (var path in cfgSearchPath)
29             {
30                 searchPath.Add(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, (string)path));
31             }
32             irb.GetRubyEngine().SetSearchPaths(searchPath);
33             //ylabYAML = irb.UseFile("YLabYAML.rb");
34 
35             var assembly = System.Reflection.Assembly.GetExecutingAssembly();
36 
37             string code;
38 
39             using (var stream = assembly.GetManifestResourceStream("YLab.YAML.YLab.YAML.YLabYAML.rb"))
40             {
41                 using (TextReader rbReader = new StreamReader(stream)) {
42                     code = rbReader.ReadToEnd();
43                 }
44             }
45             irb.GetRubyEngine().Execute(code);
46 //            irb.GetRubyEngine().Execute(@"\
47 //                # 作者 虞
48 //                # 时间 2011-6-6
49 //                require 'yaml'
50 //                class YYAML
51 //                    def load(file)
52 //                        YAML::load_file(file)
53 //                    end
54 //
55 //                    def parse(file)
56 //                        YAML::parse_file(file)
57 //                    end
58 //                end
59 //            ");
60 
61             dynamic ruby = irb.Globals;
62             yyaml = ruby.YYAML.@new();
63 
64         }
65 
66         public dynamic LoadFile(string yamlFile)
67         {
68             return yyaml.load(yamlFile);
69 
70         }
71 
72         public dynamic ParseFile(string yamlFile)
73         {
74             return yyaml.parse(yamlFile);
75         }
76     }
77 }

这样就可以了

再建立一个consoleapp

先放一个要分析的yaml config.yaml

server:
    address: 10.0.0.86
    port: 36
persons: 
    - name: 丁一
      age: 30
    - name: 王二
      age: 33

然后是program.cs

static void Main(string[] args)
        {
            YAML y 
= new YAML();
            var config 
= y.ParseFile("config.yaml");
            var server 
= (config as MappingNode).Nodes.Where(n => (n.Key as ScalarNode).Value == "server").Single().Value;
            var address 
= ((server as MappingNode).Nodes.Where(n => (n.Key as ScalarNode).Value == "address").Single().Value as ScalarNode).Value;
            var port 
= ((server as MappingNode).Nodes.Where(n => (n.Key as ScalarNode).Value == "port").Single().Value as ScalarNode).Value;
            Console.WriteLine(address);
            Console.WriteLine(port);
            var persons 
= (config as MappingNode).Nodes.Where(n => (n.Key as ScalarNode).Value == "persons").Single().Value;
            var person 
= (persons as SequenceNode).Nodes.Where(n =>{
                var name 
= (n as MappingNode).Nodes.Where(n2 => (n2.Key as ScalarNode).Value == "name").Single().Value;
                
return (name as ScalarNode).Value == "丁一";
            }).Single();
            Console.WriteLine(((person 
as MappingNode).Nodes.Where(n => (n.Key as ScalarNode).Value == "name").Single().Value as ScalarNode).Value);
        }
 

 不要忘记了 生成以后YLab.YAML项目下的YLab.YAML文件夹要拷贝到生成exe的目录里面 ironruby的lib目录也拷贝进去改名为RubyLib 当然不需要的rb文件你可以去掉啦 只要留下和yaml相关的rb文件就可以了

源码:CSharp_Parse_Yaml_Via_IronRuby.rar 

 问题:win7+E文的vs 没问题 winXP + 中文的vs 出现问题

irb.GetRubyEngine().Execute(code); 
character U+901A can't be encoded in US-ASCII
 

作者: ThinkInSharp 发表于 2011-06-06 22:10 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"