schema tree CHANGE processing submodules

Data (nodes, groupings, rpcs, notifications) from submodules are now
stored in the main module's data tree to simplify searching for the
data. For the same reason, the import and include array in the main
module are extended by imports and includes from submodules (each
item is added only once to the main module).

This is a huge change and includes also some other optimizations and
bugfixes that appeared with submodules.
diff --git a/src/common.c b/src/common.c
index 05b7b05..ab7f9f4 100644
--- a/src/common.c
+++ b/src/common.c
@@ -355,9 +355,6 @@
             free(out);
             return NULL;
         }
-        if (mod->type) {
-           mod = ((struct lys_submodule *)module)->belongsto;
-        }
 
         /* adjust out size (it can even decrease in some strange cases) */
         out_size += strlen(mod->name)-id_len;
diff --git a/src/context.c b/src/context.c
index c739395..221b98f 100644
--- a/src/context.c
+++ b/src/context.c
@@ -171,15 +171,15 @@
         return NULL;
     }
 
-    /* TODO search also for submodules not directly available from the main module */
-
-    /* search in modules included by the main module */
+    /* make sure that the provided module is not submodule */
     if (module->type) {
         module = ((struct lys_submodule *)module)->belongsto;
     }
+
+    /* search in submodules list */
     for (i = 0; i < module->inc_size; i++) {
         result = module->inc[i].submodule;
-        if (strcmp(name, result->name)) {
+        if (!result || strcmp(name, result->name)) {
             continue;
         }
 
@@ -293,7 +293,7 @@
             free(module_data);
         }
     } else {
-        module = lyp_search_file(ctx, NULL, name, revision);
+        module = lyp_search_file(ctx, NULL, name, revision, NULL);
     }
 
     return module;
@@ -348,7 +348,7 @@
         return NULL;
     }
 
-    for (i = 0; i < mod->inc_size; i++) {
+    for (i = 0; i < mod->inc_size && mod->inc[i].submodule; i++) {
         result[i] = mod->inc[i].submodule->name;
     }
     result[i] = NULL;
@@ -373,7 +373,7 @@
     }
 
     /* submodule features */
-    for (i = 0; i < cur_mod->inc_size; ++i) {
+    for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
         for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
             if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
                 continue;
@@ -398,11 +398,7 @@
     for (i = 0; i < ctx->models.used; ++i) {
         mod_iter = ctx->models.list[i];
         for (k = 0; k < mod_iter->deviation_size; ++k) {
-            if (mod_iter->deviation[k].target->module->type) {
-                target_module = ((struct lys_submodule *)mod_iter->deviation[k].target->module)->belongsto;
-            } else {
-                target_module = mod_iter->deviation[k].target->module;
-            }
+            target_module = mod_iter->deviation[k].target->module;
 
             /* we found a module deviating our module */
             if (target_module == cur_mod) {
@@ -420,14 +416,9 @@
             }
         }
 
-        for (j = 0; j < mod_iter->inc_size; ++j) {
+        for (j = 0; j < mod_iter->inc_size && mod_iter->inc[j].submodule; ++j) {
             for (k = 0; k < mod_iter->inc[j].submodule->deviation_size; ++k) {
-                if (mod_iter->inc[j].submodule->deviation[k].target->module->type) {
-                    target_module = ((struct lys_submodule *)
-                                    mod_iter->inc[j].submodule->deviation[k].target->module)->belongsto;
-                } else {
-                    target_module = mod_iter->inc[j].submodule->deviation[k].target->module;
-                }
+                target_module = mod_iter->inc[j].submodule->deviation[k].target->module;
 
                 /* we found a submodule deviating our module */
                 if (target_module == cur_mod) {
@@ -462,7 +453,7 @@
         cont = lyd_new(parent, NULL, "submodules");
     }
 
-    for (i = 0; i < cur_mod->inc_size; ++i) {
+    for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
         item = lyd_new(cont, NULL, "submodule");
         if (!item) {
             return EXIT_FAILURE;
@@ -494,7 +485,7 @@
 
     mod = ly_ctx_get_module(ctx, "ietf-yang-library", NULL);
     if (!mod) {
-        mod = lyp_search_file(ctx, NULL, "ietf-yang-library", NULL);
+        mod = lyp_search_file(ctx, NULL, "ietf-yang-library", NULL, NULL);
     }
     if (!mod || !mod->data || strcmp(mod->data->next->name, "modules")) {
         return NULL;
diff --git a/src/dict.c b/src/dict.c
index a104d1a..963665a 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -93,7 +93,7 @@
     uint32_t index;
     struct dict_rec *record, *prev = NULL;
 
-    if (!ctx || !value) {
+    if (!value || !ctx || !ctx->dict.used) {
         return;
     }
 
diff --git a/src/parser.c b/src/parser.c
index 10c2850..58240c0 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -71,9 +71,10 @@
 {
     int i;
 
+    assert(module);
     module->implemented = 1;
 
-    for (i = 0; i < module->inc_size; i++) {
+    for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
         lyp_set_implemented((struct lys_module *)module->inc[i].submodule);
     }
 }
@@ -86,7 +87,6 @@
 struct lys_module *
 lys_read_import(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
 {
-    struct unres_schema *unres;
     struct lys_module *module = NULL;
     struct stat sb;
     char *addr;
@@ -96,26 +96,19 @@
         return NULL;
     }
 
-    unres = calloc(1, sizeof *unres);
-    if (!unres) {
-        LOGMEM;
-        return NULL;
-    }
 
     if (fstat(fd, &sb) == -1) {
         LOGERR(LY_ESYS, "Failed to stat the file descriptor (%s).", strerror(errno));
-        free(unres);
         return NULL;
     }
     addr = mmap(NULL, sb.st_size + 1, PROT_READ, MAP_PRIVATE, fd, 0);
     if (addr == MAP_FAILED) {
         LOGERR(LY_EMEM,"Map file into memory failed (%s()).",__func__);
-        free(unres);
         return NULL;
     }
     switch (format) {
     case LYS_IN_YIN:
-        module = yin_read_module(ctx, addr, 0, unres);
+        module = yin_read_module(ctx, addr, 0);
         break;
     case LYS_IN_YANG:
     default:
@@ -124,19 +117,13 @@
     }
     munmap(addr, sb.st_size);
 
-    if (module && unres->count && resolve_unres_schema(module, unres)) {
-        unres_schema_free(ctx, unres);
-        lys_free(module, 0);
-        module = NULL;
-    } else {
-        unres_schema_free(ctx, unres);
-    }
-
     return module;
 }
 
+/* if module is !NULL, then the function searches for submodule */
 struct lys_module *
-lyp_search_file(struct ly_ctx *ctx, struct lys_module *module, const char *name, const char *revision)
+lyp_search_file(struct ly_ctx *ctx, struct lys_module *module, const char *name, const char *revision,
+                struct unres_schema *unres)
 {
     size_t len, flen;
     int fd;
@@ -150,6 +137,15 @@
     len = strlen(name);
     cwd = wd = get_current_dir_name();
 
+    if (module) {
+        /* searching for submodule, try if it is already loaded */
+        result = (struct lys_module *)ly_ctx_get_submodule(module, name, revision);
+        if (result) {
+            /* success */
+            return result;
+        }
+    }
+
 opendir_search:
     chdir(wd);
     dir = opendir(wd);
@@ -192,7 +188,7 @@
         }
 
         if (module) {
-            result = (struct lys_module *)lys_submodule_read(module, fd, format, module->implemented);
+            result = (struct lys_module *)lys_submodule_read(module, fd, format, unres);
         } else {
             result = lys_read_import(ctx, fd, format);
         }
@@ -922,6 +918,7 @@
         type = lyp_get_next_union_type(stype, NULL, &found);
         while (type) {
             leaf->value_type = type->base;
+            memset(&leaf->value, 0, sizeof leaf->value);
 
             /* in these cases we use JSON format */
             if (xml && ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST))) {
@@ -957,9 +954,12 @@
             LOGVAL(LYE_INVAL, line, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
             return EXIT_FAILURE;
         }
-    } else if (lyp_parse_value_(leaf, stype, resolve, unres, line)) {
-        ly_errno = LY_EVALID;
-        return EXIT_FAILURE;
+    } else {
+        memset(&leaf->value, 0, sizeof leaf->value);
+        if (lyp_parse_value_(leaf, stype, resolve, unres, line)) {
+            ly_errno = LY_EVALID;
+            return EXIT_FAILURE;
+        }
     }
 
     return EXIT_SUCCESS;
diff --git a/src/parser.h b/src/parser.h
index 6237da0..c47732b 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -36,9 +36,8 @@
  * @defgroup yin YIN format support
  * @{
  */
-struct lys_module *yin_read_module(struct ly_ctx *ctx, const char *data, int implement, struct unres_schema *unres);
-struct lys_submodule *yin_read_submodule(struct lys_module *module, const char *data, int implement,
-                                         struct unres_schema *unres);
+struct lys_module *yin_read_module(struct ly_ctx *ctx, const char *data, int implement);
+struct lys_submodule *yin_read_submodule(struct lys_module *module, const char *data, struct unres_schema *unres);
 
 /**@} yin */
 
@@ -60,7 +59,7 @@
 
 
 struct lys_module *lyp_search_file(struct ly_ctx *ctx, struct lys_module *module, const char *name,
-                                   const char *revision);
+                                   const char *revision, struct unres_schema *unres);
 
 void lyp_set_implemented(struct lys_module *module);
 
diff --git a/src/parser_yin.c b/src/parser_yin.c
index a47d4cd..39c55e0 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -121,7 +121,7 @@
 {
     int i;
 
-    if (!module->type && module->prefix && !strcmp(module->prefix, prefix)) {
+    if (module->prefix && !strcmp(module->prefix, prefix)) {
         return EXIT_FAILURE;
     }
     for (i = 0; i < module->imp_size; i++) {
@@ -225,39 +225,25 @@
         }
 
         /* check submodule's top-level names */
-        for (i = 0; i < module->inc_size; i++) {
+        for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
             if (dup_typedef_check(id, module->inc[i].submodule->tpdf, module->inc[i].submodule->tpdf_size)) {
                 LOGVAL(LYE_DUPID, line, "typedef", id);
                 return EXIT_FAILURE;
             }
         }
 
-        /* check top-level names in the main module */
-        if (module->type) {
-            if (dup_typedef_check(id, ((struct lys_submodule *)module)->belongsto->tpdf,
-                                  ((struct lys_submodule *)module)->belongsto->tpdf_size)) {
-                LOGVAL(LYE_DUPID, line, "typedef", id);
-                return EXIT_FAILURE;
-            }
-        }
-
         break;
     case LY_IDENT_PREFIX:
         assert(module);
 
-        if (module->type) {
-            /* go to the main module */
-            module = ((struct lys_submodule *)module)->belongsto;
-        }
-
-        /* check the main module itself */
+        /* check the module itself */
         if (dup_prefix_check(id, module)) {
             LOGVAL(LYE_DUPID, line, "prefix", id);
             return EXIT_FAILURE;
         }
 
         /* and all its submodules */
-        for (i = 0; i < module->inc_size; i++) {
+        for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
             if (dup_prefix_check(id, (struct lys_module *)module->inc[i].submodule)) {
                 LOGVAL(LYE_DUPID, line, "prefix", id);
                 return EXIT_FAILURE;
@@ -275,7 +261,7 @@
         }
 
         /* and all its submodules */
-        for (i = 0; i < module->inc_size; i++) {
+        for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
             if (dup_feature_check(id, (struct lys_module *)module->inc[i].submodule)) {
                 LOGVAL(LYE_DUPID, line, "feature", id);
                 return EXIT_FAILURE;
@@ -2586,7 +2572,7 @@
 
 /* logs directly */
 static int
-fill_yin_include(struct lys_module *module, struct lyxml_elem *yin, struct lys_include *inc)
+fill_yin_include(struct lys_module *module, struct lyxml_elem *yin, struct lys_include *inc, struct unres_schema *unres)
 {
     struct lyxml_elem *child;
     const char *value;
@@ -2646,7 +2632,7 @@
             module_data = module->ctx->module_clb(value, inc->rev[0] ? inc->rev : NULL, module->ctx->module_clb_data,
                                                   &format, &module_data_free);
             if (module_data) {
-                inc->submodule = lys_submodule_parse(module, module_data, format, module->implemented);
+                inc->submodule = lys_submodule_parse(module, module_data, format, unres);
                 if (module_data_free) {
                     module_data_free(module_data);
                 } else {
@@ -2657,7 +2643,7 @@
             }
         } else {
             inc->submodule = (struct lys_submodule *)lyp_search_file(module->ctx, module, value,
-                                                                     inc->rev[0] ? inc->rev : NULL);
+                                                                     inc->rev[0] ? inc->rev : NULL, unres);
         }
     }
 
@@ -2680,16 +2666,6 @@
         goto error;
     }
 
-    /* check that belongs-to corresponds */
-    if (module->type) {
-        module = ((struct lys_submodule *)module)->belongsto;
-    }
-    if (inc->submodule->belongsto != module) {
-        LOGVAL(LYE_INARG, LOGLINE(yin), value, yin->name);
-        LOGERR(LY_EVALID, "The included module does not belongs-to the \"%s\" module", module->name);
-        goto error;
-    }
-
     return EXIT_SUCCESS;
 
 error:
@@ -2913,7 +2889,7 @@
     LOGDBG("YIN: parsing %s statement \"%s\"", yin->name, retval->name);
 
     /* insert the node into the schema tree */
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -3047,7 +3023,7 @@
     LOGDBG("YIN: parsing %s statement \"%s\"", yin->name, retval->name);
 
     /* insert the node into the schema tree */
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -3211,7 +3187,7 @@
 
     LOGDBG("YIN: parsing %s statement \"%s\"", yin->name, retval->name);
 
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -3349,7 +3325,7 @@
 
     LOGDBG("YIN: parsing %s statement \"%s\"", yin->name, retval->name);
 
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -3530,7 +3506,7 @@
 
     LOGDBG("YIN: parsing %s statement \"%s\"", yin->name, retval->name);
 
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -3967,7 +3943,7 @@
         }
     }
 
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -4187,7 +4163,7 @@
         }
     }
 
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -4303,7 +4279,7 @@
         }
     }
 
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -4431,7 +4407,7 @@
         }
     }
 
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -4574,7 +4550,7 @@
         }
     }
 
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -4730,7 +4706,7 @@
         }
     }
 
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -4856,7 +4832,7 @@
         }
     }
 
