// ====================================================================================================
// YAML Parser for the .NET Framework
// ====================================================================================================
//
// Copyright (c) 2006
// Christophe Lambrechts
// Jonathan Slenders
//
// ====================================================================================================
// This file is part of the .NET YAML Parser.
//
// This .NET YAML parser is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// The .NET YAML parser is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Foobar; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection;
// ====================================================================================================
using System;
using System.Collections;
// TODO Access to nodes via the [] overload
namespace Yaml
{
///
/// Yaml Mapping
///
public class Mapping : Node
{
private ArrayList childNodes = new ArrayList ();
/// New empty mapping
public Mapping () : base ("tag:yaml.org,2002:map", NodeType.Mapping) { }
/// New mapping from a mappingnode array
public Mapping (MappingNode [] nodes) :
base ("tag:yaml.org,2002:map", NodeType.Mapping)
{
foreach (MappingNode node in nodes)
childNodes.Add (node);
}
/// Parse a mapping
public Mapping (ParseStream stream) :
base ("tag:yaml.org,2002:map", NodeType.Mapping)
{
// Mapping with eplicit key, (implicit mappings are threaded
// in Node.cs)
if (stream.Char == '?')
{
// Parse recursively
do {
Node key, val;
// Skip over '?'
stream.Next ();
stream.SkipSpaces ();
// Parse recursively. The false param avoids
// looking recursively for implicit mappings.
stream.StopAt (new char [] {':'});
stream.Indent ();
key = Parse (stream, false);
stream.UnIndent ();
stream.DontStop ();
// Parse recursively. The false param avoids
// looking for implit nodes
if (stream.Char == ':')
{
// Skip over ':'
stream.Next ();
stream.SkipSpaces ();
// Parse recursively
stream.Indent ();
val = Parse (stream);
stream.UnIndent ();
}
else
val = new Null ();
AddMappingNode (key, val);
// Skip possible newline
// NOTE: this can't be done by the drop-newline
// method since this is not the end of a block
if (stream.Char == '\n')
stream.Next ();
}
while ( ! stream.EOF && stream.Char == '?');
}
// Inline mapping
else if (stream.Char == '{')
{
// Override the parent's stop chars, never stop
stream.StopAt (new char [] { });
// Skip '{'
stream.Next ();
do {
Node key, val;
// Skip '?'
// (NOTE: it's not obligated to use this '?',
// especially because this is an inline mapping)
if (stream.Char == '?')
{
stream.Next ();
stream.SkipSpaces ();
}
// Parse recursively the key
stream.StopAt (new char [] {':', ',', '}'});
stream.Indent ();
key = Parse (stream, false);
stream.UnIndent ();
stream.DontStop ();
// Value
if (stream.Char == ':')
{
// Skip colon
stream.Next ();
stream.SkipSpaces ();
// Parse recursively the value
stream.StopAt (new char [] {'}', ','});
stream.Indent ();
val = Parse (stream, false);
stream.UnIndent ();
stream.DontStop ();
}
else
val = new Null ();
AddMappingNode (key, val);
// Skip comma (key sepatator)
if (stream.Char != '}' && stream.Char != ',')
{
stream.DontStop ();
throw new ParseException (stream, "Comma expected in inline sequence");
}
if (stream.Char == ',')
{
stream.Next ();
stream.SkipSpaces ();
}
}
while ( ! stream.EOF && stream.Char != '}' );
// Re-accept the parent's stop chars
stream.DontStop ();
// Skip '}'
if (stream.Char == '}')
stream.Next ();
else
throw new ParseException (stream, "Inline mapping not closed");
}
}
/// Add a node to this mapping
public void AddMappingNode (Node key, Node val)
{
childNodes.Add (new MappingNode (key, val));
}
/// Add a node to this mapping
public void AddMappingNode (MappingNode node)
{
if (node != null)
childNodes.Add (node);
else
childNodes.Add (new MappingNode (null, null));
}
/// Number of mappings
public int Count
{
get { return childNodes.Count; }
}
/// To String
public override string ToString ()
{
string result = "";
foreach (MappingNode node in childNodes)
result += node.ToString ();
return "[MAPPING]" + result + "[/MAPPING]";
}
/// Node info
public override Node Info ()
{
Mapping mapping = new Mapping ();
mapping.AddMappingNode (new String ("kind"), new String ("mapping"));
mapping.AddMappingNode (new String ("type_id"), new String (URI));
Mapping childs = new Mapping ();
int i = 0;
foreach (MappingNode child in childNodes)
{
Sequence keyvaluepair = new Sequence ();
keyvaluepair.AddNode (child.Key.Info () );
keyvaluepair.AddNode (child.Value.Info ());
childs.AddMappingNode (new String ("key_" + i), keyvaluepair);
i ++;
}
mapping.AddMappingNode (new String ("value"), childs);
return mapping;
}
/// Write to YAML
protected internal override void Write (WriteStream stream)
{
foreach (MappingNode node in childNodes)
{
stream.Append ("? ");
stream.Indent ();
Yaml.Node key = node.Key;
key.Write (stream);
stream.UnIndent ();
stream.Append (": ");
stream.Indent ();
node.Value.Write (stream);
stream.UnIndent ();
}
}
}
///
/// Node pair (key, value) of a mapping
///
public class MappingNode
{
private Node key;
private Node val;
/// Create a new mappingnode
public MappingNode (Node key, Node val)
{
if (key == null) key = new Null ();
if (val == null) val = new Null ();
this.key = key;
this.val = val;
}
/// Key property
public Node Key
{
get { return key; }
set { key = (value == null ? new Null () : value); }
}
/// Value property
public Node Value
{
get { return val; }
set { val = (value == null ? new Null () : value); }
}
/// To String
public override string ToString ()
{
return
"[KEY]" + key.ToString () + "[/KEY]" +
"[VAL]" + val.ToString () + "[/VAL]";
}
}
}