<h1id="introduction">Introduction</h1><p>NimYAML advocates parsing YAML input into native Nim types. Basic Nim library types like integers, floats and strings, as well as all tuples, enums and objects without private fields are supported out-of-the-box. Reference types are also supported, and NimYAML is able to detect if a reference occurs more than once and will serialize it accordingly. This means that NimYAML is able to dump and load potentially cyclic objects.</p>
<p>While loading into and dumping from native Nim types is the preferred way to use NimYAML, it also gives you complete control over each processing step, so that you can for example only use the parser and process its event stream yourself. The following diagram gives an overview of NimYAML's features based on the YAML processing pipeline. The items and terminology YAML defines is shown in <em>italic</em>, NimYAML's implementation name is shown in <strong>bold</strong>.</p>
<h1id="intermediate-representation">Intermediate Representation</h1><p>The base of all YAML processing with NimYAML is the <aclass="reference external"href="yaml.stream.html#YamlStream">YamlStream</a>. This is basically an iterator over <aclass="reference external"href="yaml.stream.html#YamlStreamEvent">YamlStreamEvent</a> objects. Every proc that represents a single stage of the loading or dumping process will either take a <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> as input or return a <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt>. Procs that implement the whole process in one step hide the <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> from the user. Every proc that returns a <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> guarantees that this stream is well-formed according to the YAML specification.</p>
<p>This stream-oriented API can efficiently be used to parse large amounts of data. The drawback is that errors in the input are only discovered while processing the <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt>. If the <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> encounters an exception while producing the next event, it will throw a <ttclass="docutils literal"><spanclass="pre">YamlStreamError</span></tt> which contains the original exception as <ttclass="docutils literal"><spanclass="pre">parent</span></tt>. The caller should know which exceptions are possible as parents of <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> because they know the source of the <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> they provided.</p>
<h1id="loading-yaml">Loading YAML</h1><p>If you want to load YAML character data directly into a native Nim variable, you can use <aclass="reference external"href="yaml.serialization.html#load,,K">load</a>. This is the easiest and recommended way to load YAML data. This section gives an overview about how <ttclass="docutils literal"><spanclass="pre">load</span></tt> is implemented. It is absolutely possible to reimplement the loading step using the low-level API.</p>
<p>For parsing, a <aclass="reference external"href="yaml.parser.html#YamlParser">YamlParser</a> object is needed. This object stores some state while parsing that may be useful for error reporting to the user. The <aclass="reference external"href="yaml.parser.html#parse,YamlParser,Stream">parse</a> proc implements the YAML processing step of the same name. All syntax errors in the input character stream are processed by <ttclass="docutils literal"><spanclass="pre">parse</span></tt>, which will raise a <ttclass="docutils literal"><spanclass="pre">YamlParserError</span></tt> if it encounters a syntax error.</p>
<p>Transforming a <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> to a native YAML object is done via <ttclass="docutils literal"><spanclass="pre">construct</span></tt>. It skips the <ttclass="docutils literal"><spanclass="pre">compose</span></tt> step for efficiency reasons. As Nim is statically typed, you have to know the target type when you write your loading code. This is different from YAML APIs of dynamically typed languages. If you cannot know the type of your YAML input at compile time, you have to manually process the <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> to serve your needs.</p>
<h1id="dumping-yaml">Dumping YAML</h1><p>Dumping is preferredly done with <aclass="reference external"href="yaml.serialization.html#dump,K,Stream,TagStyle,AnchorStyle,PresentationOptions">dump</a>, which serializes a native Nim variable to a character stream. As with <ttclass="docutils literal"><spanclass="pre">load</span></tt>, the following paragraph describes how <ttclass="docutils literal"><spanclass="pre">dump</span></tt> is implemented using the low-level API.</p>
<p>A Nim value is transformed into a <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> with <aclass="reference external"href="yaml.serialization.html#represent,T,TagStyle,AnchorStyle">represent</a>. Depending on the <ttclass="docutils literal"><spanclass="pre">AnchorStyle</span></tt> you specify, this will transform <ttclass="docutils literal"><spanclass="pre">ref</span></tt> variables with multiple instances into anchored elements and aliases (for <ttclass="docutils literal"><spanclass="pre">asTidy</span></tt> and <ttclass="docutils literal"><spanclass="pre">asAlways</span></tt>) or write the same element into all places it occurs (for <ttclass="docutils literal"><spanclass="pre">asNone</span></tt>). Be aware that if you use <ttclass="docutils literal"><spanclass="pre">asNone</span></tt>, the value you serialize might not round-trip.</p>
<p>Transforming a <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> into YAML character data is done with <aclass="reference external"href="yaml.presenter.html#present,YamlStream,Stream,TagLibrary,PresentationOptions">present</a>. You can choose from multiple presentation styles. <ttclass="docutils literal"><spanclass="pre">psJson</span></tt> is not able to process some features of <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> s, the other styles support all features and are guaranteed to round-trip to the same <ttclass="docutils literal"><spanclass="pre">YamlStream</span></tt> if you parse the generated YAML character stream again.</p>
<h1id="the-document-object-model">The Document Object Model</h1><p>Much like XML, YAML also defines a <em>document object model</em>. If you cannot or do not want to load a YAML character stream to native Nim types, you can instead load it into a <aclass="reference external"href="yaml.dom.html#YamlDocument">YamlDocument</a>. This <ttclass="docutils literal"><spanclass="pre">YamlDocument</span></tt> can also be serialized into a YAML character stream. All tags will be preserved exactly as they are when transforming from and to a <ttclass="docutils literal"><spanclass="pre">YamlDocument</span></tt>. The only important thing to remember is that when a value has no tag, it will get the non-specific tag <ttclass="docutils literal"><spanclass="pre">"!"</span></tt> for quoted scalars and <ttclass="docutils literal"><spanclass="pre">"?"</span></tt> for all other nodes.</p>
<p>While tags are preserved, anchors will be resolved during loading and re-added during serialization. It is allowed for a <ttclass="docutils literal"><spanclass="pre">YamlNode</span></tt> to occur multiple times within a <ttclass="docutils literal"><spanclass="pre">YamlDocument</span></tt>, in which case it will be serialized once and referred to afterwards via aliases.</p>
<p>The document object model is provided for completeness, but you are encouraged to use native Nim types as start- or endpoint instead. That may be significantly faster, as every <ttclass="docutils literal"><spanclass="pre">YamlNode</span></tt> is allocated on the heap and subject to garbage collection. </p>