@@ -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,139 @@ 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
1879+ /**
1880+ * @brief Parse a bare JSON value.
1881+ *
1882+ * @param[in] lydctx Data parser context.
1883+ * @param[in,out] status Current status of the data parser context.
1884+ * @param[in] parent Parent to connect the parsed nodes to, if any.
1885+ * @param[in] schema Optional schema node of the parsed node (mandatory when parsing JSON value fragment).
1886+ * @param[in,out] first_p Pointer to the first top-level parsed node, used only if @p parent is NULL.
1887+ * @return LY_ERR value.
1888+ */
1889+ static LY_ERR
1890+ lyd_parse_json_bare_value (struct lyd_json_ctx * lydctx , enum LYJSON_PARSER_STATUS * status , struct lyd_node * parent ,
1891+ const struct lysc_node * schema , struct lyd_node * * first_p )
1892+ {
1893+ LY_ERR r , rc = LY_SUCCESS ;
1894+ const struct ly_ctx * ctx = lydctx -> jsonctx -> ctx ;
1895+ struct lyd_node * node = NULL ;
1896+ const char * expected = NULL ;
1897+
1898+ assert (schema );
1899+
1900+ /* this branch partly copies the behavior of lydjson_subtree_r() */
1901+
1902+ /* set expected representation */
1903+ switch (schema -> nodetype ) {
1904+ case LYS_LEAFLIST :
1905+ expected = "array of values" ;
1906+ break ;
1907+ case LYS_LEAF :
1908+ if (* status == LYJSON_ARRAY ) {
1909+ expected = "[null]" ;
1910+ } else {
1911+ expected = "value" ;
1912+ }
1913+ break ;
1914+ }
1915+
1916+ /* check the representation according to the nodetype and then continue with the content */
1917+ /* for now object values are not supported (anydata) */
1918+ /* for now extensions not supported */
1919+ switch (schema -> nodetype ) {
1920+ case LYS_LEAFLIST :
1921+ LY_CHECK_GOTO (* status != LYJSON_ARRAY , representation_error );
1922+
1923+ /* process all the values/objects */
1924+ do {
1925+ /* move into array/next value */
1926+ r = lyjson_ctx_next (lydctx -> jsonctx , status );
1927+ LY_CHECK_ERR_GOTO (r , rc = r , cleanup );
1928+ if (* status == LYJSON_ARRAY_CLOSED ) {
1929+ /* empty array, fine... */
1930+ break ;
1931+ }
1932+
1933+ r = lydjson_parse_instance (lydctx , parent , first_p , schema , NULL , schema -> name , strlen (schema -> name ),
1934+ NULL , 0 , status , & node );
1935+ if (r == LY_ENOT ) {
1936+ goto representation_error ;
1937+ }
1938+ LY_DPARSER_ERR_GOTO (r , rc = r , lydctx , cleanup );
1939+
1940+ lydjson_maintain_children (parent , first_p , & node ,
1941+ lydctx -> parse_opts & LYD_PARSE_ORDERED ? LYD_INSERT_NODE_LAST : LYD_INSERT_NODE_DEFAULT , NULL );
1942+
1943+ /* move after the item(s) */
1944+ r = lyjson_ctx_next (lydctx -> jsonctx , status );
1945+ LY_CHECK_ERR_GOTO (r , rc = r , cleanup );
1946+ } while (* status == LYJSON_ARRAY_NEXT );
1947+
1948+ break ;
1949+ case LYS_LEAF :
1950+ /* process the value/object */
1951+ r = lydjson_parse_instance (lydctx , parent , first_p , schema , NULL , schema -> name , strlen (schema -> name ),
1952+ NULL , 0 , status , & node );
1953+ if (r == LY_ENOT ) {
1954+ goto representation_error ;
1955+ }
1956+ LY_DPARSER_ERR_GOTO (r , rc = r , lydctx , cleanup );
1957+
1958+ /* finally connect the parsed node, is zeroed */
1959+ lydjson_maintain_children (parent , first_p , & node ,
1960+ lydctx -> parse_opts & LYD_PARSE_ORDERED ? LYD_INSERT_NODE_LAST : LYD_INSERT_NODE_DEFAULT , NULL );
1961+ break ;
1962+ }
1963+
1964+ goto cleanup ;
1965+
1966+ representation_error :
1967+ LOGVAL (ctx , LYVE_SYNTAX_JSON , "Expecting JSON %s but %s \"%s\" is represented in input data as %s." ,
1968+ expected , lys_nodetype2str (schema -> nodetype ), schema -> name , lyjson_token2str (* status ));
1969+ rc = LY_EVALID ;
1970+
1971+ cleanup :
1972+ lyd_free_tree (node );
1973+ return rc ;
1974+ }
1975+
18641976LY_ERR
18651977lyd_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 )
1978+ const struct lysc_node * schema , struct lyd_node * * first_p , struct ly_in * in , uint32_t parse_opts ,
1979+ uint32_t val_opts , uint32_t int_opts , struct ly_set * parsed , ly_bool * subtree_sibling ,
1980+ struct lyd_ctx * * lydctx_p )
18681981{
18691982 LY_ERR r , rc = LY_SUCCESS ;
18701983 struct lyd_json_ctx * lydctx = NULL ;
1871- enum LYJSON_PARSER_STATUS status ;
1984+ enum LYJSON_PARSER_STATUS status = LYJSON_ERROR ;
18721985
1873- rc = lyd_parse_json_init (ctx , in , parse_opts , val_opts , & lydctx );
1986+ rc = lyd_parse_json_init (ctx , schema , in , parse_opts , val_opts , & status , & lydctx );
18741987 LY_CHECK_GOTO (rc , cleanup );
18751988
18761989 lydctx -> int_opts = int_opts ;
@@ -1879,17 +1992,25 @@ lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, st
18791992 /* find the operation node if it exists already */
18801993 LY_CHECK_GOTO (rc = lyd_parser_find_operation (parent , int_opts , & lydctx -> op_node ), cleanup );
18811994
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 );
1995+ if (status != LYJSON_OBJECT ) {
1996+ /* parse bare JSON value */
1997+ r = lyd_parse_json_bare_value (lydctx , & status , parent , schema , first_p );
1998+ LY_CHECK_ERR_GOTO (r , rc = r , cleanup );
1999+ } else {
2000+ /* parse JSON object */
18862001
1887- status = lyjson_ctx_status (lydctx -> jsonctx );
2002+ /* read subtree(s) */
2003+ do {
2004+ r = lydjson_subtree_r (lydctx , parent , first_p , parsed );
2005+ LY_DPARSER_ERR_GOTO (r , rc = r , lydctx , cleanup );
18882006
1889- if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS )) {
1890- break ;
1891- }
1892- } while (status == LYJSON_OBJECT_NEXT );
2007+ status = lyjson_ctx_status (lydctx -> jsonctx );
2008+
2009+ if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS )) {
2010+ break ;
2011+ }
2012+ } while (status == LYJSON_OBJECT_NEXT );
2013+ }
18932014
18942015 if ((int_opts & LYD_INTOPT_NO_SIBLINGS ) && lydctx -> jsonctx -> in -> current [0 ] && (status != LYJSON_OBJECT_CLOSED )) {
18952016 LOGVAL (ctx , LYVE_SYNTAX , "Unexpected sibling node." );
@@ -1927,11 +2048,16 @@ lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, st
19272048 if (rc && (!lydctx || !(lydctx -> val_opts & LYD_VALIDATE_MULTI_ERROR ) || (rc != LY_EVALID ))) {
19282049 lyd_json_ctx_free ((struct lyd_ctx * )lydctx );
19292050 } else {
1930- * lydctx_p = (struct lyd_ctx * )lydctx ;
1931-
19322051 /* the JSON context is no more needed, freeing it also stops logging line numbers which would be confusing now */
19332052 lyjson_ctx_free (lydctx -> jsonctx );
19342053 lydctx -> jsonctx = NULL ;
2054+
2055+ /* set optional lydctx pointer, otherwise free */
2056+ if (lydctx_p ) {
2057+ * lydctx_p = (struct lyd_ctx * )lydctx ;
2058+ } else {
2059+ lyd_json_ctx_free ((struct lyd_ctx * )lydctx );
2060+ }
19352061 }
19362062 return rc ;
19372063}
@@ -2020,7 +2146,7 @@ lyd_parse_json_restconf(const struct ly_ctx *ctx, const struct lysc_ext_instance
20202146 assert (!(parse_opts & LYD_PARSE_SUBTREE ));
20212147
20222148 /* init context */
2023- rc = lyd_parse_json_init (ctx , in , parse_opts , val_opts , & lydctx );
2149+ rc = lyd_parse_json_init (ctx , NULL , in , parse_opts , val_opts , NULL , & lydctx );
20242150 LY_CHECK_GOTO (rc , cleanup );
20252151 lydctx -> ext = ext ;
20262152
0 commit comments