From 459b345d69532825f21bdcd3e4f92009b0a046dc Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 3 Nov 2019 23:56:52 +0100
Subject: Handled sequences with the Yaml reader in an improved way.

---
 plugins/yaml/Makefile.am         |   1 +
 plugins/yaml/collection.c        | 312 +++++++++++++++++++++++++++++++++
 plugins/yaml/collection.h        |  74 ++++++++
 plugins/yaml/line.c              |  23 +--
 plugins/yaml/line.h              |   4 +
 plugins/yaml/node.c              | 192 +++++++++++++-------
 plugins/yaml/node.h              |  18 +-
 plugins/yaml/python/Makefile.am  |   1 +
 plugins/yaml/python/collection.c | 370 +++++++++++++++++++++++++++++++++++++++
 plugins/yaml/python/collection.h |  45 +++++
 plugins/yaml/python/module.c     |   2 +
 plugins/yaml/python/node.c       | 168 ++++++++++++------
 plugins/yaml/python/reader.c     |  16 +-
 plugins/yaml/python/tree.c       |  99 +++++------
 plugins/yaml/reader.c            |  12 +-
 plugins/yaml/tree.c              | 277 ++++++++++++++---------------
 plugins/yaml/tree.h              |  13 +-
 tests/plugins/yamlrdr.py         | 174 ++++++++++++++----
 18 files changed, 1407 insertions(+), 394 deletions(-)
 create mode 100644 plugins/yaml/collection.c
 create mode 100644 plugins/yaml/collection.h
 create mode 100644 plugins/yaml/python/collection.c
 create mode 100644 plugins/yaml/python/collection.h

diff --git a/plugins/yaml/Makefile.am b/plugins/yaml/Makefile.am
index d7464b8..75e3cc2 100644
--- a/plugins/yaml/Makefile.am
+++ b/plugins/yaml/Makefile.am
@@ -27,6 +27,7 @@ endif
 
 
 libyaml_la_SOURCES =						\
+	collection.h collection.c				\
 	core.h core.c							\
 	line.h line.c							\
 	node.h node.c							\
