3232#include "set.h"
3333#include "tree.h"
3434#include "tree_data.h"
35+ #include "tree_data_internal.h"
3536#include "tree_schema.h"
3637
3738/**
3839 * @brief JSON printer context.
3940 */
4041struct jsonpr_ctx {
41- struct ly_out * out ; /**< output specification */
42+ struct ly_out * out ; /**< output specification */
4243 const struct lyd_node * root ; /**< root node of the subtree being printed */
4344 const struct lyd_node * parent ; /**< parent of the node being printed */
44- uint16_t level ; /**< current indentation level: 0 - no formatting, >= 1 indentation levels */
45- uint32_t options ; /**< [Data printer flags](@ref dataprinterflags) */
46- const struct ly_ctx * ctx ; /**< libyang context */
45+ uint16_t level ; /**< current indentation level: 0 - no formatting, >= 1 indentation levels */
46+ uint32_t options ; /**< [Data printer flags](@ref dataprinterflags) */
47+ const struct ly_ctx * ctx ; /**< libyang context */
4748
48- uint16_t level_printed ; /* level where some data were already printed */
49- struct ly_set open ; /* currently open array(s) */
49+ uint16_t level_printed ; /**< level where some data were already printed */
50+ struct ly_set open ; /**< currently open array(s) */
5051 const struct lyd_node * first_leaflist ; /**< first printed leaf-list instance, used when printing its metadata/attributes */
5152};
5253
@@ -61,6 +62,10 @@ struct jsonpr_ctx {
6162 ly_print_(pctx->out, ",%s", (DO_FORMAT ? "\n" : "")); \
6263 }
6364
65+ static LY_ERR json_print_leaf_list_empty (struct jsonpr_ctx * pctx , const struct lysc_node * snode );
66+ static const struct lysc_node * json_print_next_empty_leaf_list (struct jsonpr_ctx * pctx , const struct lysc_node * snode ,
67+ const struct lyd_node * siblings );
68+
6469static LY_ERR json_print_node (struct jsonpr_ctx * pctx , const struct lyd_node * node );
6570
6671/**
@@ -144,27 +149,28 @@ json_print_array_close(struct jsonpr_ctx *pctx)
144149 * @brief Get the node's module name to use as the @p node prefix in JSON.
145150 *
146151 * @param[in] node Node to process.
152+ * @param[in] snode Schema node to process.
147153 * @param[out] mod_name Module name of @p node, can be NULL (format is XML and the module with NS is not in the context).
148154 * @param[out] data_dict Whether @p mod_name is from the schema or data dictionary.
149155 */
150156static void
151- node_prefix (const struct lyd_node * node , const char * * mod_name , ly_bool * data_dict )
157+ node_prefix (const struct lyd_node * node , const struct lysc_node * snode , const char * * mod_name , ly_bool * data_dict )
152158{
153159 struct lyd_node_opaq * onode ;
154160 const struct lys_module * mod ;
155161
156162 * mod_name = NULL ;
157163
158- if (!node ) {
164+ if (!node && ! snode ) {
159165 return ;
160166 }
161167
162- if (node -> schema ) {
163- * mod_name = node -> schema -> module -> name ;
168+ if (snode ) {
169+ * mod_name = snode -> module -> name ;
164170 if (data_dict ) {
165171 * data_dict = 0 ;
166172 }
167- } else {
173+ } else if ( node ) {
168174 onode = (struct lyd_node_opaq * )node ;
169175
170176 switch (onode -> format ) {
@@ -201,27 +207,27 @@ node_prefix(const struct lyd_node *node, const char **mod_name, ly_bool *data_di
201207 * @return 0 in case the nodes' modules are the same
202208 * @return 1 in case the nodes belongs to different modules
203209 */
204- int
205- json_nscmp (const struct lyd_node * node1 , const struct lyd_node * node2 )
210+ static int
211+ json_nscmp (const struct lyd_node * node1 , const struct lysc_node * snode1 , const struct lyd_node * node2 )
206212{
207213 const char * pref1 , * pref2 ;
208214 ly_bool dd1 , dd2 ;
209215
210- assert (node1 || node2 );
216+ assert (snode1 || node2 );
211217
212- if (!node1 || !node2 ) {
218+ if (!snode1 || !node2 ) {
213219 return 1 ;
214- } else if (node1 -> schema && node2 -> schema ) {
215- if (node1 -> schema -> module == node2 -> schema -> module ) {
220+ } else if (snode1 && node2 -> schema ) {
221+ if (snode1 -> module == node2 -> schema -> module ) {
216222 /* belongs to the same module */
217223 return 0 ;
218224 } else {
219225 /* different modules */
220226 return 1 ;
221227 }
222228 } else {
223- node_prefix (node1 , & pref1 , & dd1 );
224- node_prefix (node2 , & pref2 , & dd2 );
229+ node_prefix (node1 , snode1 , & pref1 , & dd1 );
230+ node_prefix (node2 , node2 -> schema , & pref2 , & dd2 );
225231
226232 if (pref1 && pref2 && (((dd1 == dd2 ) && (pref1 == pref2 )) || ((dd1 != dd2 ) && !strcmp (pref1 , pref2 )))) {
227233 return 0 ;
@@ -284,23 +290,32 @@ json_print_string(struct ly_out *out, const char *text)
284290 * @brief Print JSON object's member name, ending by ':'. It resolves if the prefix is supposed to be printed.
285291 *
286292 * @param[in] ctx JSON printer context.
287- * @param[in] node The data node being printed.
293+ * @param[in] node Data node being printed.
294+ * @param[in] snode Optional schema node if there is no @p node.
288295 * @param[in] is_attr Flag if the metadata sign (@) is supposed to be added before the identifier.
289296 * @return LY_ERR value.
290297 */
291298static LY_ERR
292- json_print_member (struct jsonpr_ctx * pctx , const struct lyd_node * node , ly_bool is_attr )
299+ json_print_member (struct jsonpr_ctx * pctx , const struct lyd_node * node , const struct lysc_node * snode , ly_bool is_attr )
293300{
294- const char * pref ;
301+ const char * pref , * name ;
302+
303+ assert (node || snode );
304+
305+ if (node ) {
306+ snode = node -> schema ;
307+ name = LYD_NAME (node );
308+ } else {
309+ name = snode -> name ;
310+ }
295311
296312 PRINT_COMMA ;
297- if ((LEVEL == 1 ) || json_nscmp (node , pctx -> parent )) {
313+ if ((LEVEL == 1 ) || json_nscmp (node , snode , pctx -> parent )) {
298314 /* print "namespace" */
299- node_prefix (node , & pref , NULL );
300- ly_print_ (pctx -> out , "%*s\"%s%s:%s\":%s" , INDENT , is_attr ? "@" : "" ,
301- pref , node -> schema -> name , DO_FORMAT ? " " : "" );
315+ node_prefix (node , snode , & pref , NULL );
316+ ly_print_ (pctx -> out , "%*s\"%s%s:%s\":%s" , INDENT , is_attr ? "@" : "" , pref , name , DO_FORMAT ? " " : "" );
302317 } else {
303- ly_print_ (pctx -> out , "%*s\"%s%s\":%s" , INDENT , is_attr ? "@" : "" , node -> schema -> name , DO_FORMAT ? " " : "" );
318+ ly_print_ (pctx -> out , "%*s\"%s%s\":%s" , INDENT , is_attr ? "@" : "" , name , DO_FORMAT ? " " : "" );
304319 }
305320
306321 return LY_SUCCESS ;
@@ -351,7 +366,7 @@ json_print_member2(struct jsonpr_ctx *pctx, const struct lyd_node *parent, LY_VA
351366 }
352367
353368 /* print the member, strcmp because node prefix is in the schema dict, module_name in data dict */
354- node_prefix (parent , & pmod_name , NULL );
369+ node_prefix (parent , parent ? parent -> schema : NULL , & pmod_name , NULL );
355370 if (module_name && (!parent || strcmp (pmod_name , module_name ))) {
356371 ly_print_ (pctx -> out , "%*s\"%s%s:%s\":%s" , INDENT , is_attr ? "@" : "" , module_name , name_str , DO_FORMAT ? " " : "" );
357372 } else {
@@ -541,7 +556,7 @@ json_print_attributes(struct jsonpr_ctx *pctx, const struct lyd_node *node, ly_b
541556 if (inner ) {
542557 LY_CHECK_RET (json_print_member2 (pctx , lyd_parent (node ), LY_VALUE_JSON , NULL , 1 ));
543558 } else {
544- LY_CHECK_RET (json_print_member (pctx , node , 1 ));
559+ LY_CHECK_RET (json_print_member (pctx , node , NULL , 1 ));
545560 }
546561 ly_print_ (pctx -> out , "{%s" , (DO_FORMAT ? "\n" : "" ));
547562 LEVEL_INC ;
@@ -577,7 +592,7 @@ json_print_attributes(struct jsonpr_ctx *pctx, const struct lyd_node *node, ly_b
577592static LY_ERR
578593json_print_leaf (struct jsonpr_ctx * pctx , const struct lyd_node * node )
579594{
580- LY_CHECK_RET (json_print_member (pctx , node , 0 ));
595+ LY_CHECK_RET (json_print_member (pctx , node , NULL , 0 ));
581596 LY_CHECK_RET (json_print_value (pctx , LYD_CTX (node ), & ((const struct lyd_node_term * )node )-> value , node -> schema -> module ));
582597 LEVEL_PRINTED ;
583598
@@ -680,14 +695,17 @@ json_print_inner(struct jsonpr_ctx *pctx, const struct lyd_node *node)
680695 struct lyd_node * child ;
681696 const struct lyd_node * prev_parent ;
682697 struct lyd_node_opaq * opaq = NULL ;
683- ly_bool has_content = 0 ;
698+ const struct lysc_node * snode ;
699+ ly_bool has_content = 0 , no_child_print = 1 ;
684700
685701 LY_LIST_FOR (lyd_child (node ), child ) {
686702 if (lyd_node_should_print (child , pctx -> options )) {
703+ no_child_print = 0 ;
687704 break ;
688705 }
689706 }
690- if (node -> meta || child ) {
707+ if (node -> meta || child || ((pctx -> options & LYD_PRINT_EMPTY_LEAF_LIST ) &&
708+ json_print_next_empty_leaf_list (pctx , lysc_node_child (node -> schema ), lyd_child (node )))) {
691709 has_content = 1 ;
692710 }
693711 if (!node -> schema ) {
@@ -714,6 +732,16 @@ json_print_inner(struct jsonpr_ctx *pctx, const struct lyd_node *node)
714732 }
715733 pctx -> parent = prev_parent ;
716734
735+ if (no_child_print && (pctx -> options & LYD_PRINT_EMPTY_LEAF_LIST )) {
736+ snode = json_print_next_empty_leaf_list (pctx , lysc_node_child (node -> schema ), NULL );
737+ while (snode ) {
738+ /* print an empty (leaf-)list */
739+ LY_CHECK_RET (json_print_leaf_list_empty (pctx , snode ));
740+
741+ snode = json_print_next_empty_leaf_list (pctx , snode -> next , NULL );
742+ }
743+ }
744+
717745 LEVEL_DEC ;
718746 if (DO_FORMAT && has_content ) {
719747 ly_print_ (pctx -> out , "\n%*s}" , INDENT );
@@ -735,7 +763,7 @@ json_print_inner(struct jsonpr_ctx *pctx, const struct lyd_node *node)
735763static int
736764json_print_container (struct jsonpr_ctx * pctx , const struct lyd_node * node )
737765{
738- LY_CHECK_RET (json_print_member (pctx , node , 0 ));
766+ LY_CHECK_RET (json_print_member (pctx , node , NULL , 0 ));
739767 LY_CHECK_RET (json_print_inner (pctx , node ));
740768
741769 return LY_SUCCESS ;
@@ -751,7 +779,7 @@ json_print_container(struct jsonpr_ctx *pctx, const struct lyd_node *node)
751779static int
752780json_print_any (struct jsonpr_ctx * pctx , const struct lyd_node * node )
753781{
754- LY_CHECK_RET (json_print_member (pctx , node , 0 ));
782+ LY_CHECK_RET (json_print_member (pctx , node , NULL , 0 ));
755783 LY_CHECK_RET (json_print_any_content (pctx , (struct lyd_node_any * )node ));
756784 LEVEL_PRINTED ;
757785
@@ -806,7 +834,7 @@ json_print_leaf_list(struct jsonpr_ctx *pctx, const struct lyd_node *node)
806834 const struct lys_module * df_mod = NULL ;
807835
808836 if (!is_open_array (pctx , node )) {
809- LY_CHECK_RET (json_print_member (pctx , node , 0 ));
837+ LY_CHECK_RET (json_print_member (pctx , node , NULL , 0 ));
810838 LY_CHECK_RET (json_print_array_open (pctx , node ));
811839 if (node -> schema -> nodetype == LYS_LEAFLIST ) {
812840 ly_print_ (pctx -> out , "%*s" , INDENT );
@@ -845,6 +873,34 @@ json_print_leaf_list(struct jsonpr_ctx *pctx, const struct lyd_node *node)
845873 return LY_SUCCESS ;
846874}
847875
876+ /**
877+ * @brief Print empty leaf-list or list instance.
878+ *
879+ * @param[in] ctx JSON printer context.
880+ * @param[in] snode Schema node to print.
881+ * @return LY_ERR value.
882+ */
883+ static LY_ERR
884+ json_print_leaf_list_empty (struct jsonpr_ctx * pctx , const struct lysc_node * snode )
885+ {
886+ assert (snode -> nodetype & (LYS_LEAFLIST | LYS_LIST ));
887+
888+ LY_CHECK_RET (json_print_member (pctx , NULL , snode , 0 ));
889+
890+ /* avoid an empty line */
891+ if (!(pctx -> options & LY_PRINT_SHRINK )) {
892+ pctx -> options |= LY_PRINT_SHRINK ;
893+ LY_CHECK_RET (json_print_array_open (pctx , (void * )snode ));
894+ pctx -> options &= ~LY_PRINT_SHRINK ;
895+ } else {
896+ LY_CHECK_RET (json_print_array_open (pctx , (void * )snode ));
897+ }
898+
899+ json_print_array_close (pctx );
900+
901+ return LY_SUCCESS ;
902+ }
903+
848904/**
849905 * @brief Print leaf-list's metadata or opaque nodes attributes.
850906 * This function is supposed to be called when the leaf-list array is closed.
@@ -874,7 +930,7 @@ json_print_meta_attr_leaflist(struct jsonpr_ctx *pctx)
874930 node = prev , prev = node -> prev ) {}
875931
876932 if (node -> schema ) {
877- LY_CHECK_RET (json_print_member (pctx , node , 1 ));
933+ LY_CHECK_RET (json_print_member (pctx , node , NULL , 1 ));
878934 } else {
879935 opaq = (struct lyd_node_opaq * )node ;
880936 LY_CHECK_RET (json_print_member2 (pctx , lyd_parent (node ), opaq -> format , & opaq -> name , 1 ));
@@ -988,16 +1044,49 @@ json_print_opaq(struct jsonpr_ctx *pctx, const struct lyd_node_opaq *node)
9881044 return LY_SUCCESS ;
9891045}
9901046
1047+ /**
1048+ * @brief Return the following empty (leaf-)lists if no predecessor is printed.
1049+ *
1050+ * @param[in] pctx JSON printer context.
1051+ * @param[in] snode First schema node to consider.
1052+ * @param[in] siblings Siblings to check for (leaf-)list existence.
1053+ * @return Next (leaf-)list without instances.
1054+ * @return NULL if no (leaf-)list without instances matches snode or following nodes until a node is printed.
1055+ */
1056+ static const struct lysc_node *
1057+ json_print_next_empty_leaf_list (struct jsonpr_ctx * pctx , const struct lysc_node * snode , const struct lyd_node * siblings )
1058+ {
1059+ struct lyd_node * match ;
1060+
1061+ /* look for following empty (leaf-)lists */
1062+ LY_LIST_FOR (snode , snode ) {
1063+ if (!lyd_find_sibling_schema (siblings , snode , & match ) && lyd_node_should_print (match , pctx -> options )) {
1064+ /* instance exists and will be printed */
1065+ break ;
1066+ }
1067+
1068+ if (snode -> nodetype & (LYS_LEAFLIST | LYS_LIST )) {
1069+ assert (!match );
1070+ return snode ;
1071+ }
1072+ }
1073+
1074+ /* no empty (leaf-)list to print */
1075+ return NULL ;
1076+ }
1077+
9911078/**
9921079 * @brief Print all the types of data node including its metadata.
9931080 *
994- * @param[in] ctx JSON printer context.
1081+ * @param[in] pctx JSON printer context.
9951082 * @param[in] node Data node to print.
9961083 * @return LY_ERR value.
9971084 */
9981085static LY_ERR
9991086json_print_node (struct jsonpr_ctx * pctx , const struct lyd_node * node )
10001087{
1088+ const struct lysc_node * snode ;
1089+
10011090 if (!lyd_node_should_print (node , pctx -> options )) {
10021091 if (json_print_array_is_last_inst (pctx , node )) {
10031092 json_print_array_close (pctx );
@@ -1030,6 +1119,16 @@ json_print_node(struct jsonpr_ctx *pctx, const struct lyd_node *node)
10301119 LOGINT (pctx -> ctx );
10311120 return EXIT_FAILURE ;
10321121 }
1122+
1123+ if (pctx -> options & LYD_PRINT_EMPTY_LEAF_LIST ) {
1124+ snode = json_print_next_empty_leaf_list (pctx , node -> schema -> next , node );
1125+ while (snode ) {
1126+ /* print an empty (leaf-)list */
1127+ LY_CHECK_RET (json_print_leaf_list_empty (pctx , snode ));
1128+
1129+ snode = json_print_next_empty_leaf_list (pctx , snode -> next , node );
1130+ }
1131+ }
10331132 }
10341133
10351134 pctx -> level_printed = pctx -> level ;
0 commit comments