-    if (lys_node_addchild(parent, module, retval)) {
+    if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, retval)) {
         goto error;
     }
 
@@ -4918,18 +4894,25 @@
  * common code for yin_read_module() and yin_read_submodule()
  */
 static int
-read_sub_module(struct lys_module *module, struct lyxml_elem *yin, struct unres_schema *unres)
+read_sub_module(struct lys_module *module, struct lys_submodule *submodule, struct lyxml_elem *yin,
+                struct unres_schema *unres)
 {
     struct ly_ctx *ctx = module->ctx;
-    struct lys_submodule *submodule = (struct lys_submodule *)module;
     struct lyxml_elem *next, *child, *child2, root, grps, augs;
     struct lys_node *node = NULL;
+    struct lys_module *trg;
+    struct lys_import *aux_imp;
+    struct lys_include *aux_inc, inc;
     const char *value;
-    int i, r;
-    int belongsto_flag = 0;
+    int i, j, r;
+    int inc_size_aux = 0;
+    int version_flag = 0;
     /* counters */
     int c_imp = 0, c_rev = 0, c_tpdf = 0, c_ident = 0, c_inc = 0, c_aug = 0, c_ftrs = 0, c_dev = 0;
 
+    /* to simplify code, store the module/submodule being processed as trg */
+    trg = submodule ? (struct lys_module*)submodule : module;
+
     /* init */
     memset(&root, 0, sizeof root);
     memset(&grps, 0, sizeof grps);
@@ -4950,7 +4933,7 @@
             continue;
         }
 
