Click here to Skip to main content
Click here to Skip to main content

YAML Parser in C#

By , 17 Feb 2011
 

Introduction

YAML is a human-friendly, cross language, Unicode based data serialization language designed around the common native data types of agile programming languages. It is broadly useful for programming needs ranging from configuration files to Internet messaging to object persistence to data auditing.

Visit the official YAML website for more information.

YAML Basics

A YAML file may contain zero or more YAML documents, separated by document markers. A YAML document contains one root DataItem. There are three types of DataItems: Scalar, Sequence, and Mapping. DataItems may be nested to form structured data.

Each DataItem type has several formatting styles for good human readability.

yamlDataItem.png

Some rules:

  • A block style item can be nested to a block style item but not a flow style item.
  • A flow style item can be nested to either a block style or a flow style item.
  • Block structure is denoted by indentation.
  • All indentations only use space char, tab is not allowed.

Here are some examples:

Block Scalar

Literal Text
|
The text using
literal style.
|-
The text using
literal style.
"The text using\nliteral style.\n" "The text using\nliteral style."
Folded Text
>
The text using
folded style.
>-
The text using
folded style.
"The text using folded style.\n" "The text using folded style."
Flow Scalar
Plain Text
  • Can not start with ,[]{}#&*!|>'\"%@`
  • Can start with -?: followed by non space char
  • ": " and " #" cannot appear in between
'Single Quoted Text'
  • Line breaks are folded
  • "'" is escaped with "''"
"Double Quoted Text"
  • Line breaks are folded
  • Escape sequences can be used
Sequence
Block Sequence
- Item one
- Item two
- Item three
Flow Sequence
[Item one, Item two,
Item three]
Mapping
Block Mapping
Key1: Item one
Key2: Item two
? Key3
: Item three 
Flow Mapping
{Key1: Item one, Key2: Item two, 
Key3: Item three} 

Other

Anchor and Alias
Key1: &items
  A: Item A
  B: Item B
Key2: *items
Key1:
  A: Item A
  B: Item B
Key2:
  A: Item A
  B: Item B
Comment
# whole line comment
Data Item # inline comment

Background

There is already a Yaml Library for .NET project, but the features supported are limited.

Using the Code

The parser code is generated using a homemade tool based on grammar specified in the YAML.PEG.txt file. This grammar is not completely equal to the official YAML specification. Here are some differences:

A separator “,” is not allowed following the last entry of Sequence or Mapping in this parser. The 32-bit Unicode escape sequence “U” (ns-hex-digit × 8) is not supported.

The parser can be used like this:

YamlParser parser = new YamlParser();
TextInput input = new TextInput(File.ReadAllText(yamlFilePath));
bool success;
YamlStream yamlStream = parser.ParseYamlStream(input, out success);
if (success)
{
    foreach (YamlDocument doc in yamlStream.Documents)
    {
        // access DataItem by doc.Root
    }
}
else
{
    MessageBox.Show(parser.GetEorrorMessages());
}

Or:

YamlStream yamlStream = YamlParser.Load(yamlFilePath);

Points of Interest

The main shortcoming of this parser is that error messages are not intuitive. You are welcome to give suggestions.

History

  • 2008-08-21: Article submitted.
  • 2011-02-16: Redesigned the UI, fixed some parser bugs.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Liu Junfeng
Software Developer
China China
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberCaptainClueless6 Apr '13 - 12:07 
The only YAML reader for C# I have found. Worked first day in a client project.
QuestionComplement to the YAML Parser [modified]memberCaptainClueless6 Apr '13 - 11:18 
I would like to share a small piece of code that processes the root provided by Liu.
Usage:
            Hash h = (Hash) recurseGen(doc.Root);