diff --git a/plugins/yaml/collection.c b/plugins/yaml/collection.c
new file mode 100644
index 0000000..1615fa8
--- /dev/null
+++ b/plugins/yaml/collection.c
@@ -0,0 +1,312 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collection.h - collection de noeuds Yaml
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "collection.h"
+
+
+#include <malloc.h>
+
+
+
+/* Collection de noeuds au format Yaml (instance) */
+struct _GYamlCollection
+{
+    GObject parent;                         /* A laisser en premier        */
+
+    bool is_seq;                            /* Nature de la collection     */
+
+    GYamlNode **nodes;                      /* Sous-noeuds intégrés        */
+    size_t count;                           /* Nombre de ces enfants       */
+
+};
+
+/* Collection de noeuds au format Yaml (classe) */
+struct _GYamlCollectionClass
+{
+    GObjectClass parent;                    /* A laisser en premier        */
+
+};
+
+
+/* Initialise la classe des collections de noeuds Yaml. */
+static void g_yaml_collection_class_init(GYamlCollectionClass *);
+
+/* Initialise une instance de collection de noeuds Yaml. */
+static void g_yaml_collection_init(GYamlCollection *);
+
+/* Supprime toutes les références externes. */
+static void g_yaml_collection_dispose(GYamlCollection *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_yaml_collection_finalize(GYamlCollection *);
+
+
+
+/* Indique le type défini pour une collection de noeuds Yaml. */
+G_DEFINE_TYPE(GYamlCollection, g_yaml_collection, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des collections de noeuds Yaml.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_yaml_collection_class_init(GYamlCollectionClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_collection_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_yaml_collection_finalize;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : collec = instance à initialiser.                             *
+*                                                                             *
+*  Description : Initialise une instance de collection de noeuds Yaml.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_yaml_collection_init(GYamlCollection *collec)
+{
+    collec->is_seq = false;
+
+    collec->nodes = NULL;
+    collec->count = 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : collec = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_yaml_collection_dispose(GYamlCollection *collec)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < collec->count; i++)
+        g_clear_object(&collec->nodes[i]);
+
+    G_OBJECT_CLASS(g_yaml_collection_parent_class)->dispose(G_OBJECT(collec));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : collec = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_yaml_collection_finalize(GYamlCollection *collec)
+{
+    if (collec->nodes != NULL)
+        free(collec->nodes);
+
+    G_OBJECT_CLASS(g_yaml_collection_parent_class)->finalize(G_OBJECT(collec));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : seq = indique la nature de la future collection.             *
+*                                                                             *
+*  Description : Construit une collection de noeuds Yaml.                     *
+*                                                                             *
+*  Retour      : Instance mise en place ou NULL en cas d'échec.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GYamlCollection *g_yaml_collection_new(bool seq)
+{
+    GYamlCollection *result;                /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_YAML_COLLEC, NULL);
+
+    result->is_seq = seq;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : collec = noeud d'arborescence Yaml à consulter.              *
+*                                                                             *
+*  Description : Indique la nature d'une collection Yaml.                     *
+*                                                                             *
+*  Retour      : Nature de la collection.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_yaml_collection_is_sequence(const GYamlCollection *collec)
+{
+    bool result;                            /* Statut à retourner          */
+
+    result = collec->is_seq;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : collec = collection de noeuds Yaml à compléter.              *
+*                node   = noeud à rattacher.                                  *
+*                                                                             *
+*  Description : Ajoute un noeud à une collection de noeuds Yaml.             *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_yaml_collection_add_node(GYamlCollection *collec, GYamlNode *node)
+{
+    collec->nodes = realloc(collec->nodes, ++collec->count * sizeof(GYamlNode *));
+
+    collec->nodes[collec->count - 1] = node;
+    g_object_ref_sink(G_OBJECT(node));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : collec = noeud d'arborescence Yaml à consulter.              *
+*                count  = taille de la liste constituée. [OUT]                *
+*                                                                             *
+*  Description : Fournit la liste des noeuds intégrés dans une collection.    *
+*                                                                             *
+*  Retour      : Enfants d'un noeud issu d'une collection Yaml.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GYamlNode **g_yaml_collection_get_nodes(const GYamlCollection *collec, size_t *count)
+{
+    GYamlNode **result;                     /* Liste à retourner           */
+    size_t i;                               /* Boucle de parcours          */
+
+    *count = collec->count;
+
+    result = malloc(*count * sizeof(GYamlNode *));
+
+    for (i = 0; i < *count; i++)
+    {
+        result[i] = collec->nodes[i];
+        g_object_ref(G_OBJECT(result[i]));
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : collec = noeud d'arborescence Yaml à consulter.              *
+*                path   = chemin d'accès à parcourir.                         *
+*                nodes  = liste de noeuds avec correspondance établie. [OUT]  *
+*                count  = quantité de ces noeuds. [OUT]                       *
+*                                                                             *
+*  Description : Recherche les noeuds correspondant à un chemin.              *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void _g_yaml_collection_find_by_path(const GYamlCollection *collec, const char *path, GYamlNode ***nodes, size_t *count)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < collec->count; i++)
+        _g_yaml_node_find_by_path(collec->nodes[i], path, nodes, count);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : collec = noeud d'arborescence Yaml à consulter.              *
+*                path   = chemin d'accès à parcourir.                         *
+*                nodes  = liste de noeuds avec correspondance établie. [OUT]  *
+*                count  = quantité de ces noeuds. [OUT]                       *
+*                                                                             *
+*  Description : Recherche les noeuds correspondant à un chemin.              *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_yaml_collection_find_by_path(const GYamlCollection *collec, const char *path, GYamlNode ***nodes, size_t *count)
+{
+    *nodes = NULL;
+    *count = 0;
+
+    _g_yaml_collection_find_by_path(collec, path, nodes, count);
+
+}
diff --git a/plugins/yaml/collection.h b/plugins/yaml/collection.h
new file mode 100644
index 0000000..71a2b46
--- /dev/null
+++ b/plugins/yaml/collection.h
@@ -0,0 +1,74 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collection.h - prototypes pour une collection de noeuds Yaml
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_YAML_COLLECTION_H
+#define PLUGINS_YAML_COLLECTION_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "node.h"
+
+
+
+#define G_TYPE_YAML_COLLEC            g_yaml_collection_get_type()
+#define G_YAML_COLLEC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_COLLEC, GYamlCollection))
+#define G_IS_YAML_COLLEC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_YAML_COLLEC))
+#define G_YAML_COLLEC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_YAML_COLLEC, GYamlCollectionClass))
+#define G_IS_YAML_COLLEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_YAML_COLLEC))
+#define G_YAML_COLLEC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_COLLEC, GYamlCollectionClass))
+
+
+/* Collection de noeuds au format Yaml (instance) */
+typedef struct _GYamlCollection GYamlCollection;
+
+/* Collection de noeuds au format Yaml (classe) */
+typedef struct _GYamlCollectionClass GYamlCollectionClass;
+
+
+/* Indique le type défini pour une collection de noeuds Yaml. */
+GType g_yaml_collection_get_type(void);
+
+/* Construit une collection de noeuds Yaml. */
+GYamlCollection *g_yaml_collection_new(bool);
+
+/* Indique la nature d'une collection Yaml. */
+bool g_yaml_collection_is_sequence(const GYamlCollection *);
+
+/* Ajoute un noeud à une collection de noeuds Yaml. */
+void g_yaml_collection_add_node(GYamlCollection *, GYamlNode *);
+
+/* Fournit la liste des noeuds intégrés dans une collection. */
+GYamlNode **g_yaml_collection_get_nodes(const GYamlCollection *, size_t *);
+
+/* Recherche les noeuds correspondant à un chemin. */
+void g_yaml_collection_find_by_path(const GYamlCollection *, const char *, GYamlNode ***, size_t *);
+
+/* Recherche les noeuds correspondant à un chemin. */
+void _g_yaml_collection_find_by_path(const GYamlCollection *, const char *, GYamlNode ***, size_t *);
+
+
+
+#endif  /* PLUGINS_YAML_COLLECTION_H */
diff --git a/plugins/yaml/line.c b/plugins/yaml/line.c
index cd993ee..26a1012 100644
--- a/plugins/yaml/line.c
+++ b/plugins/yaml/line.c
@@ -203,19 +203,20 @@ GYamlLine *g_yaml_line_new(const char *raw, size_t number)
 
     for (iter = result->raw; *iter != '\0'; iter++)
     {
-        if (*iter != ' ' && *iter != '-')
+        if (*iter != ' ')
             break;
 
         result->indent++;
 
-        if (*iter == '-')
-        {
-            if (result->is_list_item)
-                goto format_error;
+    }
 
-            result->is_list_item = true;
+    if (*iter == '-')
+    {
+        result->is_list_item = true;
 
-        }
+        for (iter++; *iter != '\0'; iter++)
+            if (*iter != ' ')
+                break;
 
     }
 
@@ -280,14 +281,6 @@ GYamlLine *g_yaml_line_new(const char *raw, size_t number)
 
     return result;
 
- format_error:
-
-    log_variadic_message(LMT_ERROR, "Yaml format error at line %zu", number);
-
-    g_object_unref(G_OBJECT(result));
-
-    return NULL;
-
 }
 
 
diff --git a/plugins/yaml/line.h b/plugins/yaml/line.h
index b959272..00f019e 100644
--- a/plugins/yaml/line.h
+++ b/plugins/yaml/line.h
@@ -68,4 +68,8 @@ const char *g_yaml_line_get_value(const GYamlLine *);
 
 
 
+#define g_yaml_line_get_number(l) 0
+
+
+
 #endif  /* PLUGINS_YAML_LINE_H */
diff --git a/plugins/yaml/node.c b/plugins/yaml/node.c
index b0229c0..57eb3d2 100644
--- a/plugins/yaml/node.c
+++ b/plugins/yaml/node.c
@@ -28,6 +28,9 @@
 #include <string.h>
 
 
+#include "collection.h"
+
+
 
 /* Noeud d'une arborescence au format Yaml (instance) */
 struct _GYamlNode
@@ -35,9 +38,7 @@ struct _GYamlNode
     GObject parent;                         /* A laisser en premier        */
 
     GYamlLine *key;                         /* Clef principale du noeud    */
-
-    GYamlNode **children;                   /* Sous-noeuds intégrés        */
-    size_t count;                           /* Nombre de ces enfants       */
+    GYamlCollection *collection;            /* Collection de noeuds        */
 
 };
 
@@ -106,9 +107,7 @@ static void g_yaml_node_class_init(GYamlNodeClass *klass)
 static void g_yaml_node_init(GYamlNode *node)
 {
     node->key = NULL;
-
-    node->children = NULL;
-    node->count = 0;
+    node->collection = NULL;
 
 }
 
@@ -127,12 +126,9 @@ static void g_yaml_node_init(GYamlNode *node)
 
 static void g_yaml_node_dispose(GYamlNode *node)
 {
-    size_t i;                               /* Boucle de parcours          */
-
     g_clear_object(&node->key);
 
-    for (i = 0; i < node->count; i++)
-        g_clear_object(&node->children[i]);
+    g_clear_object(&node->collection);
 
     G_OBJECT_CLASS(g_yaml_node_parent_class)->dispose(G_OBJECT(node));
 
@@ -153,9 +149,6 @@ static void g_yaml_node_dispose(GYamlNode *node)
 
 static void g_yaml_node_finalize(GYamlNode *node)
 {
-    if (node->children != NULL)
-        free(node->children);
-
     G_OBJECT_CLASS(g_yaml_node_parent_class)->finalize(G_OBJECT(node));
 
 }
@@ -179,8 +172,18 @@ GYamlNode *g_yaml_node_new(GYamlLine *key)
 
     result = g_object_new(G_TYPE_YAML_NODE, NULL);
 
-    result->key = key;
-    g_object_ref(G_OBJECT(key));
+    /**
+     * Le paragraphe "3.2.2.1. Keys Order" des spécifications précise
+     * qu'une séquence n'est qu'un noeud sans correspondance clef/valeur.
+     *
+     * Cette situation doit donc être prise en compte.
+     */
+
+    if (key != NULL)
+    {
+        result->key = key;
+        g_object_ref(G_OBJECT(key));
+    }
 
     return result;
 
@@ -189,7 +192,7 @@ GYamlNode *g_yaml_node_new(GYamlLine *key)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node  = noeud d'arborescence Yaml à consulter.               *
+*  Paramètres  : node = noeud d'arborescence Yaml à consulter.                *
 *                                                                             *
 *  Description : Fournit la ligne principale associée à un noeud.             *
 *                                                                             *
@@ -205,7 +208,8 @@ GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *node)
 
     result = node->key;
 
-    g_object_ref(G_OBJECT(result));
+    if (result != NULL)
+        g_object_ref(G_OBJECT(result));
 
     return result;
 
@@ -214,10 +218,10 @@ GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *node)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node  = noeud d'arborescence Yaml à compléter.               *
-*                child = noeud à rattacher.                                   *
+*  Paramètres  : node   = noeud d'arborescence Yaml à compléter.              *
+*                collec = collection de noeuds Yaml.                          *
 *                                                                             *
-*  Description : Ajoute un noeud à un noeud d'une arborescence Yaml.          *
+*  Description : Attache une collection de noeuds Yaml à un noeud.            *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -225,43 +229,36 @@ GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *node)
 *                                                                             *
 ******************************************************************************/
 
-void g_yaml_node_add_child(GYamlNode *node, GYamlNode *child)
+void g_yaml_node_set_collection(GYamlNode *node, GYamlCollection *collec)
 {
-    node->children = realloc(node->children, ++node->count * sizeof(GYamlNode *));
+    g_clear_object(&node->collection);
 
-    node->children[node->count - 1] = child;
-    g_object_ref_sink(G_OBJECT(child));
+    g_object_ref_sink(G_OBJECT(collec));
+    node->collection = collec;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node  = noeud d'arborescence Yaml à consulter.               *
-*                count = taille de la liste constituée. [OUT]                 *
+*  Paramètres  : node = noeud d'arborescence Yaml à consulter.                *
 *                                                                             *
-*  Description : Fournit la liste des noeuds intégrés dans un noeud Yaml.     *
+*  Description : Fournit une éventuelle collection rattachée à un noeud.      *
 *                                                                             *
-*  Retour      : Enfants d'un noeud issu d'une arborescence Yaml.             *
+*  Retour      : Collection de noeuds Yaml ou NULL.                           *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GYamlNode **g_yaml_node_get_children(const GYamlNode *node, size_t *count)
+GYamlCollection *g_yaml_node_get_collection(const GYamlNode *node)
 {
-    GYamlNode **result;                     /* Liste à retourner           */
-    size_t i;                               /* Boucle de parcours          */
+    GYamlCollection *result;                /* Collection à renvoyer       */
 
-    *count = node->count;
+    result = node->collection;
 
-    result = malloc(*count * sizeof(GYamlNode *));
-
-    for (i = 0; i < *count; i++)
-    {
-        result[i] = node->children[i];
-        g_object_ref(G_OBJECT(result[i]));
-    }
+    if (result != NULL)
+        g_object_ref(G_OBJECT(result));
 
     return result;
 
@@ -270,66 +267,125 @@ GYamlNode **g_yaml_node_get_children(const GYamlNode *node, size_t *count)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node = noeud d'arborescence Yaml à consulter.                *
-*                path = chemin d'accès à parcourir.                           *
+*  Paramètres  : node  = noeud d'arborescence Yaml à consulter.               *
+*                path  = chemin d'accès à parcourir.                          *
+*                nodes = liste de noeuds avec correspondance établie. [OUT]   *
+*                count = quantité de ces noeuds. [OUT]                        *
 *                                                                             *
-*  Description : Recherche le noeud correspondant à un chemin.                *
+*  Description : Recherche les noeuds correspondant à un chemin.              *
 *                                                                             *
-*  Retour      : Eventuel noeud trouvé ou NULL si aucun.                      *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GYamlNode *g_yaml_node_find_node_by_path(GYamlNode *node, const char *path)
+void _g_yaml_node_find_by_path(GYamlNode *node, const char *path, GYamlNode ***nodes, size_t *count)
 {
-    GYamlNode *result;                      /* Trouvaille à retourner      */
+    GYamlLine *line;                        /* Ligne Yaml liée au noeud    */
+    const char *key;                        /* Clef associée au noeud      */
+    bool matched;                           /* Correspondance établie ?    */
     char *next;                             /* Prochaine partie du chemin  */
     size_t cmplen;                          /* Etendue de la comparaison   */
-    size_t i;                               /* Boucle de parcours          */
-    GYamlLine *line;                        /* Ligne Yaml d'un enfant      */
-    const char *key;                        /* Clef d'un noeud             */
     int ret;                                /* Bilan d'une comparaison     */
+    GYamlCollection *collec;                /* Collection de noeuds        */
 
-    result = NULL;
+    if (path[0] == '/')
+        path++;
 
-    if (path[0] == '\0')
-        result = node;
+    /* Correspondance au niveau du noeud ? */
 
-    else if (path[0] == '/')
-    {
-        next = strchr(path + 1, '/');
+    line = g_yaml_node_get_yaml_line(node);
 
-        cmplen = (next == NULL ? strlen(path + 1) : next - path - 1);
+    if (line != NULL)
+    {
+        key = g_yaml_line_get_key(line);
 
-        if (cmplen == 0)
-            result = node;
+        if (path[0] == '\0')
+            matched = true;
 
-        for (i = 0; i < node->count && result == NULL; i++)
+        else
         {
-            line = g_yaml_node_get_yaml_line(node->children[i]);
+            next = strchr(path, '/');
+
+            cmplen = (next == NULL ? strlen(path) : next - path);
+
+            if (cmplen == 0)
+                goto cont;
 
-            key = g_yaml_line_get_key(line);
+            ret = strncmp(path, key, cmplen);
 
-            ret = strncmp(path + 1, key, cmplen);
+            if (ret != 0)
+                goto done;
 
-            if (ret == 0)
+            else
             {
-                if (next != NULL)
-                    result = g_yaml_node_find_node_by_path(node->children[i], next);
+                if (next == NULL)
+                    matched = true;
 
                 else
-                    result = node->children[i];
+                {
+                    path += cmplen;
+                    goto cont;
+                }
 
             }
 
         }
 
+        if (matched)
+        {
+            *nodes = realloc(*nodes, ++(*count) * sizeof(GYamlNode **));
+
+            g_object_ref(G_OBJECT(node));
+            (*nodes)[*count - 1] = node;
+
+            goto done;
+
+        }
+
     }
 
-    if (result != NULL)
-        g_object_ref(G_OBJECT(result));
+ cont:
 
-    return result;
+    collec = g_yaml_node_get_collection(node);
+
+    if (collec != NULL)
+    {
+        _g_yaml_collection_find_by_path(collec, path, nodes, count);
+
+        g_object_unref(G_OBJECT(collec));
+
+    }
+
+ done:
+
+    if (line != NULL)
+        g_object_unref(G_OBJECT(line));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node  = noeud d'arborescence Yaml à consulter.               *
+*                path  = chemin d'accès à parcourir.                          *
+*                nodes = liste de noeuds avec correspondance établie. [OUT]   *
+*                count = quantité de ces noeuds. [OUT]                        *
+*                                                                             *
+*  Description : Recherche les noeuds correspondant à un chemin.              *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_yaml_node_find_by_path(GYamlNode *node, const char *path, GYamlNode ***nodes, size_t *count)
+{
+    *nodes = NULL;
+    *count = 0;
+
+    _g_yaml_node_find_by_path(node, path, nodes, count);
 
 }
diff --git a/plugins/yaml/node.h b/plugins/yaml/node.h
index 582fa58..f1bbb23 100644
--- a/plugins/yaml/node.h
+++ b/plugins/yaml/node.h
@@ -32,6 +32,9 @@
 #include "line.h"
 
 
+/* Depuis collection.h : collection de noeuds au format Yaml (instance) */
+typedef struct _GYamlCollection GYamlCollection;
+
 
 #define G_TYPE_YAML_NODE            g_yaml_node_get_type()
 #define G_YAML_NODE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_NODE, GYamlNode))
@@ -57,14 +60,17 @@ GYamlNode *g_yaml_node_new(GYamlLine *);
 /* Fournit la ligne principale associée à un noeud. */
 GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *);
 
-/* Ajoute un noeud à un noeud d'une arborescence Yaml. */
-void g_yaml_node_add_child(GYamlNode *, GYamlNode *);
+/* Attache une collection de noeuds Yaml à un noeud. */
+void g_yaml_node_set_collection(GYamlNode *, GYamlCollection *);
+
+/* Fournit une éventuelle collection rattachée à un noeud. */
+GYamlCollection *g_yaml_node_get_collection(const GYamlNode *);
 
-/* Fournit la liste des noeuds intégrés dans un noeud Yaml. */
-GYamlNode **g_yaml_node_get_children(const GYamlNode *, size_t *);
+/* Recherche les noeuds correspondant à un chemin. */
+void _g_yaml_node_find_by_path(GYamlNode *, const char *, GYamlNode ***, size_t *);
 
-/* Recherche le noeud correspondant à un chemin. */
-GYamlNode *g_yaml_node_find_node_by_path(GYamlNode *, const char *);
+/* Recherche les noeuds correspondant à un chemin. */
+void g_yaml_node_find_by_path(GYamlNode *, const char *, GYamlNode ***, size_t *);
 
 
 
diff --git a/plugins/yaml/python/Makefile.am b/plugins/yaml/python/Makefile.am
index 8a8d960..a750343 100644
--- a/plugins/yaml/python/Makefile.am
+++ b/plugins/yaml/python/Makefile.am
@@ -2,6 +2,7 @@
 noinst_LTLIBRARIES = libyamlpython.la
 
 libyamlpython_la_SOURCES =					\
+	collection.h collection.c				\
 	line.h line.c							\
 	module.h module.c						\
 	node.h node.c							\
diff --git a/plugins/yaml/python/collection.c b/plugins/yaml/python/collection.c
new file mode 100644
index 0000000..7166784
--- /dev/null
+++ b/plugins/yaml/python/collection.c
@@ -0,0 +1,370 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collection.c - équivalent Python du fichier "plugins/yaml/collection.c"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "collection.h"
+
+
+#include <pygobject.h>
+
+
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../collection.h"
+
+
+
+/* Crée un nouvel objet Python de type 'YamlCollection'. */
+static PyObject *py_yaml_collection_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Recherche les noeuds correspondant à un chemin. */
+static PyObject *py_yaml_collection_find_by_path(PyObject *, PyObject *);
+
+/* Indique la nature d'une collection Yaml. */
+static PyObject *py_yaml_collection_is_sequence(PyObject *, void *);
+
+/* Fournit la liste des noeuds intégrés dans une collection. */
+static PyObject *py_yaml_collection_get_nodes(PyObject *, void *);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type de l'objet à instancier.                         *
+*                args = arguments fournis à l'appel.                          *
+*                kwds = arguments de type key=val fournis.                    *
+*                                                                             *
+*  Description : Crée un nouvel objet Python de type 'YamlCollection'.        *
+*                                                                             *
+*  Retour      : Instance Python mise en place.                               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_yaml_collection_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    PyObject *result;                       /* Instance à retourner        */
+    int seq;                                /* Indicateur de type          */
+    int ret;                                /* Bilan de lecture des args.  */
+    GYamlCollection *collec;                /* Création GLib à transmettre */
+
+#define YAML_COLLECTION_DOC                                                         \
+    "YamlCollection handle a collection of Yaml nodes.\n"                           \
+    "\n"                                                                            \
+    "Instances can be created using the following constructor:\n"                   \
+    "\n"                                                                            \
+    "    YamlCollection(seq=False)\n"                                               \
+    "\n"                                                                            \
+    "Where seq defines if the collection will be a sequence or a mapping of nodes."
+
+    ret = PyArg_ParseTuple(args, "p", &seq);
+    if (!ret) return NULL;
+
+    collec = g_yaml_collection_new(seq);
+
+    g_object_ref_sink(G_OBJECT(collec));
+    result = pygobject_new(G_OBJECT(collec));
+    g_object_unref(collec);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = variable non utilisée ici.                            *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Recherche les noeuds correspondant à un chemin.              *
+*                                                                             *
+*  Retour      : Liste de noeuds trouvés, éventuellement vide.                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_yaml_collection_find_by_path(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Instance à retourner        */
+    const char *path;                       /* Chemin d'accès à traiter    */
+    int ret;                                /* Bilan de lecture des args.  */
+    GYamlCollection *collec;                /* Version GLib du type        */
+    GYamlNode **found;                      /* Créations GLib à transmettre*/
+    size_t count;                           /* Quantité de trouvailles     */
+    size_t i;                               /* Boucle de parcours          */
+
+#define YAML_COLLECTION_FIND_BY_PATH PYTHON_METHOD_DEF                      \
+(                                                                           \
+    find_by_path, "path",                                                   \
+    METH_VARARGS, py_yaml_collection,                                       \
+    "Find nodes from a Yaml node using a path.\n"                           \
+    "\n"                                                                    \
+    "Paths are node keys separated by '/', such as '/my/path/to/node'."     \
+)
+
+    ret = PyArg_ParseTuple(args, "s", &path);
+    if (!ret) return NULL;
+
+    collec = G_YAML_COLLEC(pygobject_get(self));
+
+    g_yaml_collection_find_by_path(collec, path, &found, &count);
+
+    result = PyTuple_New(count);
+
+    for (i = 0; i < count; i++)
+    {
+#ifndef NDEBUG
+        ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+        assert(ret == 0);
+#else
+        PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+#endif
+
+        g_object_unref(G_OBJECT(found[i]));
+
+    }
+
+    if (found != NULL)
+        free(found);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Fournit la liste des noeuds intégrés dans une collection.    *
+*                                                                             *
+*  Retour      : Enfants d'un noeud issu d'une collection Yaml.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_yaml_collection_get_nodes(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GYamlCollection *collec;                /* Version GLib du type        */
+    size_t count;                           /* Quantité de noeuds à traiter*/
+    GYamlNode **nodes;                      /* Liste des noeuds à la racine*/
+    size_t i;                               /* Boucle de parcours          */
+#ifndef NDEBUG
+    int ret;                                /* Bilan d'une insertion       */
+#endif
+
+#define YAML_COLLECTION_NODES_ATTRIB PYTHON_GET_DEF_FULL    \
+(                                                           \
+    nodes, py_yaml_collection,                              \
+    "List of nodes contained in the current collection."    \
+)
+
+    collec = G_YAML_COLLEC(pygobject_get(self));
+
+    nodes = g_yaml_collection_get_nodes(collec, &count);
+
+    result = PyTuple_New(count);
+
+    for (i = 0; i < count; i++)
+    {
+#ifndef NDEBUG
+        ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(nodes[i])));
+        assert(ret == 0);
+#else
+        PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(nodes[i])));
+#endif
+
+        g_object_unref(G_OBJECT(nodes[i]));
+
+    }
+
+    free(nodes);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = objet Python concerné par l'appel.                 *
+*                closure = non utilisé ici.                                   *
+*                                                                             *
+*  Description : Indique la nature d'une collection Yaml.                     *
+*                                                                             *
+*  Retour      : Nature de la collection.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_yaml_collection_is_sequence(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Résultat à retourner        */
+    GYamlCollection *collec;                /* Version GLib du type        */
+    bool status;                            /* Bilan de consultation       */
+
+#define YAML_COLLECTION_IS_SEQUENCE_ATTRIB PYTHON_IS_DEF_FULL           \
+(                                                                       \
+    sequence, py_yaml_collection,                                       \
+    "Nature of the collection: True is the collection is a sequence,"   \
+    " False if it is a mapping of \"key: value\" nodes."                \
+)
+
+    collec = G_YAML_COLLEC(pygobject_get(self));
+
+    status = g_yaml_collection_is_sequence(collec);
+
+    result = status ? Py_True : Py_False;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Fournit un accès à une définition de type à diffuser.        *
+*                                                                             *
+*  Retour      : Définition d'objet pour Python.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyTypeObject *get_python_yaml_collection_type(void)
+{
+    static PyMethodDef py_yaml_collection_methods[] = {
+        YAML_COLLECTION_FIND_BY_PATH,
+        { NULL }
+    };
+
+    static PyGetSetDef py_yaml_collection_getseters[] = {
+        YAML_COLLECTION_IS_SEQUENCE_ATTRIB,
+        YAML_COLLECTION_NODES_ATTRIB,
+        { NULL }
+    };
+
+    static PyTypeObject py_yaml_collection_type = {
+
+        PyVarObject_HEAD_INIT(NULL, 0)
+
+        .tp_name        = "pychrysalide.plugins.yaml.YamlCollection",
+        .tp_basicsize   = sizeof(PyGObject),
+
+        .tp_flags       = Py_TPFLAGS_DEFAULT,
+
+        .tp_doc         = YAML_COLLECTION_DOC,
+
+        .tp_methods     = py_yaml_collection_methods,
+        .tp_getset      = py_yaml_collection_getseters,
+        .tp_new         = py_yaml_collection_new
+
+    };
+
+    return &py_yaml_collection_type;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : module = module dont la définition est à compléter.          *
+*                                                                             *
+*  Description : Prend en charge l'objet 'pychrysalide.....YamlCollection.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool register_python_yaml_collection(PyObject *module)
+{
+    PyTypeObject *type;                     /* Type Python 'YamlCollection'*/
+    PyObject *dict;                         /* Dictionnaire du module      */
+
+    type = get_python_yaml_collection_type();
+
+    dict = PyModule_GetDict(module);
+
+    if (!register_class_for_pygobject(dict, G_TYPE_YAML_COLLEC, type, &PyGObject_Type))
+        return false;
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
+*                dst = destination des valeurs récupérées en cas de succès.   *
+*                                                                             *
+*  Description : Tente de convertir en collection de noeuds de format Yaml.   *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_yaml_collection(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_collection_type());
+
+    switch (result)
+    {
+        case -1:
+            /* L'exception est déjà fixée par Python */
+            result = 0;
+            break;
+
+        case 0:
+            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml collection");
+            break;
+
+        case 1:
+            *((GYamlCollection **)dst) = G_YAML_COLLEC(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/yaml/python/collection.h b/plugins/yaml/python/collection.h
new file mode 100644
index 0000000..ab2caba
--- /dev/null
+++ b/plugins/yaml/python/collection.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collection.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/collection.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _PLUGINS_YAML_PYTHON_COLLECTION_H
+#define _PLUGINS_YAML_PYTHON_COLLECTION_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_yaml_collection_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlCollection'. */
+bool register_python_yaml_collection(PyObject *);
+
+/* Tente de convertir en collection de noeuds de format Yaml. */
+int convert_to_yaml_collection(PyObject *, void *);
+
+
+
+#endif  /* _PLUGINS_YAML_PYTHON_COLLECTION_H */
diff --git a/plugins/yaml/python/module.c b/plugins/yaml/python/module.c
index 542a551..2a4401e 100644
--- a/plugins/yaml/python/module.c
+++ b/plugins/yaml/python/module.c
@@ -33,6 +33,7 @@
 #include <plugins/pychrysalide/helpers.h>
 
 
+#include "collection.h"
 #include "line.h"
 #include "node.h"
 #include "reader.h"
@@ -108,6 +109,7 @@ bool populate_yaml_module(void)
 
     module = get_access_to_python_module("pychrysalide.plugins.yaml");
 
+    if (result) result = register_python_yaml_collection(module);
     if (result) result = register_python_yaml_line(module);
     if (result) result = register_python_yaml_node(module);
     if (result) result = register_python_yaml_reader(module);
diff --git a/plugins/yaml/python/node.c b/plugins/yaml/python/node.c
index d1aabee..f2984d1 100644
--- a/plugins/yaml/python/node.c
+++ b/plugins/yaml/python/node.c
@@ -31,6 +31,7 @@
 #include <plugins/pychrysalide/helpers.h>
 
 
+#include "collection.h"
 #include "line.h"
 #include "../node.h"
 
@@ -39,14 +40,17 @@
 /* Crée un nouvel objet Python de type 'YamlNode'. */
 static PyObject *py_yaml_node_new(PyTypeObject *, PyObject *, PyObject *);
 
-/* Recherche le noeud correspondant à un chemin. */
-static PyObject *py_yaml_node_find_node_by_path(PyObject *, PyObject *);
+/* Recherche les noeuds correspondant à un chemin. */
+static PyObject *py_yaml_node_find_by_path(PyObject *, PyObject *);
 
 /* Fournit la ligne principale associée à un noeud. */
 static PyObject *py_yaml_node_get_yaml_line(PyObject *, void *);
 
-/* Fournit la liste des noeuds intégrés dans un noeud Yaml. */
-static PyObject *py_yaml_node_get_children(PyObject *, void *);
+/* Attache une collection de noeuds Yaml à un noeud. */
+static int py_yaml_node_set_collection(PyObject *, PyObject *, void *);
+
+/* Fournit une éventuelle collection rattachée à un noeud. */
+static PyObject *py_yaml_node_get_collection(PyObject *, void *);
 
 
 
@@ -99,27 +103,29 @@ static PyObject *py_yaml_node_new(PyTypeObject *type, PyObject *args, PyObject *
 *  Paramètres  : self = variable non utilisée ici.                            *
 *                args = arguments fournis à l'appel.                          *
 *                                                                             *
-*  Description : Recherche le noeud correspondant à un chemin.                *
+*  Description : Recherche les noeuds correspondant à un chemin.              *
 *                                                                             *
-*  Retour      : Eventuel noeud trouvé ou NULL si aucun.                      *
+*  Retour      : Liste de noeuds trouvés, éventuellement vide.                *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_yaml_node_find_node_by_path(PyObject *self, PyObject *args)
+static PyObject *py_yaml_node_find_by_path(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Instance à retourner        */
     const char *path;                       /* Chemin d'accès à traiter    */
     int ret;                                /* Bilan de lecture des args.  */
-    GYamlNode *node;                        /* Version GLib du type        */
-    GYamlNode *found;                       /* Création GLib à transmettre */
+    GYamlNode *node;                        /* Version GLib du noeud       */
+    GYamlNode **found;                      /* Créations GLib à transmettre*/
+    size_t count;                           /* Quantité de trouvailles     */
+    size_t i;                               /* Boucle de parcours          */
 
 #define YAML_NODE_FIND_BY_PATH PYTHON_METHOD_DEF                            \
 (                                                                           \
-    find_node_by_path, "path",                                              \
+    find_by_path, "path",                                                   \
     METH_VARARGS, py_yaml_node,                                             \
-    "Find a child node in a Yaml node by its path.\n"                       \
+    "Find nodes from a Yaml node using a path.\n"                           \
     "\n"                                                                    \
     "Paths are node keys separated by '/', such as '/my/path/to/node'."     \
 )
@@ -129,20 +135,26 @@ static PyObject *py_yaml_node_find_node_by_path(PyObject *self, PyObject *args)
 
     node = G_YAML_NODE(pygobject_get(self));
 
-    found = g_yaml_node_find_node_by_path(node, path);
+    g_yaml_node_find_by_path(node, path, &found, &count);
 
-    if (found == NULL)
-    {
-        result = Py_None;
-        Py_INCREF(result);
-    }
+    result = PyTuple_New(count);
 
-    else
+    for (i = 0; i < count; i++)
     {
-        result = pygobject_new(G_OBJECT(found));
-        g_object_unref(found);
+#ifndef NDEBUG
+        ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+        assert(ret == 0);
+#else
+        PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+#endif
+
+        g_object_unref(G_OBJECT(found[i]));
+
     }
 
+    if (found != NULL)
+        free(found);
+
     return result;
 
 }
@@ -164,7 +176,7 @@ static PyObject *py_yaml_node_find_node_by_path(PyObject *self, PyObject *args)
 static PyObject *py_yaml_node_get_yaml_line(PyObject *self, void *closure)
 {
     PyObject *result;                       /* Résultat à retourner        */
-    GYamlNode *node;                        /* Version GLib du type        */
+    GYamlNode *node;                        /* Version GLib du noeud       */
     GYamlLine *line;                        /* Line Yaml associée          */
 
 #define YAML_NODE_YAML_LINE_ATTRIB PYTHON_GET_DEF_FULL      \
@@ -177,9 +189,65 @@ static PyObject *py_yaml_node_get_yaml_line(PyObject *self, void *closure)
 
     line = g_yaml_node_get_yaml_line(node);
 
-    result = pygobject_new(G_OBJECT(line));
+    if (line == NULL)
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+    else
+    {
+        result = pygobject_new(G_OBJECT(line));
+        g_object_unref(G_OBJECT(line));
+    }
+
+    return result;
+
+}
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = contenu binaire à manipuler.                       *
+*                value   = collection de noeuds Yaml.                         *
+*                closure = adresse non utilisée ici.                          *
+*                                                                             *
+*  Description : Attache une collection de noeuds Yaml à un noeud.            *
+*                                                                             *
+*  Retour      : Jeu d'attributs liés au contenu courant.                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_yaml_node_set_collection(PyObject *self, PyObject *value, void *closure)
+{
+    int result;                             /* Bilan à renvoyer            */
+    GYamlNode *node;                        /* Version GLib du noeud       */
+    GYamlCollection *collec;                /* Version GLib de la valeur   */
+
+    node = G_YAML_NODE(pygobject_get(self));
 
-    g_object_unref(G_OBJECT(line));
+    if (value == Py_None)
+    {
+        g_yaml_node_set_collection(node, NULL);
+        result = 0;
+    }
+
+    else
+    {
+        if (!convert_to_yaml_collection(value, &collec))
+            result = -1;
+
+        else
+        {
+            g_yaml_node_set_collection(node, collec);
+            result = 0;
+        }
+
+    }
 
     return result;
 
@@ -188,54 +256,44 @@ static PyObject *py_yaml_node_get_yaml_line(PyObject *self, void *closure)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self    = objet Python concerné par l'appel.                 *
-*                closure = non utilisé ici.                                   *
+*  Paramètres  : self    = contenu binaire à manipuler.                       *
+*                closure = adresse non utilisée ici.                          *
 *                                                                             *
-*  Description : Fournit la liste des noeuds intégrés dans un noeud Yaml.     *
+*  Description : Fournit une éventuelle collection rattachée à un noeud.      *
 *                                                                             *
-*  Retour      : Enfants d'un noeud issu d'une arborescence Yaml.             *
+*  Retour      : Collection de noeuds Yaml ou None.                           *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_yaml_node_get_children(PyObject *self, void *closure)
+static PyObject *py_yaml_node_get_collection(PyObject *self, void *closure)
 {
-    PyObject *result;                       /* Résultat à retourner        */
-    GYamlNode *node;                        /* Version GLib du type        */
-    size_t count;                           /* Quantité de noeuds à traiter*/
-    GYamlNode **nodes;                      /* Liste des noeuds à la racine*/
-    size_t i;                               /* Boucle de parcours          */
-#ifndef NDEBUG
-    int ret;                                /* Bilan d'une insertion       */
-#endif
+    PyObject *result;                       /* Instance à retourner        */
+    GYamlNode *node;                        /* Version GLib du noeud       */
+    GYamlCollection *collec;                /* Collection à transmettre    */
 
-#define YAML_NODE_CHILDREN_ATTRIB PYTHON_GET_DEF_FULL           \
-(                                                               \
-    children, py_yaml_node,                                     \
-    "List of nodes which are children of the current node."     \
+#define YAML_NODE_COLLECTION_ATTRIB PYTHON_GETSET_DEF_FULL                      \
+(                                                                               \
+    collection, py_yaml_node,                                                   \
+    "Provide or define the collection of nodes attached to another Yaml node."  \
 )
 
     node = G_YAML_NODE(pygobject_get(self));
 
-    nodes = g_yaml_node_get_children(node, &count);
+    collec = g_yaml_node_get_collection(node);
 
-    result = PyTuple_New(count);
-
-    for (i = 0; i < count; i++)
+    if (collec == NULL)
     {
-#ifndef NDEBUG
-        ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(nodes[i])));
-        assert(ret == 0);
-#else
-        PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(nodes[i])));
-#endif
-
-        g_object_unref(G_OBJECT(nodes[i]));
-
+        result = Py_None;
+        Py_INCREF(result);
     }
 
-    free(nodes);
+    else
+    {
+        result = pygobject_new(G_OBJECT(collec));
+        g_object_unref(collec);
+    }
 
     return result;
 
@@ -263,7 +321,7 @@ PyTypeObject *get_python_yaml_node_type(void)
 
     static PyGetSetDef py_yaml_node_getseters[] = {
         YAML_NODE_YAML_LINE_ATTRIB,
-        YAML_NODE_CHILDREN_ATTRIB,
+        YAML_NODE_COLLECTION_ATTRIB,
         { NULL }
     };
 
diff --git a/plugins/yaml/python/reader.c b/plugins/yaml/python/reader.c
index 43db6bb..809ece2 100644
--- a/plugins/yaml/python/reader.c
+++ b/plugins/yaml/python/reader.c
@@ -208,7 +208,8 @@ static PyObject *py_yaml_reader_get_lines(PyObject *self, void *closure)
 
     }
 
-    free(lines);
+    if (lines != NULL)
+        free(lines);
 
     return result;
 
@@ -244,9 +245,16 @@ static PyObject *py_yaml_reader_get_tree(PyObject *self, void *closure)
 
     tree = g_yaml_reader_get_tree(reader);
 
-    result = pygobject_new(G_OBJECT(tree));
-
-    g_object_unref(G_OBJECT(tree));
+    if (tree == NULL)
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+    else
+    {
+        result = pygobject_new(G_OBJECT(tree));
+        g_object_unref(G_OBJECT(tree));
+    }
 
     return result;
 
diff --git a/plugins/yaml/python/tree.c b/plugins/yaml/python/tree.c
index 9e1a2a3..eeab3de 100644
--- a/plugins/yaml/python/tree.c
+++ b/plugins/yaml/python/tree.c
@@ -40,11 +40,11 @@
 /* Crée un nouvel objet Python de type 'YamlTree'. */
 static PyObject *py_yaml_tree_new(PyTypeObject *, PyObject *, PyObject *);
 
-/* Recherche le noeud correspondant à un chemin. */
-static PyObject *py_yaml_tree_find_node_by_path(PyObject *, PyObject *);
+/* Recherche les noeuds correspondant à un chemin. */
+static PyObject *py_yaml_tree_find_by_path(PyObject *, PyObject *);
 
-/* Fournit la liste des premiers noeuds de l'arborescence Yaml. */
-static PyObject *py_yaml_tree_get_root_nodes(PyObject *, void *);
+/* Fournit le noeud constituant la racine d'arborescence Yaml. */
+static PyObject *py_yaml_tree_get_root(PyObject *, void *);
 
 
 
@@ -65,7 +65,6 @@ static PyObject *py_yaml_tree_get_root_nodes(PyObject *, void *);
 static PyObject *py_yaml_tree_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
     PyObject *result;                       /* Instance à retourner        */
-    Py_ssize_t indent;                      /* Indice de ligne associée    */
     PyObject *tuple;                        /* Liste de lignes Yaml        */
     int ret;                                /* Bilan de lecture des args.  */
     size_t count;                           /* Nombre d'éléments présents  */
@@ -80,12 +79,11 @@ static PyObject *py_yaml_tree_new(PyTypeObject *type, PyObject *args, PyObject *
     "\n"                                                                    \
     "Instances can be created using the following constructor:\n"           \
     "\n"                                                                    \
-    "    YamlTree(indent, lines)"                                           \
+    "    YamlTree(lines)"                                                   \
     "\n"                                                                    \
-    "Where indent provides the length of a single level of indentation"     \
-    " and lines are a tuple of Yaml lines used to built the tree."
+    "Where lines are a tuple of Yaml lines used to built the tree."
 
-    ret = PyArg_ParseTuple(args, "nO!", &indent, &PyTuple_Type, &tuple);
+    ret = PyArg_ParseTuple(args, "O!", &PyTuple_Type, &tuple);
     if (!ret) return NULL;
 
     count = PyTuple_Size(tuple);
@@ -106,7 +104,7 @@ static PyObject *py_yaml_tree_new(PyTypeObject *type, PyObject *args, PyObject *
 
     }
 
-    tree = g_yaml_tree_new(indent, lines, count);
+    tree = g_yaml_tree_new(lines, count);
 
  arg_error:
 
@@ -141,27 +139,29 @@ static PyObject *py_yaml_tree_new(PyTypeObject *type, PyObject *args, PyObject *
 *  Paramètres  : self = variable non utilisée ici.                            *
 *                args = arguments fournis à l'appel.                          *
 *                                                                             *
-*  Description : Recherche le noeud correspondant à un chemin.                *
+*  Description : Recherche les noeuds correspondant à un chemin.              *
 *                                                                             *
-*  Retour      : Eventuel noeud trouvé ou NULL si aucun.                      *
+*  Retour      : Liste de noeuds trouvés, éventuellement vide.                *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_yaml_tree_find_node_by_path(PyObject *self, PyObject *args)
+static PyObject *py_yaml_tree_find_by_path(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Instance à retourner        */
     const char *path;                       /* Chemin d'accès à traiter    */
     int ret;                                /* Bilan de lecture des args.  */
     GYamlTree *tree;                        /* Version GLib du type        */
-    GYamlNode *found;                       /* Création GLib à transmettre */
+    GYamlNode **found;                      /* Créations GLib à transmettre*/
+    size_t count;                           /* Quantité de trouvailles     */
+    size_t i;                               /* Boucle de parcours          */
 
 #define YAML_TREE_FIND_BY_PATH PYTHON_METHOD_DEF                            \
 (                                                                           \
-    find_node_by_path, "path",                                              \
+    find_by_path, "path",                                                   \
     METH_VARARGS, py_yaml_tree,                                             \
-    "Find a node in a Yaml tree by its path.\n"                             \
+    "Find nodes in a Yaml tree using a path.\n"                             \
     "\n"                                                                    \
     "Paths are node keys separated by '/', such as '/my/path/to/node'."     \
 )
@@ -171,20 +171,26 @@ static PyObject *py_yaml_tree_find_node_by_path(PyObject *self, PyObject *args)
 
     tree = G_YAML_TREE(pygobject_get(self));
 
-    found = g_yaml_tree_find_node_by_path(tree, path);
+    g_yaml_tree_find_by_path(tree, path, &found, &count);
 
-    if (found == NULL)
-    {
-        result = Py_None;
-        Py_INCREF(result);
-    }
+    result = PyTuple_New(count);
 
-    else
+    for (i = 0; i < count; i++)
     {
-        result = pygobject_new(G_OBJECT(found));
-        g_object_unref(found);
+#ifndef NDEBUG
+        ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+        assert(ret == 0);
+#else
+        PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+#endif
+
+        g_object_unref(G_OBJECT(found[i]));
+
     }
 
+    if (found != NULL)
+        free(found);
+
     return result;
 
 }
@@ -195,51 +201,32 @@ static PyObject *py_yaml_tree_find_node_by_path(PyObject *self, PyObject *args)
 *  Paramètres  : self    = objet Python concerné par l'appel.                 *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
-*  Description : Fournit la liste des premiers noeuds de l'arborescence Yaml. *
+*  Description : Fournit le noeud constituant la racine d'arborescence Yaml.  *
 *                                                                             *
-*  Retour      : Noeuds constituant les racines de l'arborescence.            *
+*  Retour      : Noeud constituant la racine de l'arborescence.               *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_yaml_tree_get_root_nodes(PyObject *self, void *closure)
+static PyObject *py_yaml_tree_get_root(PyObject *self, void *closure)
 {
     PyObject *result;                       /* Résultat à retourner        */
     GYamlTree *tree;                        /* Version GLib du type        */
-    size_t count;                           /* Quantité de noeuds à traiter*/
-    GYamlNode **nodes;                      /* Liste des noeuds à la racine*/
-    size_t i;                               /* Boucle de parcours          */
-#ifndef NDEBUG
-    int ret;                                /* Bilan d'une insertion       */
-#endif
+    GYamlNode *root;                        /* Noeud racine d'arborescence */
 
-#define YAML_TREE_ROOT_NODES_ATTRIB PYTHON_GET_DEF_FULL             \
-(                                                                   \
-    root_nodes, py_yaml_tree,                                       \
-    "List of Yaml nodes which are the roots of all tree nodes."     \
+#define YAML_TREE_ROOT_ATTRIB PYTHON_GET_DEF_FULL           \
+(                                                           \
+    root, py_yaml_tree,                                     \
+    "Yaml node which is the root of the whole tree nodes."  \
 )
 
     tree = G_YAML_TREE(pygobject_get(self));
 
-    nodes = g_yaml_tree_get_root_nodes(tree, &count);
-
-    result = PyTuple_New(count);
-
-    for (i = 0; i < count; i++)
-    {
-#ifndef NDEBUG
-        ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(nodes[i])));
-        assert(ret == 0);
-#else
-        PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(nodes[i])));
-#endif
-
-        g_object_unref(G_OBJECT(nodes[i]));
-
-    }
+    root = g_yaml_tree_get_root(tree);
 
-    free(nodes);
+    result = pygobject_new(G_OBJECT(root));
+    g_object_unref(G_OBJECT(root));
 
     return result;
 
@@ -266,7 +253,7 @@ PyTypeObject *get_python_yaml_tree_type(void)
     };
 
     static PyGetSetDef py_yaml_tree_getseters[] = {
-        YAML_TREE_ROOT_NODES_ATTRIB,
+        YAML_TREE_ROOT_ATTRIB,
         { NULL }
     };
 
diff --git a/plugins/yaml/reader.c b/plugins/yaml/reader.c
index 02e1aa9..c8852bb 100644
--- a/plugins/yaml/reader.c
+++ b/plugins/yaml/reader.c
@@ -182,7 +182,6 @@ GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length)
 {
     GYamlReader *result;                    /* Structure à retourner       */
     char *dumped;                           /* Contenu manipulable         */
-    size_t level;                           /* Niveau unique d'indentation */
     char *saved;                            /* Sauvegarde de position      */
     char *iter;                             /* Boucle de parcours          */
     size_t number;                          /* Indice de ligne courante    */
@@ -194,8 +193,6 @@ GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length)
 
     memcpy(dumped, content, length);
 
-    level = 0;
-
     for (iter = dumped, saved = strchr(iter, '\n'), number = 0;
          *iter != '\0';
          iter = ++saved, saved = strchr(iter, '\n'), number++)
@@ -210,9 +207,6 @@ GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length)
         if (line == NULL)
             goto format_error;
 
-        if (level == 0)
-            level = g_yaml_line_count_indent(line);
-
         result->lines = realloc(result->lines, ++result->count * sizeof(GYamlLine *));
 
         g_object_ref_sink(G_OBJECT(line));
@@ -222,8 +216,7 @@ GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length)
 
     free(dumped);
 
-    result->tree = g_yaml_tree_new(level, result->lines, result->count);
-    g_object_ref_sink(G_OBJECT(result->tree));
+    result->tree = g_yaml_tree_new(result->lines, result->count);
 
     return result;
 
@@ -366,7 +359,8 @@ GYamlTree *g_yaml_reader_get_tree(const GYamlReader *reader)
 
     result = reader->tree;
 
-    g_object_ref(G_OBJECT(result));
+    if (result != NULL)
+        g_object_ref(G_OBJECT(result));
 
     return result;
 
diff --git a/plugins/yaml/tree.c b/plugins/yaml/tree.c
index 98ee30c..0494aeb 100644
--- a/plugins/yaml/tree.c
+++ b/plugins/yaml/tree.c
@@ -24,20 +24,25 @@
 #include "tree.h"
 
 
+#include <assert.h>
 #include <malloc.h>
 #include <string.h>
 
 
+#include <i18n.h>
+#include <core/logs.h>
+
+
+#include "collection.h"
+
+
 
 /* Arborescence de lignes au format Yaml (instance) */
 struct _GYamlTree
 {
     GObject parent;                         /* A laisser en premier        */
 
-    size_t indent;                          /* Niveau d'indentation        */
-
-    GYamlNode **nodes;                      /* Liste de noeuds à la racine */
-    size_t count;                           /* Quantité de ces noeuds      */
+    GYamlNode *root;                        /* Racine des noeuds           */
 
 };
 
@@ -61,8 +66,8 @@ static void g_yaml_tree_dispose(GYamlTree *);
 /* Procède à la libération totale de la mémoire. */
 static void g_yaml_tree_finalize(GYamlTree *);
 
-/* Construit un nouveau noeud dans une arborescence Yaml. */
-static GYamlNode *g_yaml_tree_build_node(GYamlLine **, size_t, size_t *);
+/* Construit une collection de noeuds avec une arborescence. */
+static bool g_yaml_tree_build_node(GYamlCollection *, GYamlLine **, size_t, size_t, size_t *);
 
 
 
@@ -108,10 +113,7 @@ static void g_yaml_tree_class_init(GYamlTreeClass *klass)
 
 static void g_yaml_tree_init(GYamlTree *tree)
 {
-    tree->indent = 0;
-
-    tree->nodes = NULL;
-    tree->count = 0;
+    tree->root = NULL;
 
 }
 
@@ -130,10 +132,7 @@ static void g_yaml_tree_init(GYamlTree *tree)
 
 static void g_yaml_tree_dispose(GYamlTree *tree)
 {
-    size_t i;                               /* Boucle de parcours          */
-
-    for (i = 0; i < tree->count; i++)
-        g_clear_object(&tree->nodes[i]);
+    g_clear_object(&tree->root);
 
     G_OBJECT_CLASS(g_yaml_tree_parent_class)->dispose(G_OBJECT(tree));
 
@@ -154,9 +153,6 @@ static void g_yaml_tree_dispose(GYamlTree *tree)
 
 static void g_yaml_tree_finalize(GYamlTree *tree)
 {
-    if (tree->nodes != NULL)
-        free(tree->nodes);
-
     G_OBJECT_CLASS(g_yaml_tree_parent_class)->finalize(G_OBJECT(tree));
 
 }
@@ -164,8 +160,7 @@ static void g_yaml_tree_finalize(GYamlTree *tree)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : indent = indentation nominale pour les lignes à traiter.     *
-*                lines  = ensemble de lignes à constituer en arborescence.    *
+*  Paramètres  : lines  = ensemble de lignes à constituer en arborescence.    *
 *                count  = taille de cet ensemble de lignes.                   *
 *                                                                             *
 *  Description : Construit une arborescence à partir de lignes Yaml.          *
@@ -176,34 +171,37 @@ static void g_yaml_tree_finalize(GYamlTree *tree)
 *                                                                             *
 ******************************************************************************/
 
-GYamlTree *g_yaml_tree_new(size_t indent, GYamlLine **lines, size_t count)
+GYamlTree *g_yaml_tree_new(GYamlLine **lines, size_t count)
 {
     GYamlTree *result;                      /* Structure à retourner       */
-    size_t cur;                             /* Boucle de parcours          */
-    GYamlNode *node;                        /* Nouveau noeud à intéger     */
+    GYamlCollection *collec;                /* Collection de noeuds        */
+    size_t indent;                          /* Indentation initiale        */
+    size_t processed;                       /* Quantité de noeuds traités  */
+    bool status;                            /* Bilan de construction       */
 
     result = g_object_new(G_TYPE_YAML_TREE, NULL);
 
-    result->indent = indent;
-
-    for (cur = 0; cur < count; )
+    if (count > 0)
     {
-        node = g_yaml_tree_build_node(lines, count, &cur);
+        result->root = g_yaml_node_new(NULL);
 
-        if (node == NULL)
-            break;
+        collec = g_yaml_collection_new(g_yaml_line_is_list_item(lines[0]));
+        g_yaml_node_set_collection(result->root, collec);
 
-        result->nodes = realloc(result->nodes, ++result->count * sizeof(GYamlNode *));
+        indent = g_yaml_line_count_indent(lines[0]);
+        processed = 0;
 
-        g_object_ref_sink(G_OBJECT(node));
-        result->nodes[result->count - 1] = node;
+        status = g_yaml_tree_build_node(collec, lines, count, indent, &processed);
 
-    }
+        if (status)
+            assert(processed == count);
+
+        else
+        {
+            g_object_unref(G_OBJECT(result));
+            result = NULL;
+        }
 
-    if (cur < count)
-    {
-        g_object_unref(G_OBJECT(result));
-        result = NULL;
     }
 
     return result;
@@ -213,86 +211,129 @@ GYamlTree *g_yaml_tree_new(size_t indent, GYamlLine **lines, size_t count)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : lines = ensemble de lignes à constituer en arborescence.     *
-*                count = taille de cet ensemble de lignes.                    *
-*                cur   = position courante dans les lignes. [OUT]             *
+*  Paramètres  : lines    = ensemble de lignes à constituer en arborescence.  *
+*                count    = taille de cet ensemble de lignes.                 *
+*                expected = niveau d'identation attendu.                      *
+*                cur      = position courante dans les lignes. [OUT]          *
 *                                                                             *
-*  Description : Construit un nouveau noeud dans une arborescence Yaml.       *
+*  Description : Construit une collection de noeuds avec une arborescence.    *
 *                                                                             *
-*  Retour      : Noeud mis en place ou NULL en cas d'erreur.                  *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static GYamlNode *g_yaml_tree_build_node(GYamlLine **lines, size_t count, size_t *cur)
+static bool g_yaml_tree_build_node(GYamlCollection *collec, GYamlLine **lines, size_t count, size_t expected, size_t *cur)
 {
-    GYamlNode *result;                      /* Structure à retourner       */
+    bool result;                            /* Bilan à retourner           */
+    bool first;                             /* Marque d'un premier élément */
+    GYamlNode *last;                        /* Mémorisation du dernier     */
     GYamlLine *line;                        /* Ligne de parcours courante  */
-    size_t cur_indent;                      /* Indentation courante        */
-    bool same_indent;                       /* Comparaison pour les enfants*/
-    size_t next_indent;                     /* Indentation de la ligne     */
-    GYamlNode *child;                       /* Sous-noeud mis en place     */
+    size_t indent;                          /* Indentation de ligne        */
+    bool is_item;                           /* Elément d'une liste ?       */
+    GYamlCollection *sub;                   /* Nouvelle sous-collection    */
+    GYamlNode *glue;                        /* Noeud vide intermédiaire    */
 
-    line = lines[(*cur)++];
+    result = true;
 
-    result = g_yaml_node_new(line);
+    first = true;
+    last = NULL;
 
-    /* Détermination de l'indentation associée */
+    for (; *cur < count; )
+    {
+        line = lines[*cur];
 
-    cur_indent = g_yaml_line_count_indent(line);
+        indent = g_yaml_line_count_indent(line);
+        is_item = g_yaml_line_is_list_item(line);
+
+        /**
+         * Si la première ligne traitée commence par un élément de liste,
+         * alors un appel parent a constitué une collection qui n'est pas une séquence.
+         *
+         * L'objectif est de créer une simple association de 'clefs: valeurs'.
+         *
+         * Si la collection n'est pas adapté, alors le parcours n'est pas encore
+         * arrivé à ce stade de construction.
+         */
+        if (first && is_item && !g_yaml_collection_is_sequence(collec))
+        {
+            indent += 2; /* 2 == strlen("- ") */
+            is_item = false;
+        }
 
-    same_indent = g_yaml_line_is_list_item(line);
+        first = false;
 
-    /* Parcours du reste des lignes */
+        /* Fin de l'ensemble courant */
+        if (indent < expected)
+            goto done;
 
-    for (; *cur < count; )
-    {
-        line = lines[*cur];
+        /* Début d'un sous-ensemble */
+        else if (indent > expected)
+        {
+            assert(last != NULL);
 
-        next_indent = g_yaml_line_count_indent(line);
+            sub = g_yaml_collection_new(is_item);
+            g_yaml_node_set_collection(last, sub);
 
-        if ((same_indent && next_indent > cur_indent)
-            || (!same_indent && next_indent <= cur_indent))
-            break;
+            result = g_yaml_tree_build_node(sub, lines, count, indent, cur);
+            if (!result) goto done;
 
-        child = g_yaml_tree_build_node(lines, count, cur);
+        }
 
-        if (child == NULL)
-            goto build_error;
+        /* Elément de même niveau */
+        else
+        {
+            if (is_item)
+            {
+                /* Vérification de cohérence */
+                if (!g_yaml_collection_is_sequence(collec))
+                {
+                    log_variadic_message(LMT_BAD_BINARY, _("A mapping item was expected at line %zu"),
+                                         g_yaml_line_get_number(line));
 
-        g_yaml_node_add_child(result, child);
+                    result = false;
+                    goto done;
 
-    }
+                }
 
-    return result;
+                glue = g_yaml_node_new(NULL);
+                g_yaml_collection_add_node(collec, glue);
 
- build_error:
+                sub = g_yaml_collection_new(false);
+                g_yaml_node_set_collection(glue, sub);
 
-    g_object_unref(G_OBJECT(result));
+                result = g_yaml_tree_build_node(sub, lines, count, expected + 2 /* 2 == strlen("- ") */, cur);
+                if (!result) goto done;
 
-    return NULL;
+            }
 
-}
+            else
+            {
+                /* Vérification de cohérence */
+                if (g_yaml_collection_is_sequence(collec))
+                {
+                    log_variadic_message(LMT_BAD_BINARY, _("A list item was expected at line %zu"),
+                                         g_yaml_line_get_number(line));
 
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : tree = ligne au format Yaml à consulter.                     *
-*                                                                             *
-*  Description : Fournit la taille de l'indentation nomilae d'un arbre Yaml.  *
-*                                                                             *
-*  Retour      : Taille de l'indentation associée.                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+                    result = false;
+                    goto done;
 
-size_t g_yaml_tree_get_indent(const GYamlTree *tree)
-{
-    size_t result;                          /* Quantité à retourner        */
+                }
+
+                last = g_yaml_node_new(line);
+                g_yaml_collection_add_node(collec, last);
+
+                (*cur)++;
+
+            }
+
+        }
+
+    }
 
-    result = tree->indent;
+ done:
 
     return result;
 
@@ -302,30 +343,21 @@ size_t g_yaml_tree_get_indent(const GYamlTree *tree)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : tree  = ligne au format Yaml à consulter.                    *
-*                count = taille de la liste constituée. [OUT]                 *
 *                                                                             *
-*  Description : Fournit la liste des premiers noeuds de l'arborescence Yaml. *
+*  Description : Fournit le noeud constituant la racine d'arborescence Yaml.  *
 *                                                                             *
-*  Retour      : Noeuds constituant les racines de l'arborescence.            *
+*  Retour      : Noeud constituant la racine de l'arborescence.               *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GYamlNode **g_yaml_tree_get_root_nodes(const GYamlTree *tree, size_t *count)
+GYamlNode *g_yaml_tree_get_root(const GYamlTree *tree)
 {
-    GYamlNode **result;                     /* Liste à retourner           */
-    size_t i;                               /* Boucle de parcours          */
-
-    *count = tree->count;
+    GYamlNode *result;                      /* Liste à retourner           */
 
-    result = malloc(*count * sizeof(GYamlNode *));
-
-    for (i = 0; i < *count; i++)
-    {
-        result[i] = tree->nodes[i];
-        g_object_ref(G_OBJECT(result[i]));
-    }
+    result = tree->root;
+    g_object_ref(G_OBJECT(result));
 
     return result;
 
@@ -334,50 +366,21 @@ GYamlNode **g_yaml_tree_get_root_nodes(const GYamlTree *tree, size_t *count)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : tree = ligne au format Yaml à consulter.                     *
-*                path = chemin d'accès à parcourir.                           *
+*  Paramètres  : tree  = ligne au format Yaml à consulter.                    *
+*                path  = chemin d'accès à parcourir.                          *
+*                nodes = liste de noeuds avec correspondance établie. [OUT]   *
+*                count = quantité de ces noeuds. [OUT]                        *
 *                                                                             *
-*  Description : Recherche le noeud correspondant à un chemin.                *
+*  Description : Recherche les noeuds correspondant à un chemin.              *
 *                                                                             *
-*  Retour      : Eventuel noeud trouvé ou NULL si aucun.                      *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GYamlNode *g_yaml_tree_find_node_by_path(const GYamlTree *tree, const char *path)
+void g_yaml_tree_find_by_path(const GYamlTree *tree, const char *path, GYamlNode ***nodes, size_t *count)
 {
-    GYamlNode *result;                      /* Trouvaille à retourner      */
-    char *next;                             /* Prochaine partie du chemin  */
-    size_t cmplen;                          /* Etendue de la comparaison   */
-    size_t i;                               /* Boucle de parcours          */
-    GYamlLine *line;                        /* Ligne Yaml d'un enfant      */
-    const char *key;                        /* Clef d'un noeud             */
-    int ret;                                /* Bilan d'une comparaison     */
-
-    result = NULL;
-
-    if (path[0] == '/' && path[0] != '\0')
-    {
-        next = strchr(path + 1, '/');
-
-        cmplen = (next == NULL ? strlen(path + 1) : next - path - 1);
-
-        for (i = 0; i < tree->count && result == NULL; i++)
-        {
-            line = g_yaml_node_get_yaml_line(tree->nodes[i]);
-
-            key = g_yaml_line_get_key(line);
-
-            ret = strncmp(path + 1, key, cmplen);
-
-            if (ret == 0)
-                result = g_yaml_node_find_node_by_path(tree->nodes[i], next);
-
-        }
-
-    }
-
-    return result;
+    g_yaml_node_find_by_path(tree->root, path, nodes, count);
 
 }
diff --git a/plugins/yaml/tree.h b/plugins/yaml/tree.h
index 469199d..d152b7e 100644
--- a/plugins/yaml/tree.h
+++ b/plugins/yaml/tree.h
@@ -53,16 +53,13 @@ typedef struct _GYamlTreeClass GYamlTreeClass;
 GType g_yaml_tree_get_type(void);
 
 /* Construit une arborescence à partir de lignes Yaml. */
-GYamlTree *g_yaml_tree_new(size_t, GYamlLine **, size_t);
+GYamlTree *g_yaml_tree_new(GYamlLine **, size_t);
 
-/* Fournit la taille de l'indentation nomilae d'un arbre Yaml. */
-size_t g_yaml_tree_get_indent(const GYamlTree *);
+/* Fournit le noeud constituant la racine d'arborescence Yaml. */
+GYamlNode *g_yaml_tree_get_root(const GYamlTree *);
 
-/* Fournit la liste des premiers noeuds de l'arborescence Yaml. */
-GYamlNode **g_yaml_tree_get_root_nodes(const GYamlTree *, size_t *);
-
-/* Recherche le noeud correspondant à un chemin. */
-GYamlNode *g_yaml_tree_find_node_by_path(const GYamlTree *, const char *);
+/* Recherche les noeuds correspondant à un chemin. */
+void g_yaml_tree_find_by_path(const GYamlTree *, const char *, GYamlNode ***, size_t *);
 
 
 
diff --git a/tests/plugins/yamlrdr.py b/tests/plugins/yamlrdr.py
index 7f65624..103d6e8 100644
--- a/tests/plugins/yamlrdr.py
+++ b/tests/plugins/yamlrdr.py
@@ -16,26 +16,54 @@ class TestYamlReader(ChrysalideTestCase):
 
         super(TestYamlReader, cls).setUpClass()
 
-        cls._simple = tempfile.NamedTemporaryFile()
-
-        cls.simple_data = b'''
-meta:
-  id: java_class
-  endian: be
-  file-extension: class
-  xref:
-    justsolve: Java
-    pronom: x-fmt/415
-    'wiki"data': Q2193155
-  license: CC0-1.0
+        cls._simple_map = tempfile.NamedTemporaryFile()
+
+        cls._simple_map_data = b'''
+a: av
+b: bv
+c: cv
+
+'''
+
+        cls._simple_seq = tempfile.NamedTemporaryFile()
+
+        cls._simple_seq_data = b'''
+- a: av
+- b: bv
+- c: cv
 
 '''
 
-        cls._simple.write(cls.simple_data)
+        cls._nested = tempfile.NamedTemporaryFile()
+
+        cls._nested_data = b'''
+root:
+  a: v0
+  b: v1
+  c: v2
+  sub:
+    aa: v00
+    bb: v01
+    cc: v02
+      - i: w
+      - j: x
+      - k: c
+  d: v3
 
-        cls._simple.flush()
+'''
 
-        cls.log('Using temporary file "%s"' % cls._simple.name)
+        tmp = [
+            [ cls._simple_map, cls._simple_map_data ],
+            [ cls._simple_seq, cls._simple_seq_data ],
+            [ cls._nested, cls._nested_data ]
+        ]
+
+        for f, d in tmp:
+
+            f.write(d)
+            f.flush()
+
+            cls.log('Using temporary file "%s"' % f.name)
 
 
     @classmethod
@@ -43,52 +71,126 @@ meta:
 
         super(TestYamlReader, cls).tearDownClass()
 
-        cls.log('Delete file "%s"' % cls._simple.name)
+        tmp = [
+            cls._simple_map,
+            cls._simple_seq,
+            cls._nested,
+        ]
 
-        cls._simple.close()
+        for f in tmp:
 
+            cls.log('Delete file "%s"' % f.name)
 
-    def testSimpleYamlContent(self):
-        """Validate simple Yaml content reader."""
+            f.close()
 
-        reader = YamlReader.new_from_path(self._simple.name)
-        self.assertIsNotNone(reader)
 
+    def testSimpleYamlContent(self):
+        """Validate Yaml content readers."""
 
         def _build_node_desc(node, left):
 
             line = node.yaml_line
 
-            desc = left + line.key + ':' + (' ' + line.value if line.value else '') + '\n'
+            if line:
+                prefix = '- ' if line.is_list_item else ''
+                desc = left + prefix + line.key + ':' + (' ' + line.value if line.value else '') + '\n'
+                indent = '  '
+            else:
+                desc = ''
+                indent = ''
 
-            for child in node.children:
-                desc += _build_node_desc(child, left + '  ')
+            if node.collection:
+                for child in node.collection.nodes:
+                    desc += _build_node_desc(child, left + indent)
 
             return desc
 
 
-        fulldesc = ''
+        reader = YamlReader.new_from_path(self._simple_map.name)
+        self.assertIsNotNone(reader)
+        self.assertIsNotNone(reader.tree)
+
+        fulldesc = _build_node_desc(reader.tree.root, '')
+
+        self.assertEqual('\n' + fulldesc + '\n', self._simple_map_data.decode('ascii'))
+
+        reader = YamlReader.new_from_path(self._simple_seq.name)
+        self.assertIsNotNone(reader)
+        self.assertIsNotNone(reader.tree)
+
+        fulldesc = _build_node_desc(reader.tree.root, '')
+
+        self.assertEqual('\n' + fulldesc + '\n', self._simple_seq_data.decode('ascii'))
+
+        reader = YamlReader.new_from_path(self._nested.name)
+        self.assertIsNotNone(reader)
+        self.assertIsNotNone(reader.tree)
 
-        for rn in reader.tree.root_nodes:
-            fulldesc += _build_node_desc(rn, '')
+        fulldesc = _build_node_desc(reader.tree.root, '')
 
-        self.assertEqual('\n' + fulldesc + '\n', self.simple_data.decode('ascii'))
+        self.assertEqual('\n' + fulldesc + '\n', self._nested_data.decode('ascii'))
 
 
     def testSimpleYamlContentFinder(self):
-        """Validate simple Yaml content search."""
+        """Validate Yaml nested content search."""
 
-        reader = YamlReader.new_from_path(self._simple.name)
+        reader = YamlReader.new_from_path(self._nested.name)
         self.assertIsNotNone(reader)
 
-        found = reader.tree.find_node_by_path('/meta/xref')
+        found = reader.tree.find_by_path('/root/sub')
+
+        self.assertEqual(len(found), 1)
+
+        if len(found) == 1:
+            self.assertEqual(found[0].yaml_line.key, 'sub')
+
+        found = reader.tree.find_by_path('/root/sub/')
+
+        self.assertEqual(len(found), 3)
+
+        found = reader.tree.find_by_path('/root/sub/xx')
+
+        self.assertEqual(len(found), 0)
+
+        found = reader.tree.find_by_path('/root/sub/cc/i')
+
+        self.assertEqual(len(found), 1)
+
+        if len(found) == 1:
+            self.assertEqual(found[0].yaml_line.key, 'i')
+            self.assertEqual(found[0].yaml_line.is_list_item, True)
+
+        found = reader.tree.find_by_path('/root/sub/cc')
+
+        self.assertEqual(len(found), 1)
+
+        if len(found) == 1:
+
+            root = found[0]
+
+            found = root.find_by_path('cc/i')
+
+            self.assertEqual(len(found), 1)
+
+            if len(found) == 1:
+
+                self.assertEqual(found[0].yaml_line.key, 'i')
+                self.assertEqual(found[0].yaml_line.is_list_item, True)
+
+            found = root.find_by_path('/cc/i')
+
+            self.assertEqual(len(found), 1)
+
+            if len(found) == 1:
 
-        self.assertEqual(found.yaml_line.key, 'xref')
+                self.assertEqual(found[0].yaml_line.key, 'i')
+                self.assertEqual(found[0].yaml_line.is_list_item, True)
 
-        found = reader.tree.find_node_by_path('/meta/xref/')
+            found = root.find_by_path('//i')
 
-        self.assertEqual(found.yaml_line.key, 'xref')
+            self.assertEqual(len(found), 1)
 
-        found = reader.tree.find_node_by_path('/meta/xref/aa')
+            if len(found) == 1:
 
-        self.assertIsNone(found)
+                self.assertEqual(found[0].yaml_line.key, 'i')
+                self.assertEqual(found[0].yaml_line.is_list_item, True)
-- 
cgit v0.11.2-87-g4458