-        if (!module->type && !strcmp(child->name, "namespace")) {
+        if (!submodule && !strcmp(child->name, "namespace")) {
             if (module->ns) {
                 LOGVAL(LYE_TOOMANY, LOGLINE(child), child->name, yin->name);
                 goto error;
@@ -4958,7 +4941,7 @@
             GETVAL(value, child, "uri");
             module->ns = lydict_insert(ctx, value, strlen(value));
             lyxml_free(ctx, child);
-        } else if (!module->type && !strcmp(child->name, "prefix")) {
+        } else if (!submodule && !strcmp(child->name, "prefix")) {
             if (module->prefix) {
                 LOGVAL(LYE_TOOMANY, LOGLINE(child), child->name, yin->name);
                 goto error;
@@ -4969,16 +4952,12 @@
             }
             module->prefix = lydict_insert(ctx, value, strlen(value));
             lyxml_free(ctx, child);
-        } else if (module->type && !strcmp(child->name, "belongs-to")) {
-            if (belongsto_flag) {
+        } else if (submodule && !strcmp(child->name, "belongs-to")) {
+            if (submodule->prefix) {
                 LOGVAL(LYE_TOOMANY, LOGLINE(child), child->name, yin->name);
                 goto error;
             }
-            belongsto_flag = 1;
             GETVAL(value, child, "module");
-            while (submodule->belongsto->type) {
-                submodule->belongsto = ((struct lys_submodule *)submodule->belongsto)->belongsto;
-            }
             if (value != submodule->belongsto->name) {
                 LOGVAL(LYE_INARG, LOGLINE(child), value, child->name);
                 goto error;
@@ -5003,7 +4982,7 @@
             if (check_identifier(value, LY_IDENT_NAME, LOGLINE(child->child), NULL, NULL)) {
                 goto error;
             }
-            module->prefix = lydict_insert(ctx, value, strlen(value));
+            submodule->prefix = lydict_insert(ctx, value, strlen(value));
 
             /* we are done with belongs-to */
             lyxml_free(ctx, child);
@@ -5022,8 +5001,8 @@
         } else if (!strcmp(child->name, "augment")) {
             c_aug++;
             /* keep augments separated, processed last */
-            lyxml_unlink_elem(module->ctx, child, 2);
-            lyxml_add_child(module->ctx, &augs, child);
+            lyxml_unlink_elem(ctx, child, 2);
+            lyxml_add_child(ctx, &augs, child);
 
         } else if (!strcmp(child->name, "feature")) {
             c_ftrs++;
@@ -5040,58 +5019,58 @@
                 !strcmp(child->name, "anyxml") ||
                 !strcmp(child->name, "rpc") ||
                 !strcmp(child->name, "notification")) {
-            lyxml_unlink_elem(module->ctx, child, 2);
-            lyxml_add_child(module->ctx, &root, child);
+            lyxml_unlink_elem(ctx, child, 2);
+            lyxml_add_child(ctx, &root, child);
 
         } else if (!strcmp(child->name, "grouping")) {
             /* keep groupings separated and process them before other data statements */
-            lyxml_unlink_elem(module->ctx, child, 2);
-            lyxml_add_child(module->ctx, &grps, child);
+            lyxml_unlink_elem(ctx, child, 2);
+            lyxml_add_child(ctx, &grps, child);
 
             /* optional statements */
         } else if (!strcmp(child->name, "description")) {
-            if (module->dsc) {
+            if (trg->dsc) {
                 LOGVAL(LYE_TOOMANY, LOGLINE(child), child->name, yin->name);
                 goto error;
             }
-            module->dsc = read_yin_subnode(ctx, child, "text");
+            trg->dsc = read_yin_subnode(ctx, child, "text");
             lyxml_free(ctx, child);
-            if (!module->dsc) {
+            if (!trg->dsc) {
                 goto error;
             }
         } else if (!strcmp(child->name, "reference")) {
-            if (module->ref) {
+            if (trg->ref) {
                 LOGVAL(LYE_TOOMANY, LOGLINE(child), child->name, yin->name);
                 goto error;
             }
-            module->ref = read_yin_subnode(ctx, child, "text");
+            trg->ref = read_yin_subnode(ctx, child, "text");
             lyxml_free(ctx, child);
-            if (!module->ref) {
+            if (!trg->ref) {
                 goto error;
             }
         } else if (!strcmp(child->name, "organization")) {
-            if (module->org) {
+            if (trg->org) {
                 LOGVAL(LYE_TOOMANY, LOGLINE(child), child->name, yin->name);
                 goto error;
             }
-            module->org = read_yin_subnode(ctx, child, "text");
+            trg->org = read_yin_subnode(ctx, child, "text");
             lyxml_free(ctx, child);
-            if (!module->org) {
+            if (!trg->org) {
                 goto error;
             }
         } else if (!strcmp(child->name, "contact")) {
-            if (module->contact) {
+            if (trg->contact) {
                 LOGVAL(LYE_TOOMANY, LOGLINE(child), child->name, yin->name);
                 goto error;
             }
-            module->contact = read_yin_subnode(ctx, child, "text");
+            trg->contact = read_yin_subnode(ctx, child, "text");
             lyxml_free(ctx, child);
-            if (!module->contact) {
+            if (!trg->contact) {
                 goto error;
             }
         } else if (!strcmp(child->name, "yang-version")) {
             /* TODO: support YANG 1.1 ? */
-            if (module->version) {
+            if (version_flag) {
                 LOGVAL(LYE_TOOMANY, LOGLINE(child), child->name, yin->name);
                 goto error;
             }
@@ -5100,7 +5079,10 @@
                 LOGVAL(LYE_INARG, LOGLINE(child), value, "yang-version");
                 goto error;
             }
-            module->version = 1;
+            version_flag = 1;
+            if (!submodule) {
+                module->version = 1;
+            } /* TODO else check for the submodule's same version as in main module, waits for YANG 1.1 support */
             lyxml_free(ctx, child);
 
         } else if (!strcmp(child->name, "extension")) {
@@ -5126,11 +5108,11 @@
         }
     }
 
-    if (module->type && !belongsto_flag) {
+    /* check for mandatory statements */
+    if (submodule && !submodule->prefix) {
         LOGVAL(LYE_MISSSTMT2, LOGLINE(yin), "belongs-to", "submodule");
         goto error;
-    } else {
-        /* check for mandatory statements */
+    } else if (!submodule) {
         if (!module->ns) {
             LOGVAL(LYE_MISSSTMT2, LOGLINE(yin), "namespace", "module");
             goto error;
@@ -5143,57 +5125,62 @@
 
     /* allocate arrays for elements with cardinality of 0..n */
     if (c_imp) {
-        module->imp = calloc(c_imp, sizeof *module->imp);
-        if (!module->imp) {
+        trg->imp = calloc(c_imp, sizeof *trg->imp);
+        if (!trg->imp) {
             LOGMEM;
             goto error;
         }
     }
     if (c_rev) {
-        module->rev = calloc(c_rev, sizeof *module->rev);
-        if (!module->rev) {
+        trg->rev = calloc(c_rev, sizeof *trg->rev);
+        if (!trg->rev) {
             LOGMEM;
             goto error;
         }
     }
     if (c_tpdf) {
-        module->tpdf = calloc(c_tpdf, sizeof *module->tpdf);
-        if (!module->tpdf) {
+        trg->tpdf = calloc(c_tpdf, sizeof *trg->tpdf);
+        if (!trg->tpdf) {
             LOGMEM;
             goto error;
         }
     }
     if (c_ident) {
-        module->ident = calloc(c_ident, sizeof *module->ident);
-        if (!module->ident) {
+        trg->ident = calloc(c_ident, sizeof *trg->ident);
+        if (!trg->ident) {
             LOGMEM;
             goto error;
         }
     }
     if (c_inc) {
-        module->inc = calloc(c_inc, sizeof *module->inc);
-        if (!module->inc) {
+        trg->inc = calloc(c_inc, sizeof *trg->inc);
+        if (!trg->inc) {
             LOGMEM;
             goto error;
         }
+        trg->inc_size = c_inc;
+        /* trg->inc_size can be updated by the included submodules,
+         * so we will use inc_size_aux here, trg->inc_size stores the
+         * target size of the array
+         */
     }
     if (c_aug) {
-        module->augment = calloc(c_aug, sizeof *module->augment);
-        if (!module->augment) {
+        trg->augment = calloc(c_aug, sizeof *trg->augment);
+        if (!trg->augment) {
             LOGMEM;
             goto error;
         }
     }
     if (c_ftrs) {
-        module->features = calloc(c_ftrs, sizeof *module->features);
-        if (!module->features) {
+        trg->features = calloc(c_ftrs, sizeof *trg->features);
+        if (!trg->features) {
             LOGMEM;
             goto error;
         }
     }
     if (c_dev) {
-        module->deviation = calloc(c_dev, sizeof *module->deviation);
-        if (!module->deviation) {
+        trg->deviation = calloc(c_dev, sizeof *trg->deviation);
+        if (!trg->deviation) {
             LOGMEM;
             goto error;
         }
@@ -5202,32 +5189,37 @@
     /* middle part - process nodes with cardinality of 0..n except the data nodes and augments */
     LY_TREE_FOR_SAFE(yin->child, next, child) {
         if (!strcmp(child->name, "import")) {
-            r = fill_yin_import(module, child, &module->imp[module->imp_size]);
-            module->imp_size++;
+            r = fill_yin_import(trg, child, &trg->imp[trg->imp_size]);
+            trg->imp_size++;
             if (r) {
                 goto error;
             }
 
             /* check duplicities in imported modules */
-            for (i = 0; i < module->imp_size - 1; i++) {
-                if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
-                    LOGVAL(LYE_SPEC, LOGLINE(child), "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
+            for (i = 0; i < trg->imp_size - 1; i++) {
+                if (!strcmp(trg->imp[i].module->name, trg->imp[trg->imp_size - 1].module->name)) {
+                    LOGVAL(LYE_SPEC, LOGLINE(child), "Importing module \"%s\" repeatedly.", trg->imp[i].module->name);
                     goto error;
                 }
             }
 
         } else if (!strcmp(child->name, "include")) {
-            r = fill_yin_include(module, child, &module->inc[module->inc_size]);
-            module->inc_size++;
+            memset(&inc, 0, sizeof inc);
+            /* 1) pass module, not trg, since we want to pass the main module
+             * 2) we cannot pass directly the structure in the array since
+             * submodule parser can realloc our array of includes */
+            r = fill_yin_include(module, child, &inc, unres);
+            memcpy(&trg->inc[inc_size_aux], &inc, sizeof inc);
+            inc_size_aux++;
             if (r) {
                 goto error;
             }
 
             /* check duplications in include submodules */
-            for (i = 0; i < module->inc_size - 1; i++) {
-                if (!strcmp(module->inc[i].submodule->name, module->inc[module->inc_size - 1].submodule->name)) {
-                    LOGVAL(LYE_SPEC, LOGLINE(child), "Importing module \"%s\" repeatedly.",
-                           module->inc[i].submodule->name);
+            for (i = 0; i < inc_size_aux - 1; i++) {
+                if (!strcmp(trg->inc[i].submodule->name, trg->inc[inc_size_aux - 1].submodule->name)) {
+                    LOGVAL(LYE_SPEC, LOGLINE(child), "Including submodule \"%s\" repeatedly.",
+                           trg->inc[i].submodule->name);
                     goto error;
                 }
             }
@@ -5237,10 +5229,10 @@
             if (check_date(value, LOGLINE(child))) {
                 goto error;
             }
-            memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
+            memcpy(trg->rev[trg->rev_size].date, value, LY_REV_SIZE - 1);
             /* check uniqueness of the revision date - not required by RFC */
-            for (i = 0; i < module->rev_size; i++) {
-                if (!strcmp(value, module->rev[i].date)) {
+            for (i = 0; i < trg->rev_size; i++) {
+                if (!strcmp(value, trg->rev[i].date)) {
                     LOGVAL(LYE_INARG, LOGLINE(child), value, child->name);
                     LOGVAL(LYE_SPEC, 0, "Revision is not unique.");
                 }
@@ -5248,21 +5240,21 @@
 
             LY_TREE_FOR(child->child, child2) {
                 if (!strcmp(child2->name, "description")) {
-                    if (module->rev[module->rev_size].dsc) {
+                    if (trg->rev[trg->rev_size].dsc) {
                         LOGVAL(LYE_TOOMANY, LOGLINE(child), child2->name, child->name);
                         goto error;
                     }
-                    module->rev[module->rev_size].dsc = read_yin_subnode(ctx, child2, "text");
-                    if (!module->rev[module->rev_size].dsc) {
+                    trg->rev[trg->rev_size].dsc = read_yin_subnode(ctx, child2, "text");
+                    if (!trg->rev[trg->rev_size].dsc) {
                         goto error;
                     }
                 } else if (!strcmp(child2->name, "reference")) {
-                    if (module->rev[module->rev_size].ref) {
+                    if (trg->rev[trg->rev_size].ref) {
                         LOGVAL(LYE_TOOMANY, LOGLINE(child), child2->name, child->name);
                         goto error;
                     }
-                    module->rev[module->rev_size].ref = read_yin_subnode(ctx, child2, "text");
-                    if (!module->rev[module->rev_size].ref) {
+                    trg->rev[trg->rev_size].ref = read_yin_subnode(ctx, child2, "text");
+                    if (!trg->rev[trg->rev_size].ref) {
                         goto error;
                     }
                 } else {
@@ -5272,56 +5264,56 @@
             }
 
             /* keep the latest revision at position 0 */
-            if (module->rev_size && strcmp(module->rev[module->rev_size].date, module->rev[0].date) > 0) {
+            if (trg->rev_size && strcmp(trg->rev[trg->rev_size].date, trg->rev[0].date) > 0) {
                 /* switch their position */
-                value = strdup(module->rev[0].date);
+                value = strdup(trg->rev[0].date);
                 if (!value) {
                     LOGMEM;
                     goto error;
                 }
-                memcpy(module->rev[0].date, module->rev[module->rev_size].date, LY_REV_SIZE - 1);
-                memcpy(module->rev[module->rev_size].date, value, LY_REV_SIZE - 1);
+                memcpy(trg->rev[0].date, trg->rev[trg->rev_size].date, LY_REV_SIZE - 1);
+                memcpy(trg->rev[trg->rev_size].date, value, LY_REV_SIZE - 1);
                 free((char *)value);
 
-                if (module->rev[0].dsc != module->rev[module->rev_size].dsc) {
-                    value = module->rev[0].dsc;
-                    module->rev[0].dsc = module->rev[module->rev_size].dsc;
-                    module->rev[module->rev_size].dsc = value;
+                if (trg->rev[0].dsc != trg->rev[trg->rev_size].dsc) {
+                    value = trg->rev[0].dsc;
+                    trg->rev[0].dsc = trg->rev[trg->rev_size].dsc;
+                    trg->rev[trg->rev_size].dsc = value;
                 }
 
-                if (module->rev[0].ref != module->rev[module->rev_size].ref) {
-                    value = module->rev[0].ref;
-                    module->rev[0].ref = module->rev[module->rev_size].ref;
-                    module->rev[module->rev_size].ref = value;
+                if (trg->rev[0].ref != trg->rev[trg->rev_size].ref) {
+                    value = trg->rev[0].ref;
+                    trg->rev[0].ref = trg->rev[trg->rev_size].ref;
+                    trg->rev[trg->rev_size].ref = value;
                 }
             }
 
-            module->rev_size++;
+            trg->rev_size++;
 
         } else if (!strcmp(child->name, "typedef")) {
-            r = fill_yin_typedef(module, NULL, child, &module->tpdf[module->tpdf_size], unres);
-            module->tpdf_size++;
+            r = fill_yin_typedef(trg, NULL, child, &trg->tpdf[trg->tpdf_size], unres);
+            trg->tpdf_size++;
             if (r) {
                 goto error;
             }
 
         } else if (!strcmp(child->name, "identity")) {
-            r = fill_yin_identity(module, child, &module->ident[module->ident_size], unres);
-            module->ident_size++;
+            r = fill_yin_identity(trg, child, &trg->ident[trg->ident_size], unres);
+            trg->ident_size++;
             if (r) {
                 goto error;
             }
 
         } else if (!strcmp(child->name, "feature")) {
-            r = fill_yin_feature(module, child, &module->features[module->features_size], unres);
-            module->features_size++;
+            r = fill_yin_feature(trg, child, &trg->features[trg->features_size], unres);
+            trg->features_size++;
             if (r) {
                 goto error;
             }
 
         } else if (!strcmp(child->name, "deviation")) {
-            r = fill_yin_deviation(module, child, &module->deviation[module->deviation_size], unres);
-            module->deviation_size++;
+            r = fill_yin_deviation(trg, child, &trg->deviation[trg->deviation_size], unres);
+            trg->deviation_size++;
             if (r) {
                 goto error;
             }
@@ -5329,11 +5321,97 @@
         }
     }
 
+    if (submodule) {
+        /* propagate imports into the main module */
+        for (i = r = 0; i < submodule->imp_size; i++) {
+            for (j = 0; j < module->imp_size; j++) {
+                if (submodule->imp[i].module == module->imp[j].module &&
+                        !strcmp(submodule->imp[i].rev, module->imp[j].rev)) {
+                    /* check prefix match */
+                    if (submodule->imp[i].prefix != module->imp[j].prefix) {
+                        LOGVAL(LYE_INID, LOGLINE(yin), submodule->imp[i].prefix,
+                               "non-matching prefixes of imported module in main module and submodule");
+                        goto error;
+                    }
+                    break;
+                }
+            }
+            if (j == module->imp_size) {
+                /* new import */
+                r++;
+            }
+        }
+        if (r) {
+            aux_imp = realloc(module->imp, (module->imp_size + r) * sizeof *module->imp);
+            if (!aux_imp) {
+                LOGMEM;
+                goto error;
+            }
+            module->imp = aux_imp;
+            for (i = r = 0; i < submodule->imp_size; i++) {
+                for (j = 0; j < module->imp_size; j++) {
+                    if (submodule->imp[i].module == module->imp[j].module) {
+                        break;
+                    }
+                }
+                if (j == module->imp_size) {
+                    /* new import */
+                    /* check prefix uniqueness */
+                    if (dup_prefix_check(submodule->imp[i].prefix, module)) {
+                        LOGVAL(LYE_DUPID, LOGLINE(yin), "prefix", submodule->imp[i].prefix);
+                        goto error;
+                    }
+                    memcpy(&module->imp[module->imp_size + r], &submodule->imp[i], sizeof *submodule->imp);
+                    module->imp[module->imp_size + r].external = 1;
+                    r++;
+                }
+            }
+            module->imp_size += r;
+        }
+
+        /* propagate imports into the main module */
+        for (i = r = 0; i < submodule->inc_size; i++) {
+            for (j = 0; j < module->inc_size; j++) {
+                if (submodule->inc[i].submodule == module->inc[j].submodule) {
+                    break;
+                }
+            }
+            if (j == module->inc_size) {
+                /* new include */
+                r++;
+            }
+        }
+
+        if (r) {
+            aux_inc = realloc(module->inc, (module->inc_size + r) * sizeof *module->inc);
+            if (!aux_inc) {
+                LOGMEM;
+                goto error;
+            }
+            module->inc = aux_inc;
+            for (i = r = 0; i < submodule->inc_size; i++) {
+                for (j = 0; j < module->inc_size; j++) {
+                    if (submodule->inc[i].submodule == module->inc[j].submodule) {
+                        break;
+                    }
+                }
+                if (j == module->inc_size) {
+                    /* new include */
+                    memcpy(&module->inc[module->inc_size + r], &submodule->inc[i], sizeof *submodule->inc);
+                    module->inc[module->inc_size + r].external = 1;
+                    r++;
+                }
+            }
+            module->inc_size += r;
+        }
+    }
+
     /* process data nodes. Start with groupings to allow uses
-     * refer to them
+     * refer to them. Submodule's data nodes are stored in the
+     * main module data tree.
      */
     LY_TREE_FOR_SAFE(grps.child, next, child) {
-        node = read_yin_grouping(module, NULL, child, 0, unres);
+        node = read_yin_grouping(trg, NULL, child, 0, unres);
         if (!node) {
             goto error;
         }
@@ -5372,8 +5450,8 @@
 
     /* ... and finally augments (last, so we can augment our data, for instance) */
     LY_TREE_FOR_SAFE(augs.child, next, child) {
-        r = fill_yin_augment(module, NULL, child, &module->augment[module->augment_size], unres);
-        module->augment_size++;
+        r = fill_yin_augment(trg, NULL, child, &trg->augment[trg->augment_size], unres);
+        trg->augment_size++;
 
         if (r) {
             goto error;
@@ -5395,24 +5473,12 @@
         lyxml_free(module->ctx, augs.child);
     }
 
-    free(unres->item);
-    unres->item = NULL;
-    free(unres->type);
-    unres->type = NULL;
-    free(unres->str_snode);
-    unres->str_snode = NULL;
-#ifndef NDEBUG
-    free(unres->line);
-    unres->line = NULL;
-#endif
-    unres->count = 0;
-
     return EXIT_FAILURE;
 }
 
 /* logs directly */
 struct lys_submodule *
-yin_read_submodule(struct lys_module *module, const char *data, int implement, struct unres_schema *unres)
+yin_read_submodule(struct lys_module *module, const char *data, struct unres_schema *unres)
 {
     struct lyxml_elem *yin;
     struct lys_submodule *submodule = NULL;
@@ -5446,10 +5512,9 @@
     submodule->name = lydict_insert(submodule->ctx, value, strlen(value));
     submodule->type = 1;
     submodule->belongsto = module;
-    submodule->implemented = (implement ? 1 : 0);
 
     LOGVRB("Reading submodule %s", submodule->name);
-    if (read_sub_module((struct lys_module *)submodule, yin, unres)) {
+    if (read_sub_module(module, submodule, yin, unres)) {
         goto error;
     }
 
@@ -5462,6 +5527,7 @@
 
 error:
     /* cleanup */
+    unres_schema_free((struct lys_module *)submodule, &unres);
     lyxml_free(module->ctx, yin);
     lys_submodule_free(submodule, 0);
 
@@ -5470,16 +5536,23 @@
 
 /* logs directly */
 struct lys_module *
-yin_read_module(struct ly_ctx *ctx, const char *data, int implement, struct unres_schema *unres)
+yin_read_module(struct ly_ctx *ctx, const char *data, int implement)
 {
     struct lyxml_elem *yin;
     struct lys_module *module = NULL, **newlist = NULL;
+    struct unres_schema *unres;
     const char *value;
     int i;
 
+    unres = calloc(1, sizeof *unres);
+    if (!unres) {
+        LOGMEM;
+        return NULL;
+    }
+
     yin = lyxml_read_data(ctx, data, 0);
     if (!yin) {
-        return NULL;
+       goto error;
     }
 
     /* check root element */
@@ -5505,7 +5578,12 @@
     module->implemented = (implement ? 1 : 0);
 
     LOGVRB("Reading module %s", module->name);
-    if (read_sub_module(module, yin, unres)) {
+    if (read_sub_module(module, NULL, yin, unres)) {
+        goto error;
+    }
+
+    /* resolve rest of unres items */
+    if (unres->count && resolve_unres_schema(module, unres)) {
         goto error;
     }
 
@@ -5530,16 +5608,15 @@
                 if (!module->rev_size || !strcmp(ctx->models.list[i]->rev[0].date, module->rev[0].date)) {
                     /* both have the same revision -> we already have the same module */
                     /* so free the new one and update the old one's implement flag if needed */
-                    lyxml_free(ctx, yin);
-                    lys_free(module, 0);
-                    unres->count = 0;
-
                     LOGVRB("Module %s already in context", ctx->models.list[i]->name);
 
-                    if (implement && !ctx->models.list[i]->implemented) {
-                        lyp_set_implemented(ctx->models.list[i]);
+                    lys_free(module, 0);
+                    module = ctx->models.list[i];
+                    if (implement && !module->implemented) {
+                        lyp_set_implemented(module);
                     }
-                    return ctx->models.list[i];
+
+                    goto success;
                 }
             }
             /* else (both elses) keep searching, for now the caller is just adding
@@ -5555,8 +5632,10 @@
     ctx->models.used++;
     ctx->models.module_set_id++;
 
+success:
     /* cleanup */
     lyxml_free(ctx, yin);
+    unres_schema_free(NULL, &unres);
 
     LOGVRB("Module %s successfully parsed", module->name);
 
@@ -5564,8 +5643,9 @@
 
 error:
     /* cleanup */
-    lyxml_free(ctx, yin);
+    unres_schema_free(module, &unres);
     lys_free(module, 0);
+    lyxml_free(ctx, yin);
 
     return NULL;
 }
diff --git a/src/printer_info.c b/src/printer_info.c
index 379a487..fa2f9c8 100644
--- a/src/printer_info.c
+++ b/src/printer_info.c
@@ -664,7 +664,7 @@
 info_print_data_with_include(struct lyout *out, const struct lys_module *mod)
 
 {
-    int first = 1, i;
+    int first = 1;
     struct lys_node *node;
 
     ly_print(out, "%-*s", INDENT_LEN, "Data: ");
@@ -679,22 +679,6 @@
         }
     }
 
-    for (i = 0; i < mod->inc_size; ++i) {
-        if (mod->inc[i].submodule->data) {
-            if (first) {
-                ly_print(out, "%s \"%s\"\n", strnodetype(mod->inc[i].submodule->data->nodetype), mod->inc[i].submodule->data->name);
-                node = mod->inc[i].submodule->data->next;
-            } else {
-                node = mod->inc[i].submodule->data;
-            }
-            first = 0;
-
-            for (; node; node = node->next) {
-                ly_print(out, "%*s%s \"%s\"\n", INDENT_LEN, "", strnodetype(node->nodetype), node->name);
-            }
-        }
-    }
-
     if (first) {
         ly_print(out, "\n");
     }
@@ -785,9 +769,12 @@
     info_print_text(out, module->ref, "Reference: ");
     info_print_text(out, module->org, "Org: ");
     info_print_text(out, module->contact, "Contact: ");
-    ly_print(out, "%-*s%s\n", INDENT_LEN, "YANG ver: ", (module->version == 2 ? "1.1" : "1.0"));
-    ly_print(out, "%-*s%s\n", INDENT_LEN, "Deviated: ", (module->deviated ? "yes" : "no"));
-    ly_print(out, "%-*s%s\n", INDENT_LEN, "Implement: ", (module->implemented ? "yes" : "no"));
+
+    /* inherited from main module */
+    ly_print(out, "%-*s%s\n", INDENT_LEN, "YANG ver: ", (module->belongsto->version == 2 ? "1.1" : "1.0"));
+    ly_print(out, "%-*s%s\n", INDENT_LEN, "Deviated: ", (module->belongsto->deviated ? "yes" : "no"));
+    ly_print(out, "%-*s%s\n", INDENT_LEN, "Implement: ", (module->belongsto->implemented ? "yes" : "no"));
+
     info_print_text(out, module->uri, "URI: ");
 
     info_print_revision(out, module->rev, module->rev_size);
diff --git a/src/printer_tree.c b/src/printer_tree.c
index 2bdd26e..39a347b 100644
--- a/src/printer_tree.c
+++ b/src/printer_tree.c
@@ -31,10 +31,9 @@
 /* spec_config = 0 (no special config status), 1 (read-only - rpc output, notification), 2 (write-only - rpc input) */
 static void tree_print_choice_content(struct lyout *out, const struct lys_module* module, int level, char *indent,
                                       unsigned int max_name_len, const struct lys_node *node, int mask,
-                                      int spec_config, const struct lys_submodule *main_submod);
+                                      int spec_config);
 static void tree_print_snode(struct lyout *out, const struct lys_module *module, int level, char *indent,
-                             unsigned int max_name_len, const struct lys_node *node, int mask, int spec_config,
-                             const struct lys_submodule *main_submod);
+                             unsigned int max_name_len, const struct lys_node *node, int mask, int spec_config);
 
 static int
 sibling_is_valid_child(const struct lys_node *node, int including)
@@ -67,10 +66,9 @@
 }
 
 static char *
-create_indent(int level, const char *old_indent, const struct lys_node *node, int shorthand,
-              const struct lys_submodule *main_submod)
+create_indent(int level, const char *old_indent, const struct lys_node *node, int shorthand)
 {
-    int next_is_case = 0, is_case = 0, has_next = 0, i, found;
+    int next_is_case = 0, is_case = 0, has_next = 0;
     char *new_indent = malloc((level * 4 + 1) * sizeof (char));
 
     if (!new_indent) {
@@ -96,57 +94,6 @@
     /* next is a node that will actually be printed */
     has_next = sibling_is_valid_child(node, 0);
 
-    /* there is no next, but we are in top-level of a submodule */
-    if (!has_next && (node->module->type == 1) && !node->parent) {
-        struct lys_submodule *submod = (struct lys_submodule *)node->module;
-        struct lys_module *mod = submod->belongsto;
-
-        /* a special case when we check the includes of a submodule */
-        if (main_submod) {
-            if (submod != main_submod) {
-                found = 0;
-                for (i = 0; i < main_submod->inc_size; i++) {
-                    if (found) {
-                        has_next = sibling_is_valid_child(main_submod->inc[i].submodule->data, 1);
-                        if (has_next) {
-                            break;
-                        }
-                    }
-                    if (!found && (submod == main_submod->inc[i].submodule)) {
-                        found = 1;
-                    }
-                }
-
-                if (!has_next) {
-                    has_next = sibling_is_valid_child(main_submod->data, 1);
-                }
-            }
-
-            goto strcat_indent;
-        }
-
-        /* find this submodule, check all the next ones for valid printed nodes */
-        found = 0;
-        for (i = 0; i < mod->inc_size; i++) {
-            /* we found ours, check all the following submodules and the module */
-            if (found) {
-                has_next = sibling_is_valid_child(mod->inc[i].submodule->data, 1);
-                if (has_next) {
-                    break;
-                }
-            }
-            if (!found && (submod == mod->inc[i].submodule)) {
-                found = 1;
-            }
-        }
-
-        /* there is nothing in submodules, check module */
-        if (!has_next) {
-            has_next = sibling_is_valid_child(mod->data, 1);
-        }
-    }
-
-strcat_indent:
     if (has_next && !next_is_case) {
         strcat(new_indent, "|  ");
     } else {
@@ -160,6 +107,7 @@
 get_max_name_len(const struct lys_module *module, const struct lys_node *node)
 {
     const struct lys_node *sub;
+    struct lys_module *mod;
     unsigned int max_name_len = 0, uses_max_name_len, name_len;
 
     LY_TREE_FOR(node, sub) {
@@ -171,7 +119,8 @@
         } else if (sub->nodetype &
                 (LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST
                 | LYS_ANYXML | LYS_CASE)) {
-            name_len = strlen(sub->name) + (module == sub->module ? 0 : strlen(sub->module->prefix)+1);
+            mod = lys_mainmodule(sub);
+            name_len = strlen(sub->name) + (module == mod ? 0 : strlen(mod->prefix)+1);
             if (name_len > max_name_len) {
                 max_name_len = name_len;
             }
@@ -214,7 +163,7 @@
 
 static void
 tree_print_inout(struct lyout *out, const struct lys_module *module, int level, char *indent,
-                 const struct lys_node *node, int spec_config, const struct lys_submodule *main_submod)
+                 const struct lys_node *node, int spec_config)
 {
     unsigned int max_child_len;
     char *new_indent;
@@ -225,14 +174,14 @@
     ly_print(out, "%s+--%s %s\n", indent, (spec_config == 1 ? "-w" : "ro"), (spec_config == 1 ? "input" : "output"));
 
     level++;
-    new_indent = create_indent(level, indent, node, 0, main_submod);
+    new_indent = create_indent(level, indent, node, 0);
 
     max_child_len = get_max_name_len(module, node->child);
 
     LY_TREE_FOR(node->child, sub) {
         tree_print_snode(out, module, level, new_indent, max_child_len, sub,
                          LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_USES,
-                         spec_config, main_submod);
+                         spec_config);
     }
 
     free(new_indent);
@@ -240,12 +189,13 @@
 
 static void
 tree_print_container(struct lyout *out, const struct lys_module *module, int level, char *indent,
-                     const struct lys_node *node, int spec_config, const struct lys_submodule *main_submod)
+                     const struct lys_node *node, int spec_config)
 {
     unsigned int max_child_len;
     char *new_indent;
     struct lys_node_container *cont = (struct lys_node_container *)node;
     struct lys_node *sub;
+    struct lys_module *nodemod;
 
     assert(spec_config >= 0 && spec_config <= 2);
 
@@ -260,8 +210,9 @@
         ly_print(out, "ro ");
     }
 
-    if (module != cont->module) {
-        ly_print(out, "%s:", cont->module->prefix);
+    nodemod = lys_mainmodule(node);
+    if (module != nodemod) {
+        ly_print(out, "%s:", nodemod->prefix);
     }
 
     ly_print(out, "%s%s", cont->name, (cont->presence ? "!" : ""));
@@ -271,14 +222,14 @@
     ly_print(out, "\n");
 
     level++;
-    new_indent = create_indent(level, indent, node, 0, main_submod);
+    new_indent = create_indent(level, indent, node, 0);
 
     max_child_len = get_max_name_len(module, node->child);
 
     LY_TREE_FOR(cont->child, sub) {
         tree_print_snode(out, module, level, new_indent, max_child_len, sub,
                          LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_USES,
-                         spec_config, main_submod);
+                         spec_config);
     }
 
     free(new_indent);
@@ -286,12 +237,13 @@
 
 static void
 tree_print_choice(struct lyout *out, const struct lys_module *module, int level, char *indent,
-                  const struct lys_node *node, int spec_config, const struct lys_submodule *main_submod)
+                  const struct lys_node *node, int spec_config)
 {
     unsigned int max_child_len;
     char *new_indent;
     struct lys_node_choice *choice = (struct lys_node_choice *)node;
     struct lys_node *sub;
+    struct lys_module *nodemod;
 
     assert(spec_config >= 0 && spec_config <= 2);
 
@@ -308,8 +260,9 @@
 
     ly_print(out, "(");
 
-    if (module != choice->module) {
-        ly_print(out, "%s:", choice->module->prefix);
+    nodemod = lys_mainmodule(node);
+    if (module != nodemod) {
+        ly_print(out, "%s:", nodemod->prefix);
     }
 
     ly_print(out, "%s)%s", choice->name, (choice->flags & LYS_MAND_TRUE ? "" : "?"));
@@ -323,14 +276,14 @@
     ly_print(out, "\n");
 
     level++;
-    new_indent = create_indent(level, indent, node, 0, main_submod);
+    new_indent = create_indent(level, indent, node, 0);
 
     max_child_len = get_max_name_len(module, node->child);
 
     LY_TREE_FOR(choice->child, sub) {
         tree_print_choice_content(out, module, level, new_indent, max_child_len, sub,
                                   LYS_CASE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML,
-                                  spec_config, main_submod);
+                                  spec_config);
     }
 
     free(new_indent);
@@ -338,17 +291,19 @@
 
 static void
 tree_print_case(struct lyout *out, const struct lys_module *module, int level, char *indent, unsigned int max_name_len,
-                const struct lys_node *node, int shorthand, int spec_config, const struct lys_submodule *main_submod)
+                const struct lys_node *node, int shorthand, int spec_config)
 {
     char *new_indent;
     struct lys_node_case *cas = (struct lys_node_case *)node;
     struct lys_node *sub;
+    struct lys_module *nodemod;
 
     ly_print(out, "%s%s--:(", indent,
             (cas->flags & LYS_STATUS_DEPRC ? "x" : (cas->flags & LYS_STATUS_OBSLT ? "o" : "+")));
 
-    if (module != cas->module) {
-        ly_print(out, "%s:", cas->module->prefix);
+    nodemod = lys_mainmodule(node);
+    if (module != nodemod) {
+        ly_print(out, "%s:", nodemod->prefix);
     }
 
     ly_print(out, "%s)", cas->name);
@@ -358,17 +313,17 @@
     ly_print(out, "\n");
 
     level++;
-    new_indent = create_indent(level, indent, node, shorthand, main_submod);
+    new_indent = create_indent(level, indent, node, shorthand);
 
     if (shorthand) {
         tree_print_snode(out, module, level, new_indent, max_name_len, node,
                          LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_USES,
-                         spec_config, main_submod);
+                         spec_config);
     } else {
         LY_TREE_FOR(node->child, sub) {
             tree_print_snode(out, module, level, new_indent, max_name_len, sub,
                              LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_USES,
-                             spec_config, main_submod);
+                             spec_config);
         }
     }
 
@@ -380,6 +335,7 @@
                   const struct lys_node *node, int spec_config)
 {
     uint8_t prefix_len;
+    struct lys_module *nodemod;
     struct lys_node_anyxml *anyxml = (struct lys_node_anyxml *)node;
 
     assert(spec_config >= 0 && spec_config <= 2);
@@ -396,9 +352,10 @@
     }
 
     prefix_len = 0;
-    if (module != anyxml->module) {
-        ly_print(out, "%s:", anyxml->module->prefix);
-        prefix_len = strlen(anyxml->module->prefix)+1;
+    nodemod = lys_mainmodule(node);
+    if (module != nodemod) {
+        ly_print(out, "%s:", nodemod->prefix);
+        prefix_len = strlen(nodemod->prefix)+1;
     }
 
     ly_print(out, "%s%s%*sanyxml", anyxml->name, (anyxml->flags & LYS_MAND_TRUE ? " " : "?"),
@@ -417,6 +374,7 @@
     struct lys_node_leaf *leaf = (struct lys_node_leaf *)node;
     struct lys_node *parent;
     struct lys_node_list *list;
+    struct lys_module *nodemod;
     int i, is_key = 0;
 
     assert(spec_config >= 0 && spec_config <= 2);
@@ -446,9 +404,10 @@
     }
 
     prefix_len = 0;
-    if (module != leaf->module) {
-        ly_print(out, "%s:", leaf->module->prefix);
-        prefix_len = strlen(leaf->module->prefix)+1;
+    nodemod = lys_mainmodule(node);
+    if (module != nodemod) {
+        ly_print(out, "%s:", nodemod->prefix);
+        prefix_len = strlen(nodemod->prefix)+1;
     }
 
     ly_print(out, "%s%s%*s", leaf->name, ((leaf->flags & LYS_MAND_TRUE) || is_key ? " " : "?"),
@@ -470,6 +429,7 @@
                     const struct lys_node *node, int spec_config)
 {
     struct lys_node_leaflist *leaflist = (struct lys_node_leaflist *)node;
+    struct lys_module *nodemod;
 
     assert(spec_config >= 0 && spec_config <= 2);
 
@@ -484,8 +444,9 @@
         ly_print(out, "ro ");
     }
 
-    if (module != leaflist->module) {
-        ly_print(out, "%s:", leaflist->module->prefix);
+    nodemod = lys_mainmodule(node);
+    if (module != nodemod) {
+        ly_print(out, "%s:", nodemod->prefix);
     }
 
     ly_print(out, "%s*%*s", leaflist->name, 3 + (int)(max_name_len - strlen(leaflist->name)), "   ");
@@ -499,13 +460,14 @@
 
 static void
 tree_print_list(struct lyout *out, const struct lys_module *module, int level, char *indent,
-                const struct lys_node *node, int spec_config, const struct lys_submodule *main_submod)
+                const struct lys_node *node, int spec_config)
 {
     int i;
     unsigned int max_child_len;
     char *new_indent;
     struct lys_node *sub;
     struct lys_node_list *list = (struct lys_node_list *)node;
+    struct lys_module *nodemod;
 
     ly_print(out, "%s%s--", indent,
             (list->flags & LYS_STATUS_DEPRC ? "x" : (list->flags & LYS_STATUS_OBSLT ? "o" : "+")));
@@ -518,8 +480,9 @@
         ly_print(out, "ro ");
     }
 
-    if (module != list->module) {
-        ly_print(out, "%s:", list->module->prefix);
+    nodemod = lys_mainmodule(node);
+    if (module != nodemod) {
+        ly_print(out, "%s:", nodemod->prefix);
     }
 
     ly_print(out, "%s*", list->name);
@@ -536,14 +499,14 @@
     ly_print(out, "\n");
 
     level++;
-    new_indent = create_indent(level, indent, node, 0, main_submod);
+    new_indent = create_indent(level, indent, node, 0);
 
     max_child_len = get_max_name_len(module, node->child);
 
     LY_TREE_FOR(node->child, sub) {
         tree_print_snode(out, module, level, new_indent, max_child_len, sub,
                          LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_USES | LYS_ANYXML,
-                         spec_config, main_submod);
+                         spec_config);
     }
 
     free(new_indent);
@@ -551,7 +514,7 @@
 
 static void
 tree_print_uses(struct lyout *out, const struct lys_module *module, int level, char *indent, unsigned int max_name_len,
-                const struct lys_node *node, int spec_config, const struct lys_submodule *main_submod)
+                const struct lys_node *node, int spec_config)
 {
     struct lys_node *child;
     struct lys_node_uses *uses = (struct lys_node_uses *)node;
@@ -559,13 +522,13 @@
     LY_TREE_FOR(uses->child, child) {
         tree_print_snode(out, module, level, indent, max_name_len, child,
                          LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_USES | LYS_ANYXML,
-                         spec_config, main_submod);
+                         spec_config);
     }
 }
 
 static void
 tree_print_rpc(struct lyout *out, const struct lys_module *module, int level, char *indent,
-               const struct lys_node *node, const struct lys_submodule *main_submod)
+               const struct lys_node *node)
 {
     char *new_indent;
     struct lys_node *child;
@@ -583,13 +546,13 @@
     ly_print(out, "\n");
 
     level++;
-    new_indent = create_indent(level, indent, node, 0, main_submod);
+    new_indent = create_indent(level, indent, node, 0);
 
     LY_TREE_FOR(rpc->child, child) {
         if (child->nodetype == LYS_INPUT) {
-            tree_print_inout(out, module, level, new_indent, child, 1, main_submod);
+            tree_print_inout(out, module, level, new_indent, child, 1);
         } else if (child->nodetype == LYS_OUTPUT) {
-            tree_print_inout(out, module, level, new_indent, child, 2, main_submod);
+            tree_print_inout(out, module, level, new_indent, child, 2);
         }
     }
 
@@ -598,7 +561,7 @@
 
 static void
 tree_print_notif(struct lyout *out, const struct lys_module *module, int level, char *indent,
-                 const struct lys_node *node, const struct lys_submodule *main_submod)
+                 const struct lys_node *node)
 {
     unsigned int max_child_len;
     char *new_indent;
@@ -618,14 +581,13 @@
     ly_print(out, "\n");
 
     level++;
-    new_indent = create_indent(level, indent, node, 0, main_submod);
+    new_indent = create_indent(level, indent, node, 0);
 
     max_child_len = get_max_name_len(module, node->child);
 
     LY_TREE_FOR(notif->child, child) {
         tree_print_snode(out, module, level, new_indent, max_child_len, child,
-                         LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_USES,
-                         2, main_submod);
+                         LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_USES, 2);
     }
 
     free(new_indent);
@@ -633,8 +595,7 @@
 
 static void
 tree_print_choice_content(struct lyout *out, const struct lys_module *module, int level, char *indent,
-                          unsigned int max_name_len, const struct lys_node *node, int mask, int spec_config,
-                          const struct lys_submodule *main_submod)
+                          unsigned int max_name_len, const struct lys_node *node, int mask, int spec_config)
 {
     if (lys_is_disabled(node, 0)) {
         return;
@@ -642,9 +603,9 @@
 
     if (node->nodetype & mask) {
         if (node->nodetype == LYS_CASE) {
-            tree_print_case(out, module, level, indent, max_name_len, node, 0, spec_config, main_submod);
+            tree_print_case(out, module, level, indent, max_name_len, node, 0, spec_config);
         } else {
-            tree_print_case(out, module, level, indent, max_name_len, node, 1, spec_config, main_submod);
+            tree_print_case(out, module, level, indent, max_name_len, node, 1, spec_config);
         }
     }
 }
@@ -652,8 +613,7 @@
 /* spec_config = 0 (no special config status), 1 (read-only - rpc output, notification), 2 (write-only - rpc input) */
 static void
 tree_print_snode(struct lyout *out, const struct lys_module *module, int level, char *indent,
-                 unsigned int max_name_len, const struct lys_node *node, int mask, int spec_config,
-                 const struct lys_submodule *main_submod)
+                 unsigned int max_name_len, const struct lys_node *node, int mask, int spec_config)
 {
     if (lys_is_disabled(node, 0)) {
         return;
@@ -661,10 +621,10 @@
 
     switch (node->nodetype & mask) {
     case LYS_CONTAINER:
-        tree_print_container(out, module, level, indent, node, spec_config, main_submod);
+        tree_print_container(out, module, level, indent, node, spec_config);
         break;
     case LYS_CHOICE:
-        tree_print_choice(out, module, level, indent, node, spec_config, main_submod);
+        tree_print_choice(out, module, level, indent, node, spec_config);
         break;
     case LYS_LEAF:
         tree_print_leaf(out, module, indent, max_name_len, node, spec_config);
@@ -673,13 +633,13 @@
         tree_print_leaflist(out, module, indent, max_name_len, node, spec_config);
         break;
     case LYS_LIST:
-        tree_print_list(out, module, level, indent, node, spec_config, main_submod);
+        tree_print_list(out, module, level, indent, node, spec_config);
         break;
     case LYS_ANYXML:
         tree_print_anyxml(out, module, indent, max_name_len, node, spec_config);
         break;
     case LYS_USES:
-        tree_print_uses(out, module, level, indent, max_name_len, node, spec_config, main_submod);
+        tree_print_uses(out, module, level, indent, max_name_len, node, spec_config);
         break;
     default:
         break;
@@ -690,9 +650,8 @@
 tree_print_model(struct lyout *out, const struct lys_module *module)
 {
     struct lys_node *node;
-    struct lys_submodule *submod;
     unsigned int max_child_len;
-    int level = 1, i, have_rpcs = 0, have_notifs = 0;
+    int level = 1, have_rpcs = 0, have_notifs = 0;
     char *indent = malloc((level * 4 + 1) * sizeof (char));
 
     if (!indent) {
@@ -702,24 +661,12 @@
     strcpy(indent, "   ");
 
     if (module->type) {
-        submod = (struct lys_submodule *)module;
-        ly_print(out, "submodule: %s (belongs-to %s)\n", submod->name, submod->belongsto->name);
+        ly_print(out, "submodule: %s (belongs-to %s)\n", module->name,
+                 ((struct lys_submodule *)module)->belongsto->name);
     } else {
-        submod = NULL;
         ly_print(out, "module: %s\n", module->name);
     }
 
-    /* included submodules */
-    for (i = 0; i < module->inc_size; i++) {
-        max_child_len = get_max_name_len((struct lys_module *)module->inc[i].submodule, module->inc[i].submodule->data);
-
-        LY_TREE_FOR(module->inc[i].submodule->data, node) {
-            tree_print_snode(out, (struct lys_module *)module->inc[i].submodule, level, indent, max_child_len, node,
-                             LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST
-                             | LYS_ANYXML | LYS_USES, 0, submod);
-        }
-    }
-
     /* module */
     max_child_len = get_max_name_len(module, module->data);
     level++;
@@ -739,7 +686,7 @@
         default:
             tree_print_snode(out, module, level, indent, max_child_len, node,
                              LYS_CHOICE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST
-                             | LYS_ANYXML | LYS_USES, 0, submod);
+                             | LYS_ANYXML | LYS_USES, 0);
             break;
         }
     }
@@ -747,23 +694,12 @@
     /* rpc */
     if (have_rpcs) {
         ly_print(out, "rpcs:\n");
-        for (i = 0; i < module->inc_size; i++) {
-            LY_TREE_FOR(module->inc[i].submodule->data, node) {
-                if (!have_rpcs) {
-                    break;
-                }
-                if (node->nodetype == LYS_RPC) {
-                    tree_print_rpc(out, (struct lys_module *)module->inc[i].submodule, level, indent, node, submod);
-                    have_rpcs--;
-                }
-            }
-        }
         LY_TREE_FOR(module->data, node) {
             if (!have_rpcs) {
                 break;
             }
             if (node->nodetype == LYS_RPC) {
-                tree_print_rpc(out, module, level, indent, node, submod);
+                tree_print_rpc(out, module, level, indent, node);
                 have_rpcs--;
             }
         }
@@ -772,23 +708,12 @@
     /* notification */
     if (have_notifs) {
         ly_print(out, "notifications:\n");
-        for (i = 0; i < module->inc_size; i++) {
-            LY_TREE_FOR(module->inc[i].submodule->data, node) {
-                if (!have_notifs) {
-                    break;
-                }
-                if (node->nodetype == LYS_NOTIF) {
-                    tree_print_notif(out, (struct lys_module *)module->inc[i].submodule, level, indent, node, submod);
-                    have_notifs--;
-                }
-            }
-        }
         LY_TREE_FOR(module->data, node) {
             if (!have_notifs) {
                 break;
             }
             if (node->nodetype == LYS_NOTIF) {
-                tree_print_notif(out, module, level, indent, node, submod);
+                tree_print_notif(out, module, level, indent, node);
                 have_notifs--;
             }
         }
diff --git a/src/printer_yang.c b/src/printer_yang.c
index e861370..a4d612b 100644
--- a/src/printer_yang.c
+++ b/src/printer_yang.c
@@ -258,6 +258,7 @@
     int i;
     int flag = 0, flag2;
     const char *str;
+    struct lys_module *mod;
 
     if (type->module_name) {
         str = transform_json2xml(module, type->module_name, NULL, NULL, NULL);
@@ -311,11 +312,13 @@
         break;
     case LY_TYPE_IDENT:
         yang_print_open(out, &flag);
-        if (module == type->info.ident.ref->module) {
+        mod = type->info.ident.ref->module->type ?
+                        ((struct lys_submodule *)type->info.ident.ref->module)->belongsto :
+                        type->info.ident.ref->module;
+        if (module == mod) {
             ly_print(out, "%*sbase %s;\n", LEVEL, INDENT, type->info.ident.ref->name);
         } else {
-            ly_print(out, "%*sbase %s:%s;\n", LEVEL, INDENT, type->info.ident.ref->module->prefix,
-                    type->info.ident.ref->name);
+            ly_print(out, "%*sbase %s:%s;\n", LEVEL, INDENT, mod->prefix, type->info.ident.ref->name);
         }
         break;
     case LY_TYPE_INST:
@@ -655,8 +658,8 @@
     }
 
     LY_TREE_FOR(node->child, sub) {
-        /* augment */
-        if (sub->parent != node) {
+        /* augment and data from submodules */
+        if (sub->module != node->module) {
             continue;
         }
         yang_print_open(out, &flag);
@@ -690,8 +693,8 @@
     }
 
     LY_TREE_FOR(node->child, sub) {
-        /* augment */
-        if (sub->parent != node) {
+        /* augment and data from submodules */
+        if (sub->module != node->module) {
             continue;
         }
         yang_print_snode(out, level, sub,
@@ -729,8 +732,8 @@
     }
 
     LY_TREE_FOR(node->child, sub) {
-        /* augment */
-        if (sub->parent != node) {
+        /* augment and data from submodules */
+        if (sub->module != node->module) {
             continue;
         }
         yang_print_snode(out, level, sub,
@@ -890,8 +893,8 @@
         yang_print_typedef(out, level, list->module, &list->tpdf[i]);
     }
     LY_TREE_FOR(node->child, sub) {
-        /* augment */
-        if (sub->parent != node) {
+        /* augment and data from submodules */
+        if (sub->module != node->module) {
             continue;
         }
         yang_print_snode(out, level, sub,
@@ -981,8 +984,8 @@
     }
 
     LY_TREE_FOR(node->child, sub) {
-        /* augment */
-        if (sub->parent != node) {
+        /* augment and data from submodules */
+        if (sub->module != node->module) {
             continue;
         }
         yang_print_snode(out, level, sub,
@@ -1017,6 +1020,10 @@
     }
 
     LY_TREE_FOR(node->child, sub) {
+        /* augment and data from submodules */
+        if (sub->module != node->module) {
+            continue;
+        }
         yang_print_open(out, &flag);
         yang_print_snode(out, level, sub, LYS_GROUPING | LYS_INPUT | LYS_OUTPUT);
     }
@@ -1048,8 +1055,8 @@
     }
 
     LY_TREE_FOR(node->child, sub) {
-        /* augment */
-        if (sub->parent != node) {
+        /* augment and data from submodules */
+        if (sub->module != node->module) {
             continue;
         }
         yang_print_open(out, &flag);
@@ -1116,7 +1123,8 @@
         ly_print(out, "submodule %s {%s\n", module->name, (module->deviated ? " // DEVIATED" : ""));
         level++;
         if (module->version) {
-            ly_print(out, "%*syang-version %s;\n", LEVEL, INDENT, module->version == 1 ? "1" : "1.1");
+            ly_print(out, "%*syang-version %s;\n", LEVEL, INDENT,
+                     ((struct lys_submodule *)module)->belongsto->version == 2 ? "1.1" : "1");
         }
         ly_print(out, "%*sbelongs-to %s {\n", LEVEL, INDENT, ((struct lys_submodule *)module)->belongsto->name);
         level++;
@@ -1127,7 +1135,7 @@
         ly_print(out, "module %s {%s\n", module->name, (module->deviated ? " // DEVIATED" : ""));
         level++;
         if (module->version) {
-            ly_print(out, "%*syang-version %s;\n", LEVEL, INDENT, module->version == 1 ? "1" : "1.1");
+            ly_print(out, "%*syang-version %s;\n", LEVEL, INDENT, module->version == 2 ? "1.1" : "1");
         }
         ly_print(out, "%*snamespace \"%s\";\n", LEVEL, INDENT, module->ns);
         ly_print(out, "%*sprefix %s;\n", LEVEL, INDENT, module->prefix);
@@ -1138,6 +1146,9 @@
         ly_print(out, "\n");
     }
     for (i = 0; i < module->imp_size; i++) {
+        if (module->imp[i].external) {
+            continue;
+        }
         ly_print(out, "%*simport \"%s\" {\n", LEVEL, INDENT, module->imp[i].module->name);
         level++;
         ly_print(out, "%*sprefix %s;\n", LEVEL, INDENT, module->imp[i].prefix);
@@ -1148,6 +1159,9 @@
         ly_print(out, "%*s}", LEVEL, INDENT);
     }
     for (i = 0; i < module->inc_size; i++) {
+        if (module->inc[i].external) {
+            continue;
+        }
         if (module->inc[i].rev[0]) {
             ly_print(out, "%*sinclude \"%s\" {\n", LEVEL, INDENT, module->inc[i].submodule->name);
             level++;
@@ -1219,6 +1233,9 @@
     }
 
     LY_TREE_FOR(module->data, node) {
+        if (node->module != module) {
+            continue;
+        }
         ly_print(out, "\n");
         switch(node->nodetype) {
         case LYS_RPC:
diff --git a/src/resolve.c b/src/resolve.c
index 92c3afd..7b172d7 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -1277,7 +1277,7 @@
 
             parent = parent->parent;
         }
-    } else if (mod_name) {
+    } else {
         /* get module where to search */
         module = lys_get_import_module(module, NULL, 0, mod_name, 0);
         if (!module) {
@@ -1296,7 +1296,7 @@
     }
 
     /* search in submodules */
-    for (i = 0; i < module->inc_size; i++) {
+    for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
         for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
             if (!strcmp(module->inc[i].submodule->tpdf[j].name, name) && module->inc[i].submodule->tpdf[j].type.base) {
                 if (ret) {
@@ -1504,18 +1504,17 @@
         return -1;
     }
 
-    if (mod_prefix) {
-        module = lys_get_import_module(uses->module, mod_prefix, mod_prefix_len, NULL, 0);
-        if (!module) {
-            LOGVAL(LYE_INMOD_LEN, line, mod_prefix_len, mod_prefix);
-            return -1;
-        }
+    module = lys_get_import_module(uses->module, mod_prefix, mod_prefix_len, NULL, 0);
+    if (!module) {
+        LOGVAL(LYE_INMOD_LEN, line, mod_prefix_len, mod_prefix);
+        return -1;
+    } else if (module != uses->module) {
         start = module->data;
     } else {
         start = (struct lys_node *)uses;
     }
 
-    uses->grp = lys_find_grouping_up(name, start, 1);
+    uses->grp = lys_find_grouping_up(name, start);
     if (uses->grp) {
         return EXIT_SUCCESS;
     }
@@ -1557,29 +1556,14 @@
         return -1;
     }
 
-    if (mod_name) {
-        /* search in imported modules */
-        module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
-        if (!module) {
-            /* identity refers unknown data model */
-            LOGVAL(LYE_INMOD_LEN, line, mod_name_len, mod_name);
-            return -1;
-        }
-    } else {
-        /* search in submodules */
-        for (i = 0; i < module->inc_size; i++) {
-            for (j = 0; j < module->inc[i].submodule->features_size; j++) {
-                if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
-                    if (ret) {
-                        *ret = &(module->inc[i].submodule->features[j]);
-                    }
-                    return EXIT_SUCCESS;
-                }
-            }
-        }
+    module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
+    if (!module) {
+        /* identity refers unknown data model */
+        LOGVAL(LYE_INMOD_LEN, line, mod_name_len, mod_name);
+        return -1;
     }
 
-    /* search in the identified module */
+    /* search in the identified module ... */
     for (j = 0; j < module->features_size; j++) {
         if (!strcmp(name, module->features[j].name)) {
             if (ret) {
@@ -1594,6 +1578,25 @@
             return EXIT_SUCCESS;
         }
     }
+    /* ... and all its submodules */
+    for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
+        for (j = 0; j < module->inc[i].submodule->features_size; j++) {
+            if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
+                if (ret) {
+                    /* check status */
+                    node = (struct lys_node *)*ret;
+                    if (check_status(node->flags, node->module, node->name,
+                                     module->inc[i].submodule->features[j].flags,
+                                     module->inc[i].submodule->features[j].module,
+                                     module->inc[i].submodule->features[j].name, line)) {
+                        return -1;
+                    }
+                    *ret = &(module->inc[i].submodule->features[j]);
+                }
+                return EXIT_SUCCESS;
+            }
+        }
+    }
 
     /* not found */
     if (!first) {
@@ -1688,13 +1691,11 @@
 resolve_schema_nodeid(const char *id, const struct lys_node *start, const struct lys_module *mod, LYS_NODE node_type,
                       const struct lys_node **ret)
 {
-    const char *name, *mod_name, *pref_mod_name;
+    const char *name, *mod_name;
     const struct lys_node *sibling;
     int i, opts, nam_len, mod_name_len, is_relative = -1;
     /* resolved import module from the start module, it must match the next node-name-match sibling */
     const struct lys_module *prefix_mod;
-    /* 0 - in module, 1 - in 1st submodule, 2 - in 2nd submodule, ... */
-    uint8_t in_submod = 0;
 
     assert(mod);
     assert(id);
@@ -1716,15 +1717,11 @@
 
     /* absolute-schema-nodeid */
     if (!is_relative) {
-        if (mod_name) {
-            prefix_mod = lys_get_import_module(mod, NULL, 0, mod_name, mod_name_len);
-            if (!prefix_mod) {
-                return -1;
-            }
-            start = prefix_mod->data;
-        } else {
-            start = mod->data;
+        prefix_mod = lys_get_import_module(mod, NULL, 0, mod_name, mod_name_len);
+        if (!prefix_mod) {
+            return -1;
         }
+        start = prefix_mod->data;
     /* descendant-schema-nodeid */
     } else if (!start) {
         /* start must be set in this case */
@@ -1741,46 +1738,21 @@
                     || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT)))) {
 
                 /* get module for module name match check */
-                if (mod_name) {
-                    prefix_mod = lys_get_import_module(mod, NULL, 0, mod_name, mod_name_len);
-
-                    if (!prefix_mod && (node_type == LYS_AUGMENT)) {
-                        /* we want augment nodes in this case */
-                        prefix_mod = sibling->module;
-                        if (prefix_mod->type) {
-                            pref_mod_name = ((struct lys_submodule *)prefix_mod)->belongsto->name;
-                        } else {
-                            pref_mod_name = prefix_mod->name;
-                        }
-                        if (strncmp(pref_mod_name, mod_name, mod_name_len) || pref_mod_name[mod_name_len]) {
-                            prefix_mod = NULL;
-                        }
-                    }
-                    if (!prefix_mod) {
+                prefix_mod = lys_get_import_module(mod, NULL, 0, mod_name, mod_name_len);
+                if (!prefix_mod && (node_type == LYS_AUGMENT)) {
+                    /* we want augment nodes in this case */
+                    prefix_mod = sibling->module;
+                    if (strncmp(prefix_mod->name, mod_name, mod_name_len) || prefix_mod->name[mod_name_len]) {
                         return -1;
                     }
-                } else {
-                    prefix_mod = mod;
+                } else if (!prefix_mod) {
+                    return -1;
                 }
 
                 /* modules need to always be checked, we want to skip augments (no other reason to check them) */
-                if (prefix_mod != sibling->module) {
-                    if (in_submod) {
-                        if (prefix_mod->type) {
-                            prefix_mod = ((struct lys_submodule *)prefix_mod)->belongsto;
-                        }
-                        if (sibling->module->type) {
-                            if (prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto) {
-                                continue;
-                            }
-                        } else {
-                            if (prefix_mod != sibling->module) {
-                                continue;
-                            }
-                        }
-                    } else {
-                        continue;
-                    }
+                if ((!sibling->module->type && prefix_mod != sibling->module) ||
+                       (sibling->module->type && prefix_mod != ((struct lys_submodule *)sibling->module)->belongsto)) {
+                    continue;
                 }
 
                 /* the result node? */
@@ -1818,15 +1790,7 @@
 
         /* no match */
         if (!sibling) {
-            /* are we done with the included submodules as well? */
-            if (start->parent || (in_submod == mod->inc_size)) {
-                return EXIT_FAILURE;
-            }
-
-            /* we aren't, check the next one */
-            ++in_submod;
-            start = mod->inc[in_submod-1].submodule->data;
-            continue;
+            return EXIT_FAILURE;
         }
 
         if ((i = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
@@ -2363,6 +2327,7 @@
                         const struct lys_node **ret)
 {
     const struct lys_node *node;
+    const struct lys_module *mod;
     const char *id, *prefix, *name;
     int pref_len, nam_len, parent_times, has_predicate;
     int i, first_iter, rc;
@@ -2380,7 +2345,10 @@
 
         if (first_iter) {
             if (parent_times == -1) {
-                node = parent_node->module->data;
+                /* resolve prefix of the module */
+                mod = lys_get_import_module(parent_node->module, NULL, 0, prefix, pref_len);
+                /* get start node */
+                node = mod ? mod->data : NULL;
                 if (!node) {
                     if (!first) {
                         LOGVAL(LYE_NORESOLV, line, path);
@@ -2427,12 +2395,14 @@
             }
 
             if (!prefix) {
-                prefix = parent_node->module->name;
+                mod = parent_node->module;
+                prefix = mod->type ? ((struct lys_submodule *)mod)->belongsto->name : mod->name;
             }
             first_iter = 0;
         } else {
             if (!prefix) {
-                prefix = node->module->name;
+                mod = parent_node->module;
+                prefix = mod->type ? ((struct lys_submodule *)mod)->belongsto->name : mod->name;
             }
             node = node->child;
         }
@@ -2718,6 +2688,7 @@
 {
     int rc;
     struct lys_node *sub;
+    struct lys_module *mm;
 
     assert(aug);
 
@@ -2741,9 +2712,10 @@
         inherit_config_flag(sub);
     }
 
-    /* check identifier uniquness as in lys_node_addchild() */
+    /* check identifier uniqueness as in lys_node_addchild() */
+    mm = aug->module->type ? ((struct lys_submodule *)aug->module)->belongsto : aug->module;
     LY_TREE_FOR(aug->child, sub) {
-        if (lys_check_id(sub, aug->parent, aug->module)) {
+        if (lys_check_id(sub, aug->parent, mm)) {
             return -1;
         }
     }
@@ -2786,16 +2758,11 @@
 
     /* copy the data nodes from grouping into the uses context */
     LY_TREE_FOR(uses->grp->child, node_aux) {
-        node = lys_node_dup(uses->module, node_aux, uses->flags, uses->nacm, 1, unres);
+        node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->flags, uses->nacm, unres);
         if (!node) {
             LOGVAL(LYE_SPEC, line, "Copying data from grouping failed.");
             return -1;
         }
-        if (lys_node_addchild((struct lys_node *)uses, NULL, node)) {
-            /* error logged */
-            lys_node_free(node);
-            return -1;
-        }
     }
     ctx = uses->module->ctx;
 
@@ -2986,7 +2953,7 @@
 
     /* search submodules */
     if (!base_iter) {
-        for (j = 0; j < module->inc_size; j++) {
+        for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
             for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
                 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
 
@@ -3080,27 +3047,24 @@
         name = basename;
     }
 
-    if (mod_name_len) {
-        /* get module where to search */
-        module = lys_get_import_module(module, NULL, 0, basename, mod_name_len);
-        if (!module) {
-            /* identity refers unknown data model */
-            LOGVAL(LYE_INMOD, line, basename);
-            return -1;
-        }
-    } else {
-        /* search in submodules */
-        for (i = 0; i < module->inc_size; i++) {
-            if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
-                goto success;
-            }
-        }
+    /* get module where to search */
+    module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
+    if (!module) {
+        /* identity refers unknown data model */
+        LOGVAL(LYE_INMOD, line, basename);
+        return -1;
     }
 
-    /* search in the identified module */
+    /* search in the identified module ... */
     if (!resolve_base_ident_sub(module, ident, name, ret)) {
         goto success;
     }
+    /* and all its submodules */
+    for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
+        if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
+            goto success;
+        }
+    }
 
     if (!first) {
         LOGVAL(LYE_INARG, line, basename, parent);
@@ -3266,7 +3230,7 @@
 resolve_list_keys(struct lys_node_list *list, const char *keys_str, int first, uint32_t line)
 {
     int i, len, rc;
-    const char *value;
+    const char *value, *modname;
 
     for (i = 0; i < list->keys_size; ++i) {
         /* get the key name */
@@ -3279,7 +3243,8 @@
             len = strlen(keys_str);
         }
 
-        rc = lys_get_sibling(list->child, list->module->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
+        modname = list->module->type ? ((struct lys_submodule *)list->module)->belongsto->name : list->module->name;
+        rc = lys_get_sibling(list->child, modname, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
         if (rc) {
             if ((rc == -1) || !first) {
                 LOGVAL(LYE_INRESOLV, line, "list keys", keys_str);
@@ -3767,6 +3732,7 @@
         return -1;
     }
 
+    unres->count = 0;
     return EXIT_SUCCESS;
 }
 
@@ -3845,6 +3811,12 @@
         return -1;
     }
     unres->str_snode[unres->count-1] = snode;
+    unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
+    if (!unres->module) {
+        LOGMEM;
+        return -1;
+    }
+    unres->module[unres->count-1] = mod;
 #ifndef NDEBUG
     unres->line = ly_realloc(unres->line, unres->count*sizeof *unres->line);
     if (!unres->line) {
@@ -3913,23 +3885,41 @@
 }
 
 void
-unres_schema_free(struct ly_ctx *ctx, struct unres_schema *unres)
+unres_schema_free(struct lys_module *module, struct unres_schema **unres)
 {
     uint32_t i;
+    unsigned int unresolved = 0;
 
-    for (i = 0; i < unres->count; ++i) {
-        if (unres->type[i] == UNRES_TYPE_DER) {
-            lyxml_free(ctx, (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der);
-        }
+    if (!unres || !(*unres)) {
+        return;
     }
 
-    free(unres->item);
-    free(unres->type);
-    free(unres->str_snode);
+    assert(module || (*unres)->count == 0);
+
+    for (i = 0; i < (*unres)->count; ++i) {
+        if ((*unres)->module[i] != module) {
+            if ((*unres)->type[i] != UNRES_RESOLVED) {
+                unresolved++;
+            }
+            continue;
+        }
+        if ((*unres)->type[i] == UNRES_TYPE_DER) {
+            lyxml_free(module->ctx, (struct lyxml_elem *)((struct lys_type *)(*unres)->item[i])->der);
+        }
+        (*unres)->type[i] = UNRES_RESOLVED;
+    }
+
+    if (!module || (!unresolved && !module->type)) {
+        free((*unres)->item);
+        free((*unres)->type);
+        free((*unres)->str_snode);
+        free((*unres)->module);
 #ifndef NDEBUG
-    free(unres->line);
+        free((*unres)->line);
 #endif
-    free(unres);
+        free((*unres));
+        (*unres) = NULL;
+    }
 }
 
 /* logs directly */
diff --git a/src/resolve.h b/src/resolve.h
index 030a9f4..c830989 100644
--- a/src/resolve.h
+++ b/src/resolve.h
@@ -68,6 +68,7 @@
     void **item;            /* array of pointers, each is determined by the type (one of lys_* structures) */
     enum UNRES_ITEM *type;  /* array of unres types */
     void **str_snode;       /* array of pointers, each is determined by the type (a string, a lys_node *, or NULL) */
+    struct lys_module **module; /* array of pointers to the item's module */
 #ifndef NDEBUG
     uint32_t *line;         /* array of lines for each unres item */
 #endif
@@ -128,7 +129,7 @@
 
 int unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type);
 
-void unres_schema_free(struct ly_ctx *ctx, struct unres_schema *unres);
+void unres_schema_free(struct lys_module *module, struct unres_schema **unres);
 
 int resolve_unres_data_item(struct lyd_node *dnode, enum UNRES_ITEM type, int first, uint32_t line);
 
diff --git a/src/tree_internal.h b/src/tree_internal.h
index 3bfefe6..c544b63 100644
--- a/src/tree_internal.h
+++ b/src/tree_internal.h
@@ -77,10 +77,11 @@
  * @param[in] module Schema tree where to connect the submodule, belongs-to value must match.
  * @param[in] data String containing the submodule specification in the given \p format.
  * @param[in] format Format of the data to read.
- * @param[in] implement Flag to distinguish implemented and just imported (sub)modules.
+ * @param[in] unres TODO provide description
  * @return Created submodule structure or NULL in case of error.
  */
-struct lys_submodule *lys_submodule_parse(struct lys_module *module, const char *data, LYS_INFORMAT format, int implement);
+struct lys_submodule *lys_submodule_parse(struct lys_module *module, const char *data, LYS_INFORMAT format,
+                                          struct unres_schema *unres);
 
 /**
  * @brief Create submodule structure by reading data from file descriptor.
@@ -91,10 +92,11 @@
  * @param[in] fd File descriptor of a regular file (e.g. sockets are not supported) containing the submodule
  *            specification in the given \p format.
  * @param[in] format Format of the data to read.
- * @param[in] implement Flag to distinguish implemented and just imported (sub)modules.
+ * @param[in] unres TODO provide description
  * @return Created submodule structure or NULL in case of error.
  */
-struct lys_submodule *lys_submodule_read(struct lys_module *module, int fd, LYS_INFORMAT format, int implement);
+struct lys_submodule *lys_submodule_read(struct lys_module *module, int fd, LYS_INFORMAT format,
+                                         struct unres_schema *unres);
 
 /**
  * @brief Free the submodule structure
@@ -130,10 +132,9 @@
  *
  * @param[in] name Name of the searched grouping.
  * @param[in] start Definition must be valid (visible) for this node.
- * @param[in] in_submodules Whether search the submodules as well or not.
  * @return Matching valid grouping or NULL.
  */
-struct lys_node_grp *lys_find_grouping_up(const char *name, struct lys_node *start, int in_submodules);
+struct lys_node_grp *lys_find_grouping_up(const char *name, struct lys_node *start);
 
 /**
  * @brief Check that the \p node being connected into the \p parent has a unique name (identifier).
@@ -154,15 +155,26 @@
  * @brief Create a copy of the specified schema tree \p node
  *
  * @param[in] module Target module for the duplicated node.
+ * @param[in] parent Schema tree node where the node is being connected, NULL in case of top level \p node.
  * @param[in] node Schema tree node to be duplicated.
  * @param[in] flags Config flag to be inherited in case the origin node does not specify config flag
  * @param[in] nacm NACM flags to be inherited from the parent
- * @param[in] recursive 1 if all children are supposed to be also duplicated.
  * @param[in] unres TODO provide description
  * @return Created copy of the provided schema \p node.
  */
-struct lys_node *lys_node_dup(struct lys_module *module, const struct lys_node *node, uint8_t flags, uint8_t nacm,
-                              int recursive, struct unres_schema *unres);
+struct lys_node *lys_node_dup(struct lys_module *module, struct lys_node *parent, const struct lys_node *node,
+                              uint8_t flags, uint8_t nacm, struct unres_schema *unres);
+
+/**
+ * @brief Return main module of the schema tree node.
+ *
+ * In case of regular YANG module, it returns ::lys_node#module pointer,
+ * but in case of submodule, it returns pointer to the main module.
+ *
+ * @param[in] node Schema tree node to be examined
+ * @return pointer to the main module (schema structure), NULL in case of error.
+ */
+struct lys_module *lys_mainmodule(const struct lys_node *node);
 
 /**
  * @brief Free a schema when condition
@@ -243,9 +255,8 @@
 struct lyd_node *lyd_attr_parent(struct lyd_node *root, struct lyd_attr *attr);
 
 /**
- * @brief Find an import from \p module with matching \p prefix, \p name, or both.
- * \p module itself is also compared. If \p module is a submodule, it's module
- * name is actually the name of the belongs-to module.
+ * @brief Find an import from \p module with matching \p prefix, \p name, or both,
+ * \p module itself is also compared.
  *
  * @param[in] module Module with imports.
  * @param[in] prefix Module prefix to search for.
@@ -253,7 +264,7 @@
  * @param[in] name Module name to search for.
  * @param[in] name_len Module \p name length. If 0, the whole name is used, if not NULL.
  *
- * @return Matching module (or submodule), NULL if not found.
+ * @return Matching module, NULL if not found.
  */
 const struct lys_module *lys_get_import_module(const struct lys_module *module, const char *prefix, int pref_len,
                                                const char *name, int name_len);
diff --git a/src/tree_schema.c b/src/tree_schema.c
index a6a26b4..477505a 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -94,19 +94,13 @@
 lys_get_sibling(const struct lys_node *siblings, const char *mod_name, int mod_name_len, const char *name,
                 int nam_len, LYS_NODE type, const struct lys_node **ret)
 {
-    const struct lys_node *node, *old_siblings = NULL;
-    const struct lys_module *mod;
+    const struct lys_node *node, *parent = NULL;
+    const struct lys_module *mod = NULL;
     const char *node_mod_name;
-    int in_submod;
 
     assert(siblings && mod_name && name);
     assert(!(type & (LYS_USES | LYS_GROUPING)));
 
-    /* find the beginning */
-    while (siblings->prev->next) {
-        siblings = siblings->prev;
-    }
-
     /* fill the lengths in case the caller is so indifferent */
     if (!mod_name_len) {
         mod_name_len = strlen(mod_name);
@@ -115,70 +109,34 @@
         nam_len = strlen(name);
     }
 
-    /* we start with the module itself, submodules come later */
-    in_submod = 0;
-
     /* set mod correctly */
-    if (!siblings->parent) {
-        mod = lys_get_import_module(siblings->module, NULL, 0, mod_name, mod_name_len);
-        if (mod) {
-            old_siblings = siblings;
-            siblings = mod->data;
-        } else if (type & LYS_AUGMENT) {
-            mod = siblings->module;
-        } else {
-            return -1;
-        }
-    } else {
+    parent = lys_parent(siblings);
+    if (!parent) {
         mod = siblings->module;
     }
 
-    while (1) {
-        /* try to find the node */
-        node = NULL;
-        while ((node = lys_getnext(node, siblings->parent, mod, LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
-            if (!type || (node->nodetype & type)) {
-                /* modules need to always be checked, we want to skip augments (no other reason to check them) */
-                if (node->module->type) {
-                    node_mod_name = ((struct lys_submodule *)node->module)->belongsto->name;
-                } else {
-                    node_mod_name = node->module->name;
-                }
-                if ((node_mod_name != mod_name) && (strncmp(node_mod_name, mod_name, mod_name_len) || node_mod_name[mod_name_len])) {
-                    continue;
-                }
+    /* try to find the node */
+    node = NULL;
+    while ((node = lys_getnext(node, parent, mod, LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
+        if (!type || (node->nodetype & type)) {
+            /* modules need to always be checked, we want to skip augments (no other reason to check them) */
+            if (node->module->type) {
+                node_mod_name = ((struct lys_submodule *)node->module)->belongsto->name;
+            } else {
+                node_mod_name = node->module->name;
+            }
+            if (strncmp(node_mod_name, mod_name, mod_name_len) || node_mod_name[mod_name_len]) {
+                continue;
+            }
 
-                /* direct name check */
-                if ((node->name == name) || (!strncmp(node->name, name, nam_len) && !node->name[nam_len])) {
-                    if (ret) {
-                        *ret = node;
-                    }
-                    return EXIT_SUCCESS;
+            /* direct name check */
+            if ((node->name == name) || (!strncmp(node->name, name, nam_len) && !node->name[nam_len])) {
+                if (ret) {
+                    *ret = node;
                 }
+                return EXIT_SUCCESS;
             }
         }
-
-        /* The original siblings may be valid,
-         * it's a special case when we're looking
-         * for a node from an augment.
-         */
-        if ((type & LYS_AUGMENT) && old_siblings) {
-            siblings = old_siblings;
-            old_siblings = NULL;
-            continue;
-        }
-
-        /* we're not top-level, search ended */
-        if (siblings->parent) {
-            break;
-        }
-
-        /* let's try the submodules */
-        if (in_submod == mod->inc_size) {
-            break;
-        }
-        siblings = mod->inc[in_submod].submodule->data;
-        ++in_submod;
     }
 
     return EXIT_FAILURE;
@@ -247,11 +205,18 @@
         }
 
         /* let's try the submodules */
+        while(in_submod != mod->inc_size) {
+            if (!mod->inc[in_submod].submodule) {
+                in_submod++;
+                continue;
+            }
+
+            cur_mod = (struct lys_module *)mod->inc[in_submod].submodule;
+            siblings = cur_mod->data;
+        }
         if (in_submod == mod->inc_size) {
             break;
         }
-        cur_mod = (struct lys_module *)mod->inc[in_submod].submodule;
-        siblings = cur_mod->data;
         ++in_submod;
     }
 
@@ -645,6 +610,7 @@
 lys_node_unlink(struct lys_node *node)
 {
     struct lys_node *parent, *first;
+    struct lys_module *main_module;
 
     if (!node) {
         return;
@@ -652,8 +618,10 @@
 
     /* unlink from data model if necessary */
     if (node->module) {
-        if (node->module->data == node) {
-            node->module->data = node->next;
+        /* get main module with data tree */
+        for (main_module = node->module; main_module->type; main_module = ((struct lys_submodule *)main_module)->belongsto);
+        if (main_module->data == node) {
+            main_module->data = node->next;
         }
     }
 
@@ -705,10 +673,9 @@
 }
 
 struct lys_node_grp *
-lys_find_grouping_up(const char *name, struct lys_node *start, int in_submodules)
+lys_find_grouping_up(const char *name, struct lys_node *start)
 {
     struct lys_node *par_iter, *iter, *stop;
-    int i;
 
     for (par_iter = start; par_iter; par_iter = par_iter->parent) {
         /* top-level augment, look into module (uses augment is handled correctly below) */
@@ -739,20 +706,6 @@
         }
     }
 
-    if (in_submodules) {
-        for (i = 0; i < start->module->inc_size; ++i) {
-            for (iter = start->module->inc[i].submodule->data; iter; iter = iter->next) {
-                if (iter->nodetype != LYS_GROUPING) {
-                    continue;
-                }
-
-                if (!strcmp(name, iter->name)) {
-                    return (struct lys_node_grp *)iter;
-                }
-            }
-        }
-    }
-
     return NULL;
 }
 
@@ -789,12 +742,12 @@
         }
         while (!next) {
             /* go back through parents */
-            if (last->parent == root) {
+            if (lys_parent(last) == root) {
                 /* we are done */
                 return NULL;
             }
-            last = last->parent;
             next = last->next;
+            last = lys_parent(last);
         }
 
         if (next->nodetype == LYS_GROUPING) {
@@ -837,7 +790,7 @@
             start = module->data;
         }
         /* go up */
-        if (lys_find_grouping_up(node->name, start, 0)) {
+        if (lys_find_grouping_up(node->name, start)) {
             LOGVAL(LYE_DUPID, 0, "grouping", node->name);
             return EXIT_FAILURE;
         }
@@ -927,7 +880,13 @@
         break;
     case LYS_CASE:
         /* 6.2.1, rule 8 */
-        LY_TREE_FOR(parent->child, iter) {
+        if (parent) {
+            start = parent->child;
+        } else {
+            start = module->data;
+        }
+
+        LY_TREE_FOR(start, iter) {
             if (!(iter->nodetype & (LYS_ANYXML | LYS_CASE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
                 continue;
             }
@@ -1029,7 +988,7 @@
             return EXIT_FAILURE;
         }
 
-        break;;
+        break;
     }
 
     /* check identifier uniqueness */
@@ -1074,7 +1033,6 @@
 API const struct lys_module *
 lys_parse_data(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
 {
-    struct unres_schema *unres;
     struct lys_module *mod = NULL;
 
     if (!ctx || !data) {
@@ -1082,15 +1040,9 @@
         return NULL;
     }
 
-    unres = calloc(1, sizeof *unres);
-    if (!unres) {
-        LOGMEM;
-        return NULL;
-    }
-
     switch (format) {
     case LYS_IN_YIN:
-        mod = yin_read_module(ctx, data, 1, unres);
+        mod = yin_read_module(ctx, data, 1);
         break;
     case LYS_IN_YANG:
     default:
@@ -1098,35 +1050,25 @@
         break;
     }
 
-    if (mod && unres->count && resolve_unres_schema(mod, unres)) {
-        unres_schema_free(ctx, unres);
-        lys_free(mod, 0);
-        mod = NULL;
-    } else {
-        unres_schema_free(ctx, unres);
-    }
-
     return mod;
 }
 
 struct lys_submodule *
-lys_submodule_parse(struct lys_module *module, const char *data, LYS_INFORMAT format, int implement)
+lys_submodule_parse(struct lys_module *module, const char *data, LYS_INFORMAT format, struct unres_schema *unres)
 {
-    struct unres_schema *unres;
     struct lys_submodule *submod = NULL;
 
     assert(module);
     assert(data);
 
-    unres = calloc(1, sizeof *unres);
-    if (!unres) {
-        LOGMEM;
-        return NULL;
+    /* get the main module */
+    while(module->type) {
+        module = ((struct lys_submodule *)module)->belongsto;
     }
 
     switch (format) {
     case LYS_IN_YIN:
-        submod = yin_read_submodule(module, data, implement, unres);
+        submod = yin_read_submodule(module, data, unres);
         break;
     case LYS_IN_YANG:
     default:
@@ -1134,14 +1076,6 @@
         break;
     }
 
-   if (submod && unres->count && resolve_unres_schema((struct lys_module *)submod, unres)) {
-       unres_schema_free(module->ctx, unres);
-        lys_submodule_free(submod, 0);
-        submod = NULL;
-    } else {
-        unres_schema_free(module->ctx, unres);
-    }
-
     return submod;
 }
 
@@ -1195,7 +1129,7 @@
 }
 
 struct lys_submodule *
-lys_submodule_read(struct lys_module *module, int fd, LYS_INFORMAT format, int implement)
+lys_submodule_read(struct lys_module *module, int fd, LYS_INFORMAT format, struct unres_schema *unres)
 {
     struct lys_submodule *submodule;
     struct stat sb;
@@ -1213,7 +1147,7 @@
         LOGERR(LY_EMEM,"Map file into memory failed (%s()).",__func__);
         return NULL;
     }
-    submodule = lys_submodule_parse(module, addr, format, implement);
+    submodule = lys_submodule_parse(module, addr, format, unres);
     munmap(addr, sb.st_size);
 
     return submodule;
@@ -1275,6 +1209,7 @@
         /* HACK (serious one) for unres */
         /* nothing else we can do but duplicate it immediately */
         new->der = (struct lys_tpdf *)lyxml_dup_elem(mod->ctx, (struct lyxml_elem *)old->der, NULL, 1);
+        new->parent = (struct lys_tpdf *)parent;
         /* all these unres additions can fail even though they did not before */
         if (unres_schema_add_node(mod, unres, new, UNRES_TYPE_DER, parent, 0)) {
             return -1;
@@ -1572,9 +1507,11 @@
 {
     struct lys_node *next, *sub;
 
-    /* children from a resolved uses */
-    LY_TREE_FOR_SAFE(aug.child, next, sub) {
-        lys_node_free(sub);
+    /* children from a resolved augment are freed under the target node */
+    if (!aug.target) {
+        LY_TREE_FOR_SAFE(aug.child, next, sub) {
+            lys_node_free(sub);
+        }
     }
 
     lydict_remove(ctx, aug.target_name);
@@ -2004,10 +1941,9 @@
 const struct lys_module *
 lys_get_import_module(const struct lys_module *module, const char *prefix, int pref_len, const char *name, int name_len)
 {
+    const struct lys_module *main_module;
     int i, match;
-    struct lys_submodule *submodule = (struct lys_submodule *)module;
 
-    assert(prefix || name);
     if (prefix && !pref_len) {
         pref_len = strlen(prefix);
     }
@@ -2015,17 +1951,10 @@
         name_len = strlen(name);
     }
 
-    /* special case, in submodule we pretend the (JSON) module name is the name of the belongs-to module */
-    if (module->type) {
-        if ((!prefix || (!strncmp(submodule->prefix, prefix, pref_len) && !submodule->prefix[pref_len]))
-                && (!name || (!strncmp(submodule->belongsto->name, name, name_len) && !submodule->belongsto->name[name_len]))) {
-            return module;
-        }
-    } else {
-        if ((!prefix || (!strncmp(module->prefix, prefix, pref_len) && !module->prefix[pref_len]))
-                && (!name || (!strncmp(module->name, name, name_len) && !module->name[name_len]))) {
-            return module;
-        }
+    main_module = module->type ? ((struct lys_submodule *)module)->belongsto : module;
+    if ((!prefix || (!strncmp(main_module->prefix, prefix, pref_len) && !main_module->prefix[pref_len])) && (!name
+                    || (!strncmp(main_module->name, name, name_len) && !main_module->name[name_len]))) {
+        return main_module;
     }
 
     for (i = 0; i < module->imp_size; ++i) {
@@ -2047,6 +1976,7 @@
 module_free_common(struct lys_module *module, int free_int_mods)
 {
     struct ly_ctx *ctx;
+    struct lys_node *next, *iter;
     unsigned int i;
     int j, l;
 
@@ -2055,6 +1985,11 @@
 
     /* as first step, free the imported modules */
     for (i = 0; i < module->imp_size; i++) {
+        /* skip external modules from submodules' import */
+        if (module->imp[i].external) {
+            continue;
+        }
+
         /* do not free internal modules */
         if (!free_int_mods) {
             for (j = 0; j < int_mods.count; ++j) {
@@ -2083,8 +2018,12 @@
     }
     free(module->imp);
 
-    while (module->data) {
-        lys_node_free(module->data);
+    /* submodules don't have data tree, the data nodes
+     * are placed in the main module altogether */
+    if (!module->type) {
+        LY_TREE_FOR_SAFE(module->data, next, iter) {
+            lys_node_free(iter);
+        }
     }
 
     lydict_remove(ctx, module->dsc);
@@ -2114,7 +2053,11 @@
 
     /* include */
     for (i = 0; i < module->inc_size; i++) {
-        lys_submodule_free(module->inc[i].submodule, free_int_mods);
+        /* complete submodule free is done only from main module since
+         * submodules propagate their includes to the main module */
+        if (!module->type) {
+            lys_submodule_free(module->inc[i].submodule, free_int_mods);
+        }
     }
     free(module->inc);
 
@@ -2146,10 +2089,6 @@
         return;
     }
 
-    submodule->inc_size = 0;
-    free(submodule->inc);
-    submodule->inc = NULL;
-
     /* common part with struct ly_module */
     module_free_common((struct lys_module *)submodule, free_int_mods);
 
@@ -2159,11 +2098,12 @@
 }
 
 struct lys_node *
-lys_node_dup(struct lys_module *module, const struct lys_node *node, uint8_t flags, uint8_t nacm, int recursive,
-             struct unres_schema *unres)
+lys_node_dup(struct lys_module *module, struct lys_node *parent, const struct lys_node *node, uint8_t flags,
+             uint8_t nacm, struct unres_schema *unres)
 {
-    struct lys_node *retval = NULL, *aux, *child;
+    struct lys_node *retval = NULL, *child;
     struct ly_ctx *ctx = module->ctx;
+    const char *modname;
     int i, j, rc;
 
     struct lys_node_container *cont = NULL;
@@ -2298,11 +2238,15 @@
         }
     }
 
-    if (recursive) {
-        /* go recursively */
+    /* connect it to the parent */
+    if (lys_node_addchild(parent, retval->module, retval)) {
+        goto error;
+    }
+
+    /* go recursively */
+    if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
         LY_TREE_FOR(node->child, child) {
-            aux = lys_node_dup(module, child, retval->flags, retval->nacm, 1, unres);
-            if (!aux || lys_node_addchild(retval, NULL, aux)) {
+            if (!lys_node_dup(module, retval, child, retval->flags, retval->nacm, unres)) {
                 goto error;
             }
         }
@@ -2331,7 +2275,8 @@
         }
 
         if (choice_orig->dflt) {
-            rc = lys_get_sibling(choice->child, choice->module->name, 0, choice_orig->dflt->name, 0, LYS_ANYXML
+            modname = list->module->type ? ((struct lys_submodule *)list->module)->belongsto->name : list->module->name;
+            rc = lys_get_sibling(choice->child, modname, 0, choice_orig->dflt->name, 0, LYS_ANYXML
                                          | LYS_CASE | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST
                                          | LYS_LIST, (const struct lys_node **)&choice->dflt);
             if (rc) {
@@ -2407,8 +2352,9 @@
 
             /* we managed to resolve it before, resolve it again manually */
             if (list_orig->keys[0]) {
+                modname = list->module->type ? ((struct lys_submodule *)list->module)->belongsto->name : list->module->name;
                 for (i = 0; i < list->keys_size; ++i) {
-                    rc = lys_get_sibling(list->child, list->module->name, 0, list_orig->keys[i]->name, 0, LYS_LEAF,
+                    rc = lys_get_sibling(list->child, modname, 0, list_orig->keys[i]->name, 0, LYS_LEAF,
                                          (const struct lys_node **)&list->keys[i]);
                     if (rc) {
                         if (rc == EXIT_FAILURE) {
@@ -2663,8 +2609,6 @@
         }
     }
 
-    /* TODO submodules of submodules ... */
-
     /* feature definition not found */
     return -1;
 }
@@ -2727,14 +2671,18 @@
         }
     }
 
-    /* TODO submodules of submodules ... */
-
     /* terminating NULL byte */
     result[count] = NULL;
 
     return result;
 }
 
+struct lys_module *
+lys_mainmodule(const struct lys_node *node)
+{
+    return node->module->type ? ((struct lys_submodule *)node->module)->belongsto : node->module;
+}
+
 API struct lys_node *
 lys_parent(const struct lys_node *node)
 {
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 8e3c77e..8938909 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -239,14 +239,14 @@
     const char *ref;                 /**< cross-reference for the module */
     const char *org;                 /**< party/company responsible for the module */
     const char *contact;             /**< contact information for the module */
+    const char *uri;                 /**< source of this module in URI format (can be NULL) */
+    uint8_t type:1;                  /**< 0 - structure type used to distinguish structure from ::lys_submodule */
     uint8_t version:5;               /**< yang-version:
                                           - 0 = not specified, YANG 1.0 as default,
                                           - 1 = YANG 1.0,
                                           - 2 = YANG 1.1 not yet supported */
-    uint8_t type:1;                  /**< 0 - structure type used to distinguish structure from ::lys_submodule */
     uint8_t deviated:1;              /**< deviated flag (true/false) if the module is deviated by some other module */
     uint8_t implemented:1;           /**< flag if the module is implemented, not just imported */
-    const char *uri;                 /**< source of this module in URI format (can be NULL) */
 
     /* array sizes */
     uint8_t rev_size;                /**< number of elements in #rev array */
@@ -268,9 +268,8 @@
     struct lys_node_augment *augment;/**< array of augments */
     struct lys_deviation *deviation; /**< array of specified deviations */
 
-    struct lys_node *data;           /**< first data statement, includes also RPCs and Notifications */
-
     /* specific module's items in comparison to submodules */
+    struct lys_node *data;           /**< first data statement, includes also RPCs and Notifications */
     const char *ns;                  /**< namespace of the module (mandatory) */
 };
 
@@ -278,9 +277,8 @@
  * @brief Submodule schema node structure that can be included into a YANG module.
  *
  * Compatible with ::lys_module structure with exception of the last, #belongsto member, which is replaced by
- * ::lys_module#ns member. Sometimes, ::lys_submodule can be provided casted to ::lys_module. Such a thing can
- * be determined via the #type member value.
- *
+ * ::lys_module#data and ::lys_module#ns members. Sometimes, ::lys_submodule can be provided casted to ::lys_module.
+ * Such a thing can be determined via the #type member value.
  *
  */
 struct lys_submodule {
@@ -291,14 +289,9 @@
     const char *ref;                 /**< cross-reference for the submodule */
     const char *org;                 /**< party responsible for the submodule */
     const char *contact;             /**< contact information for the submodule */
-    uint8_t version:5;               /**< yang-version:
-                                          - 0 = not specified, YANG 1.0 as default,
-                                          - 1 = YANG 1.0,
-                                          - 2 = YANG 1.1 not yet supported */
-    uint8_t type:1;                  /**< 1 - structure type used to distinguish structure from ::lys_module */
-    uint8_t deviated:1;              /**< deviated flag (true/false) if the module is deviated by some other module */
-    uint8_t implemented:1;           /**< flag if the module is implemented, not just imported */
     const char *uri;                 /**< origin URI of the submodule */
+    uint8_t type:1;                  /**< 1 - structure type used to distinguish structure from ::lys_module */
+    uint8_t padding:7;                /**< not used, kept for compatibility with ::lys_module */
 
     /* array sizes */
     uint8_t rev_size;                /**< number of elements in #rev array */
@@ -320,8 +313,6 @@
     struct lys_node_augment *augment;/**< array of augments */
     struct lys_deviation *deviation; /**< array of specified deviations */
 
-    struct lys_node *data;           /**< first data statement, includes also RPCs and Notifications */
-
     /* specific submodule's items in comparison to modules */
     struct lys_module *belongsto;    /**< belongs-to (parent module) */
 };
@@ -1130,6 +1121,7 @@
     struct lys_module *module;       /**< link to the imported module (mandatory) */
     const char *prefix;              /**< prefix for the data from the imported schema (mandatory) */
     char rev[LY_REV_SIZE];           /**< revision-date of the imported module (optional) */
+    uint8_t external;                /**< flag for import records from submodules */
 };
 
 /**
@@ -1138,6 +1130,7 @@
 struct lys_include {
     struct lys_submodule *submodule; /**< link to the included submodule (mandatory) */
     char rev[LY_REV_SIZE];           /**< revision-date of the included submodule (optional) */
+    uint8_t external;                /**< flag for include records from submodules */
 };
 
 /**
diff --git a/src/xml.c b/src/xml.c
index 2843ad9..6f0c222 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -185,7 +185,7 @@
     LY_TREE_DFS_BEGIN(elem, tmp, iter) {
         if (iter->ns) {
             /* find the root of elem NS */
-            for (ns_root = iter->ns->parent; ns_root->parent; ns_root = ns_root->parent);
+            for (ns_root = iter->ns->parent; ns_root; ns_root = ns_root->parent);
 
             /* elem NS is defined outside elem subtree */
             if (ns_root != elem_root) {