Now it's possible to access the members in the tree like this:
            ass(Convert.ToString(h["namn"]),"Alternativ A");
            ass(Convert.ToInt32(h["centroider"]),2874);
            ass(GetListFloat((List)h["tidsvarden"])[0], 35)
        private static Hash recurse(Mapping item) {
            Hash hash = new Hash();
            foreach (MappingEntry entry in item.Enties) hash[entry.Key.ToString()] = recurseGen(entry.Value);
            return hash;
        }
 
        private static List recurse(Sequence item) {
            List list = new List();
            foreach (DataItem entry in item.Enties) list.Add(recurseGen(entry));
            return list;
        }
 
        private static object recurse(Scalar item) {
            var s = item.Text;
            int n;
            if (int.TryParse(s, out n)) return n;
            float f;
            if (float.TryParse(s, out f)) return f;
            if (!s.Contains("..")) return s;
            s = s.Replace("..", "@");
            var arr = s.Split('@');
            var i0 = Convert.ToInt32(arr[0]);
            var i1 = Convert.ToInt32(arr[1]);
            var list = new List();
            for (var i = i0; i <= i1; i++) list.Add(i);
            return list;
        }
 
        private static object recurseGen(DataItem item) {
            if (item is Mapping) return recurse((Mapping)item);
            if (item is Sequence) return recurse((Sequence)item);
            if (item is Scalar) return recurse((Scalar)item);
            return null;
        }
I also added code for expanding a range to a list. 1..3 => [1,2,3]
(Last seven lines in handling of Scalars.)
        public static List<float> GetListFloat(List list1) {return (from object item in list1 select Convert.ToSingle(item)).ToList();}


modified 6 Apr '13 - 18:09.

AnswerRe: Complement to the YAML ParsermemberCaptainClueless6 Apr '13 - 12:15 
I realized Liu actually had almost the same recursive functions to get data out of the tree as in my code. As he is filling a TreeView and I'm filling Hashes and Lists I think my comment still has some value.
QuestionHow do I get the data out of the tree?memberCaptainClueless6 Apr '13 - 10:54 
Thanks for an excellent YAML-reader!
 
My problem is how to get the information out the YAML-tree provided by your module.
The code below works, but it's a bit wordy, at least compared with Ruby:
 
tree = YAML.load_file('data\styrfil.yml')
 
assert tree['namn'],"Alternativ A"
assert tree['centroider'], 2874
assert tree['tidsvarden'], [35, 42, 85, 135, 275, 650, 650, 275, 650, 275, 650]
 
Have I missed something?
 
YamlStream yamlStream = YamlParser.Load(filename);
var doc = yamlStream.Documents[0];
Mapping mapping = (Mapping) doc.root;
 
assert(mapping.Enties.Find(entry => entry.Key.ToString() == "namn").Value.ToString(), "Alternativ A");
assert(Convert.ToInt32(mapping.Enties.Find(entry => entry.Key.ToString() == "centroider").Value.ToString()), 2874);
assert(Convert.ToInt32(((Sequence) mapping.Enties.Find(entry => entry.Key.ToString() == "tidsvarden").Value).Enties[0].ToString()), 35);

QuestionNew to YAMLmemberHanibani27 Sep '12 - 6:03 
Hello,
 
I'm a newbie to YAML and simply downloaded and compiled the test program, but my first YAML file that I insert can't be parsed.
 
The errors reported doesn't seen to correspond to real lines in the file. I shortened the file but still getting the same errors. Can you help? File is:
 
portals:
add: Add Portal
delete: Delete Portal
source: Portal Source
name: Portal Name
no_portals: 'There are no portals currently configured for this server.'
upgrading: 'Upgrading from version 3.0?'
options: Click here for upgrade options
enabled: %1 enabled # where %1 is the name of the portal
large_icon_select: Select Large Icon Image
 
Regards
Hanibani
Question谢谢你!membersebgod28 Dec '11 - 21:37 
你做的一个非常棒的软件!!!你好厉害啊!
Smile | :)
SuggestionVery good LibrarymemberMadhur Ahuja30 Aug '11 - 0:50 
Its the best YAML Parser out there. Please update it to work with non indented list.
Madhur
http://madhurahuja.blogspot.com

GeneralCould you release this under GPL, LGPL, or BSD licence please?memberaj_codeproject26 May '11 - 3:43 
Hi Liu,
 
I would like to use this code for a project that is GPL. Could you please release this code under either a GPL-compatible licence to allow this to occur?
 
Thanks!
GeneralRe: Could you release this under GPL, LGPL, or BSD licence please?memberMember 393683426 May '11 - 5:26 
+1 That would be great.
GeneralRe: Could you release this under GPL, LGPL, or BSD licence please?memberLiu Junfeng4 Jun '11 - 2:02 
No problem. You can use it in GPL project.
Cheers.
I am happy to work with people doing great projects.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 17 Feb 2011
Article Copyright 2008 by Liu Junfeng
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid