@@ -935,7 +935,7 @@ lydjson_meta_attr(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, st
935935 */
936936static void
937937lydjson_maintain_children (struct lyd_node * parent , struct lyd_node * * first_p , struct lyd_node * * node_p , ly_bool last ,
938- struct lysc_ext_instance * ext )
938+ const struct lysc_ext_instance * ext )
939939{
940940 if (!* node_p ) {
941941 return ;
@@ -1822,15 +1822,17 @@ lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node *parent, struct l
18221822 * @brief Common start of JSON parser processing different types of the input data.
18231823 *
18241824 * @param[in] ctx libyang context
1825+ * @param[in] schema Schema node of the potential bare value to check.
18251826 * @param[in] in Input structure.
18261827 * @param[in] parse_opts Options for parser, see @ref dataparseroptions.
18271828 * @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
1829+ * @param[out] status_p Initial status of the input structure.
18281830 * @param[out] lydctx_p Data parser context to finish validation.
18291831 * @return LY_ERR value.
18301832 */
18311833static LY_ERR
1832- lyd_parse_json_init (const struct ly_ctx * ctx , struct ly_in * in , uint32_t parse_opts , uint32_t val_opts ,
1833- struct lyd_json_ctx * * lydctx_p )
1834+ lyd_parse_json_init (const struct ly_ctx * ctx , const struct lysc_node * schema , struct ly_in * in , uint32_t parse_opts ,
1835+ uint32_t val_opts , enum LYJSON_PARSER_STATUS * status_p , struct lyd_json_ctx * * lydctx_p )
18341836{
18351837 LY_ERR ret = LY_SUCCESS ;
18361838 struct lyd_json_ctx * lydctx ;
@@ -1849,28 +1851,44 @@ lyd_parse_json_init(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_o
18491851 status = lyjson_ctx_status (lydctx -> jsonctx );
18501852
18511853 /* parse_opts & LYD_PARSE_SUBTREE not implemented */
1852- if (status != LYJSON_OBJECT ) {
1853- /* expecting top-level object */
1854- LOGVAL (ctx , LYVE_SYNTAX_JSON , "Expected top-level JSON object, but %s found." , lyjson_token2str (status ));
1854+ /* there are two options: either we want to parse a bare JSON value or a JSON object
1855+ * node of the bare JSON value has to have a schema, otherwise we do not know where to put the value
1856+ * the only types of nodes that can take on a value are a leaf (number, string or bool) and a leaf-list (array) */
1857+ if (schema &&
1858+ (((status == LYJSON_ARRAY ) && (schema -> nodetype & LYS_LEAFLIST )) ||
1859+ (((status == LYJSON_NUMBER ) || (status == LYJSON_STRING ) || (status == LYJSON_FALSE ) ||
1860+ (status == LYJSON_TRUE ) || (status == LYJSON_NULL ) || (status == LYJSON_ARRAY )) && (schema -> nodetype & LYS_LEAF )))) {
1861+ /* bare value (bare anydata 'value = object' is not supported) */
1862+ } else if (status == LYJSON_OBJECT ) {
1863+ /* JSON object */
1864+ } else {
1865+ /* expecting top-level object or bare value */
1866+ LOGVAL (ctx , LYVE_SYNTAX_JSON , "Expected top-level JSON object or correct bare value, but %s found." , lyjson_token2str (status ));
18551867 * lydctx_p = NULL ;
18561868 lyd_json_ctx_free ((struct lyd_ctx * )lydctx );
18571869 return LY_EVALID ;
18581870 }
18591871
18601872 * lydctx_p = lydctx ;
1873+ if (status_p ) {
1874+ * status_p = status ;
1875+ }
18611876 return LY_SUCCESS ;
18621877}
18631878
18641879LY_ERR
18651880lyd_parse_json (const struct ly_ctx * ctx , const struct lysc_ext_instance * ext , struct lyd_node * parent ,
1866- struct lyd_node * * first_p , struct ly_in * in , uint32_t parse_opts , uint32_t val_opts , uint32_t int_opts ,
1867- struct ly_set * parsed , ly_bool * subtree_sibling , struct lyd_ctx * * lydctx_p )
1881+ const struct lysc_node * schema , struct lyd_node * * first_p , struct ly_in * in , uint32_t parse_opts ,
1882+ uint32_t val_opts , uint32_t int_opts , struct ly_set * parsed , ly_bool * subtree_sibling ,
1883+ struct lyd_ctx * * lydctx_p )
18681884{
18691885 LY_ERR r , rc = LY_SUCCESS ;
18701886 struct lyd_json_ctx * lydctx = NULL ;
1871- enum LYJSON_PARSER_STATUS status ;
1887+ enum LYJSON_PARSER_STATUS status = LYJSON_ERROR ;
1888+ struct lyd_node * node = NULL ;
1889+ const char * expected = NULL ;
18721890
1873- rc = lyd_parse_json_init (ctx , in , parse_opts , val_opts , & lydctx );
1891+ rc = lyd_parse_json_init (ctx , schema , in , parse_opts , val_opts , & status , & lydctx );
18741892 LY_CHECK_GOTO (rc , cleanup );
18751893
18761894 lydctx -> int_opts = int_opts ;
@@ -1879,17 +1897,88 @@ lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, st
18791897 /* find the operation node if it exists already */
18801898 LY_CHECK_GOTO (rc = lyd_parser_find_operation (parent , int_opts , & lydctx -> op_node ), cleanup );
18811899
1882- /* read subtree(s) */
1883- do {
1884- r = lydjson_subtree_r (lydctx , parent , first_p , parsed );
1885- LY_DPARSER_ERR_GOTO (r , rc = r , lydctx , cleanup );
1900+ if (status != LYJSON_OBJECT ) {
1901+ /* parse bare JSON value */
1902+ assert (schema );
18861903
1887- status = lyjson_ctx_status ( lydctx -> jsonctx );
1904+ /* this branch partly copies the behavior of lydjson_subtree_r() */
18881905
1889- if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS )) {
1906+ /* set expected representation */
1907+ switch (schema -> nodetype ) {
1908+ case LYS_LEAFLIST :
1909+ expected = "array of values" ;
1910+ break ;
1911+ case LYS_LEAF :
1912+ if (status == LYJSON_ARRAY ) {
1913+ expected = "[null]" ;
1914+ } else {
1915+ expected = "value" ;
1916+ }
18901917 break ;
18911918 }
1892- } while (status == LYJSON_OBJECT_NEXT );
1919+
1920+ /* check the representation according to the nodetype and then continue with the content */
1921+ /* for now object values are not supported (anydata) */
1922+ /* for now extensions not supported */
1923+ switch (schema -> nodetype ) {
1924+ case LYS_LEAFLIST :
1925+ LY_CHECK_GOTO (status != LYJSON_ARRAY , representation_error );
1926+
1927+ /* process all the values/objects */
1928+ do {
1929+ /* move into array/next value */
1930+ r = lyjson_ctx_next (lydctx -> jsonctx , & status );
1931+ LY_CHECK_ERR_GOTO (r , rc = r , cleanup );
1932+ if (status == LYJSON_ARRAY_CLOSED ) {
1933+ /* empty array, fine... */
1934+ break ;
1935+ }
1936+
1937+ r = lydjson_parse_instance (lydctx , parent , first_p , schema , NULL , schema -> name , strlen (schema -> name ),
1938+ NULL , 0 , & status , & node );
1939+ if (r == LY_ENOT ) {
1940+ goto representation_error ;
1941+ }
1942+ LY_DPARSER_ERR_GOTO (r , rc = r , lydctx , cleanup );
1943+
1944+ lydjson_maintain_children (parent , first_p , & node ,
1945+ lydctx -> parse_opts & LYD_PARSE_ORDERED ? LYD_INSERT_NODE_LAST : LYD_INSERT_NODE_DEFAULT , NULL );
1946+
1947+ /* move after the item(s) */
1948+ r = lyjson_ctx_next (lydctx -> jsonctx , & status );
1949+ LY_CHECK_ERR_GOTO (r , rc = r , cleanup );
1950+ } while (status == LYJSON_ARRAY_NEXT );
1951+
1952+ break ;
1953+ case LYS_LEAF :
1954+ /* process the value/object */
1955+ r = lydjson_parse_instance (lydctx , parent , first_p , schema , NULL , schema -> name , strlen (schema -> name ),
1956+ NULL , 0 , & status , & node );
1957+ if (r == LY_ENOT ) {
1958+ goto representation_error ;
1959+ }
1960+ LY_DPARSER_ERR_GOTO (r , rc = r , lydctx , cleanup );
1961+
1962+ /* finally connect the parsed node, is zeroed */
1963+ lydjson_maintain_children (parent , first_p , & node ,
1964+ lydctx -> parse_opts & LYD_PARSE_ORDERED ? LYD_INSERT_NODE_LAST : LYD_INSERT_NODE_DEFAULT , NULL );
1965+ break ;
1966+ }
1967+ } else {
1968+ /* parse JSON object */
1969+
1970+ /* read subtree(s) */
1971+ do {
1972+ r = lydjson_subtree_r (lydctx , parent , first_p , parsed );
1973+ LY_DPARSER_ERR_GOTO (r , rc = r , lydctx , cleanup );
1974+
1975+ status = lyjson_ctx_status (lydctx -> jsonctx );
1976+
1977+ if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS )) {
1978+ break ;
1979+ }
1980+ } while (status == LYJSON_OBJECT_NEXT );
1981+ }
18931982
18941983 if ((int_opts & LYD_INTOPT_NO_SIBLINGS ) && lydctx -> jsonctx -> in -> current [0 ] && (status != LYJSON_OBJECT_CLOSED )) {
18951984 LOGVAL (ctx , LYVE_SYNTAX , "Unexpected sibling node." );
@@ -1919,6 +2008,13 @@ lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, st
19192008 }
19202009 }
19212010
2011+ goto cleanup ;
2012+
2013+ representation_error :
2014+ LOGVAL (ctx , LYVE_SYNTAX_JSON , "Expecting JSON %s but %s \"%s\" is represented in input data as %s." ,
2015+ expected , lys_nodetype2str (schema -> nodetype ), schema -> name , lyjson_token2str (status ));
2016+ rc = LY_EVALID ;
2017+
19222018cleanup :
19232019 /* there should be no unresolved types stored */
19242020 assert (!(parse_opts & LYD_PARSE_ONLY ) || !lydctx || (!lydctx -> node_types .count && !lydctx -> meta_types .count &&
@@ -1927,12 +2023,19 @@ lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, st
19272023 if (rc && (!lydctx || !(lydctx -> val_opts & LYD_VALIDATE_MULTI_ERROR ) || (rc != LY_EVALID ))) {
19282024 lyd_json_ctx_free ((struct lyd_ctx * )lydctx );
19292025 } else {
1930- * lydctx_p = (struct lyd_ctx * )lydctx ;
1931-
19322026 /* the JSON context is no more needed, freeing it also stops logging line numbers which would be confusing now */
19332027 lyjson_ctx_free (lydctx -> jsonctx );
19342028 lydctx -> jsonctx = NULL ;
2029+
2030+ /* set optional lydctx pointer, otherwise free */
2031+ if (lydctx_p ) {
2032+ * lydctx_p = (struct lyd_ctx * )lydctx ;
2033+ } else {
2034+ lyd_json_ctx_free ((struct lyd_ctx * )lydctx );
2035+ }
19352036 }
2037+
2038+ lyd_free_tree (node );
19362039 return rc ;
19372040}
19382041
@@ -2020,7 +2123,7 @@ lyd_parse_json_restconf(const struct ly_ctx *ctx, const struct lysc_ext_instance
20202123 assert (!(parse_opts & LYD_PARSE_SUBTREE ));
20212124
20222125 /* init context */
2023- rc = lyd_parse_json_init (ctx , in , parse_opts , val_opts , & lydctx );
2126+ rc = lyd_parse_json_init (ctx , NULL , in , parse_opts , val_opts , NULL , & lydctx );
20242127 LY_CHECK_GOTO (rc , cleanup );
20252128 lydctx -> ext = ext ;
20262129
0 commit comments