@@ -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,137 @@ 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] ctx libyang context.
1883+ * @param[in] lydctx Data parser context.
1884+ * @param[in,out] status Current status of the data parser context.
1885+ * @param[in] parent Parent to connect the parsed nodes to, if any.
1886+ * @param[in] schema Optional schema node of the parsed node (mandatory when parsing JSON value fragment).
1887+ * @param[in,out] first_p Pointer to the first top-level parsed node, used only if @p parent is NULL.
1888+ * @return LY_ERR value.
1889+ */
1890+ static LY_ERR
1891+ lyd_parse_json_bare_value (const struct ly_ctx * ctx , struct lyd_json_ctx * lydctx , enum LYJSON_PARSER_STATUS * status ,
1892+ struct lyd_node * parent , const struct lysc_node * schema , struct lyd_node * * first_p )
1893+ {
1894+ LY_ERR r , rc = LY_SUCCESS ;
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+ representation_error :
1965+ LOGVAL (ctx , LYVE_SYNTAX_JSON , "Expecting JSON %s but %s \"%s\" is represented in input data as %s." ,
1966+ expected , lys_nodetype2str (schema -> nodetype ), schema -> name , lyjson_token2str (* status ));
1967+ rc = LY_EVALID ;
1968+
1969+ cleanup :
1970+ lyd_free_tree (node );
1971+ return rc ;
1972+ }
1973+
18641974LY_ERR
18651975lyd_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 )
1976+ const struct lysc_node * schema , struct lyd_node * * first_p , struct ly_in * in , uint32_t parse_opts ,
1977+ uint32_t val_opts , uint32_t int_opts , struct ly_set * parsed , ly_bool * subtree_sibling ,
1978+ struct lyd_ctx * * lydctx_p )
18681979{
18691980 LY_ERR r , rc = LY_SUCCESS ;
18701981 struct lyd_json_ctx * lydctx = NULL ;
1871- enum LYJSON_PARSER_STATUS status ;
1982+ enum LYJSON_PARSER_STATUS status = LYJSON_ERROR ;
18721983
1873- rc = lyd_parse_json_init (ctx , in , parse_opts , val_opts , & lydctx );
1984+ rc = lyd_parse_json_init (ctx , schema , in , parse_opts , val_opts , & status , & lydctx );
18741985 LY_CHECK_GOTO (rc , cleanup );
18751986
18761987 lydctx -> int_opts = int_opts ;
@@ -1879,17 +1990,25 @@ lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, st
18791990 /* find the operation node if it exists already */
18801991 LY_CHECK_GOTO (rc = lyd_parser_find_operation (parent , int_opts , & lydctx -> op_node ), cleanup );
18811992
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 );
1993+ if (status != LYJSON_OBJECT ) {
1994+ /* parse bare JSON value */
1995+ r = lyd_parse_json_bare_value (ctx , lydctx , & status , parent , schema , first_p );
1996+ LY_CHECK_ERR_GOTO (r , rc = r , cleanup );
1997+ } else {
1998+ /* parse JSON object */
18861999
1887- status = lyjson_ctx_status (lydctx -> jsonctx );
2000+ /* read subtree(s) */
2001+ do {
2002+ r = lydjson_subtree_r (lydctx , parent , first_p , parsed );
2003+ LY_DPARSER_ERR_GOTO (r , rc = r , lydctx , cleanup );
18882004
1889- if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS )) {
1890- break ;
1891- }
1892- } while (status == LYJSON_OBJECT_NEXT );
2005+ status = lyjson_ctx_status (lydctx -> jsonctx );
2006+
2007+ if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS )) {
2008+ break ;
2009+ }
2010+ } while (status == LYJSON_OBJECT_NEXT );
2011+ }
18932012
18942013 if ((int_opts & LYD_INTOPT_NO_SIBLINGS ) && lydctx -> jsonctx -> in -> current [0 ] && (status != LYJSON_OBJECT_CLOSED )) {
18952014 LOGVAL (ctx , LYVE_SYNTAX , "Unexpected sibling node." );
@@ -1927,11 +2046,16 @@ lyd_parse_json(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, st
19272046 if (rc && (!lydctx || !(lydctx -> val_opts & LYD_VALIDATE_MULTI_ERROR ) || (rc != LY_EVALID ))) {
19282047 lyd_json_ctx_free ((struct lyd_ctx * )lydctx );
19292048 } else {
1930- * lydctx_p = (struct lyd_ctx * )lydctx ;
1931-
19322049 /* the JSON context is no more needed, freeing it also stops logging line numbers which would be confusing now */
19332050 lyjson_ctx_free (lydctx -> jsonctx );
19342051 lydctx -> jsonctx = NULL ;
2052+
2053+ /* set optional lydctx pointer, otherwise free */
2054+ if (lydctx_p ) {
2055+ * lydctx_p = (struct lyd_ctx * )lydctx ;
2056+ } else {
2057+ lyd_json_ctx_free ((struct lyd_ctx * )lydctx );
2058+ }
19352059 }
19362060 return rc ;
19372061}
@@ -2020,7 +2144,7 @@ lyd_parse_json_restconf(const struct ly_ctx *ctx, const struct lysc_ext_instance
20202144 assert (!(parse_opts & LYD_PARSE_SUBTREE ));
20212145
20222146 /* init context */
2023- rc = lyd_parse_json_init (ctx , in , parse_opts , val_opts , & lydctx );
2147+ rc = lyd_parse_json_init (ctx , NULL , in , parse_opts , val_opts , NULL , & lydctx );
20242148 LY_CHECK_GOTO (rc , cleanup );
20252149 lydctx -> ext = ext ;
20262150
0 commit comments