Moved code from clixon_xml.c to namespace and io functions to reduce size of core xml file
This commit is contained in:
parent
2d521d52c8
commit
75b20936d3
22 changed files with 1162 additions and 1011 deletions
|
|
@ -42,7 +42,7 @@ Expected: Early March 2020
|
||||||
* Bugfix of config false statement may cause change of sorting of lists in GET opertions (lists that were sorted should not have been sorted)
|
* Bugfix of config false statement may cause change of sorting of lists in GET opertions (lists that were sorted should not have been sorted)
|
||||||
* New clixon-config@2020-02-22.yang revision
|
* New clixon-config@2020-02-22.yang revision
|
||||||
* Search index extension `search_index` for declaring which non-key variables are search indexes
|
* Search index extension `search_index` for declaring which non-key variables are search indexes
|
||||||
* Added `clixon-stats` for clixon XML and memory statistics.
|
* Added `clixon-stats` state for clixon XML and memory statistics.
|
||||||
* JSON parse error messages change from ` on line x: syntax error,..` to `json_parse: line x: syntax error`
|
* JSON parse error messages change from ` on line x: syntax error,..` to `json_parse: line x: syntax error`
|
||||||
* Unknown-element error message is more descriptive, eg from `namespace is: urn:example:clixon` to: `Failed to find YANG spec of XML node: x with parent: xp in namespace urn:example:clixon`.
|
* Unknown-element error message is more descriptive, eg from `namespace is: urn:example:clixon` to: `Failed to find YANG spec of XML node: x with parent: xp in namespace urn:example:clixon`.
|
||||||
* C-API parse and validation API more capable
|
* C-API parse and validation API more capable
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@
|
||||||
#include <clixon/clixon_regex.h>
|
#include <clixon/clixon_regex.h>
|
||||||
#include <clixon/clixon_path.h>
|
#include <clixon/clixon_path.h>
|
||||||
#include <clixon/clixon_xml_map.h>
|
#include <clixon/clixon_xml_map.h>
|
||||||
|
#include <clixon/clixon_xml_io.h>
|
||||||
#include <clixon/clixon_validate.h>
|
#include <clixon/clixon_validate.h>
|
||||||
#include <clixon/clixon_datastore.h>
|
#include <clixon/clixon_datastore.h>
|
||||||
#include <clixon/clixon_xpath_ctx.h>
|
#include <clixon/clixon_xpath_ctx.h>
|
||||||
|
|
|
||||||
|
|
@ -134,9 +134,6 @@ int nscache_set(cxobj *x, char *prefix, char *namespace);
|
||||||
int nscache_clear(cxobj *x);
|
int nscache_clear(cxobj *x);
|
||||||
int nscache_replace(cxobj *x, cvec *ns);
|
int nscache_replace(cxobj *x, cvec *ns);
|
||||||
|
|
||||||
int xml2ns(cxobj *x, char *localname, char **namespace);
|
|
||||||
int xml2prefix(cxobj *xn, char *namespace, char **prefixp);
|
|
||||||
|
|
||||||
int xmlns_set(cxobj *x, char *prefix, char *namespace);
|
int xmlns_set(cxobj *x, char *prefix, char *namespace);
|
||||||
cxobj *xml_parent(cxobj *xn);
|
cxobj *xml_parent(cxobj *xn);
|
||||||
int xml_parent_set(cxobj *xn, cxobj *parent);
|
int xml_parent_set(cxobj *xn, cxobj *parent);
|
||||||
|
|
@ -193,20 +190,6 @@ cxobj *xml_find_body_obj(cxobj *xt, char *name, char *val);
|
||||||
|
|
||||||
int xml_free(cxobj *xn);
|
int xml_free(cxobj *xn);
|
||||||
|
|
||||||
int xml_print(FILE *f, cxobj *xn);
|
|
||||||
int clicon_xml2file(FILE *f, cxobj *xn, int level, int prettyprint);
|
|
||||||
int clicon_xml2cbuf(cbuf *xf, cxobj *xn, int level, int prettyprint, int32_t depth);
|
|
||||||
int xml_parse_file(int fd, yang_stmt *yspec, cxobj **xt);
|
|
||||||
int xml_parse_file2(int fd, enum yang_bind bind, yang_stmt *yspec, char *endtag, cxobj **xt, cxobj **xerr);
|
|
||||||
int xml_parse_string(const char *str, yang_stmt *yspec, cxobj **xml_top);
|
|
||||||
int xml_parse_string2(const char *str, enum yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr);
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
|
||||||
int xml_parse_va(cxobj **xt, yang_stmt *yspec, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
|
|
||||||
#else
|
|
||||||
int xml_parse_va(cxobj **xt, yang_stmt *yspec, const char *format, ...);
|
|
||||||
#endif
|
|
||||||
int xmltree2cbuf(cbuf *cb, cxobj *x, int level);
|
|
||||||
int xml_copy_one(cxobj *xn0, cxobj *xn1);
|
int xml_copy_one(cxobj *xn0, cxobj *xn1);
|
||||||
int xml_copy(cxobj *x0, cxobj *x1);
|
int xml_copy(cxobj *x0, cxobj *x1);
|
||||||
cxobj *xml_dup(cxobj *x0);
|
cxobj *xml_dup(cxobj *x0);
|
||||||
|
|
@ -219,9 +202,6 @@ int xml_apply0(cxobj *xn, enum cxobj_type type, xml_applyfn_t fn, void *ar
|
||||||
int xml_apply_ancestor(cxobj *xn, xml_applyfn_t fn, void *arg);
|
int xml_apply_ancestor(cxobj *xn, xml_applyfn_t fn, void *arg);
|
||||||
int xml_isancestor(cxobj *x, cxobj *xp);
|
int xml_isancestor(cxobj *x, cxobj *xp);
|
||||||
|
|
||||||
int xml_body_parse(cxobj *xb, enum cv_type type, cg_var **cvp);
|
|
||||||
int xml_body_int32(cxobj *xb, int32_t *val);
|
|
||||||
int xml_body_uint32(cxobj *xb, uint32_t *val);
|
|
||||||
int xml_operation(char *opstr, enum operation_type *op);
|
int xml_operation(char *opstr, enum operation_type *op);
|
||||||
char *xml_operation2str(enum operation_type op);
|
char *xml_operation2str(enum operation_type op);
|
||||||
int xml_attr_insert2val(char *instr, enum insert_type *ins);
|
int xml_attr_insert2val(char *instr, enum insert_type *ins);
|
||||||
|
|
|
||||||
65
lib/clixon/clixon_xml_io.h
Normal file
65
lib/clixon/clixon_xml_io.h
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
||||||
|
Copyright (C) 2017-2019 Olof Hagsand
|
||||||
|
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC
|
||||||
|
|
||||||
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Alternatively, the contents of this file may be used under the terms of
|
||||||
|
the GNU General Public License Version 3 or later (the "GPL"),
|
||||||
|
in which case the provisions of the GPL are applicable instead
|
||||||
|
of those above. If you wish to allow use of your version of this file only
|
||||||
|
under the terms of the GPL, and not to allow others to
|
||||||
|
use your version of this file under the terms of Apache License version 2,
|
||||||
|
indicate your decision by deleting the provisions above and replace them with
|
||||||
|
the notice and other provisions required by the GPL. If you do not delete
|
||||||
|
the provisions above, a recipient may use your version of this file under
|
||||||
|
the terms of any one of the Apache License version 2 or the GPL.
|
||||||
|
|
||||||
|
***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
|
* Clixon XML object parse and print functions
|
||||||
|
* @see https://www.w3.org/TR/2008/REC-xml-20081126
|
||||||
|
* https://www.w3.org/TR/2009/REC-xml-names-20091208
|
||||||
|
*/
|
||||||
|
#ifndef _CLIXON_XML_IO_H_
|
||||||
|
#define _CLIXON_XML_IO_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes
|
||||||
|
*/
|
||||||
|
int clicon_xml2file(FILE *f, cxobj *x, int level, int prettyprint);
|
||||||
|
int xml_print(FILE *f, cxobj *xn);
|
||||||
|
int clicon_xml2cbuf(cbuf *cb, cxobj *x, int level, int prettyprint, int32_t depth);
|
||||||
|
int xmltree2cbuf(cbuf *cb, cxobj *x, int level);
|
||||||
|
|
||||||
|
int xml_parse_file(int fd, yang_stmt *yspec, cxobj **xt);
|
||||||
|
int xml_parse_file2(int fd, enum yang_bind yb, yang_stmt *yspec, char *endtag, cxobj **xt, cxobj **xerr);
|
||||||
|
int xml_parse_string2(const char *str, enum yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr);
|
||||||
|
int xml_parse_string(const char *str, yang_stmt *yspec, cxobj **xt);
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||||
|
int xml_parse_va(cxobj **xt, yang_stmt *yspec, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
|
||||||
|
#else
|
||||||
|
int xml_parse_va(cxobj **xt, yang_stmt *yspec, const char *format, ...);
|
||||||
|
#endif
|
||||||
|
#ifdef NOTUSED
|
||||||
|
int xml_body_int32(cxobj *xb, int32_t *val);
|
||||||
|
int xml_body_uint32(cxobj *xb, uint32_t *val);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _CLIXON_XML_IO_H_ */
|
||||||
|
|
@ -57,4 +57,8 @@ int xml_nsctx_node(cxobj *x, cvec **ncp);
|
||||||
int xml_nsctx_yang(yang_stmt *yn, cvec **ncp);
|
int xml_nsctx_yang(yang_stmt *yn, cvec **ncp);
|
||||||
int xml_nsctx_yangspec(yang_stmt *yspec, cvec **ncp);
|
int xml_nsctx_yangspec(yang_stmt *yspec, cvec **ncp);
|
||||||
|
|
||||||
|
int xml2ns(cxobj *x, char *localname, char **namespace);
|
||||||
|
int xml2prefix(cxobj *xn, char *namespace, char **prefixp);
|
||||||
|
int xml_localname_check(cxobj *xn, void *arg);
|
||||||
|
|
||||||
#endif /* _CLIXON_XML_NSCTX_H */
|
#endif /* _CLIXON_XML_NSCTX_H */
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,8 @@ INCLUDES = -I. @INCLUDES@ -I$(top_srcdir)/lib/clixon -I$(top_srcdir)/include -I$
|
||||||
|
|
||||||
SRC = clixon_sig.c clixon_uid.c clixon_log.c clixon_err.c clixon_event.c \
|
SRC = clixon_sig.c clixon_uid.c clixon_log.c clixon_err.c clixon_event.c \
|
||||||
clixon_string.c clixon_regex.c clixon_handle.c clixon_file.c \
|
clixon_string.c clixon_regex.c clixon_handle.c clixon_file.c \
|
||||||
clixon_xml.c clixon_xml_sort.c clixon_xml_map.c clixon_xml_vec.c clixon_json.c \
|
clixon_xml.c clixon_xml_io.c clixon_xml_sort.c clixon_xml_map.c clixon_xml_vec.c \
|
||||||
|
clixon_json.c \
|
||||||
clixon_yang.c clixon_yang_type.c clixon_yang_module.c clixon_yang_parse_lib.c \
|
clixon_yang.c clixon_yang_type.c clixon_yang_module.c clixon_yang_parse_lib.c \
|
||||||
clixon_yang_cardinality.c clixon_xml_changelog.c clixon_xml_nsctx.c \
|
clixon_yang_cardinality.c clixon_xml_changelog.c clixon_xml_nsctx.c \
|
||||||
clixon_path.c clixon_validate.c \
|
clixon_path.c clixon_validate.c \
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
|
|
||||||
#include "clixon_datastore.h"
|
#include "clixon_datastore.h"
|
||||||
|
|
@ -646,7 +647,7 @@ xmldb_get_zerocopy(clicon_handle h,
|
||||||
|
|
||||||
/*! Get content of datastore and return a copy of the XML tree
|
/*! Get content of datastore and return a copy of the XML tree
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] db Name of database to search in (filename including dir path
|
* @param[in] db Name of database to search in, eg "running"
|
||||||
* @param[in] nsc XML namespace context for XPATH
|
* @param[in] nsc XML namespace context for XPATH
|
||||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||||
* @param[out] xret Single return XML tree. Free with xml_free()
|
* @param[out] xret Single return XML tree. Free with xml_free()
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,8 @@
|
||||||
#include "clixon_yang_type.h"
|
#include "clixon_yang_type.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
|
|
||||||
#include "clixon_datastore.h"
|
#include "clixon_datastore.h"
|
||||||
#include "clixon_datastore_write.h"
|
#include "clixon_datastore_write.h"
|
||||||
#include "clixon_datastore_read.h"
|
#include "clixon_datastore_read.h"
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_data.h"
|
#include "clixon_data.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
#include "clixon_xpath.h"
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@
|
||||||
#include "clixon_yang_parse_lib.h"
|
#include "clixon_yang_parse_lib.h"
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_validate.h"
|
#include "clixon_validate.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_sig.h"
|
#include "clixon_sig.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_proto.h"
|
#include "clixon_proto.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
#include "clixon_xml_sort.h"
|
#include "clixon_xml_sort.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
#include "clixon_proto_client.h"
|
#include "clixon_proto_client.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_data.h"
|
#include "clixon_data.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -72,6 +72,7 @@
|
||||||
#include "clixon_netconf_lib.h"
|
#include "clixon_netconf_lib.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_validate.h"
|
#include "clixon_validate.h"
|
||||||
#include "clixon_xml_changelog.h"
|
#include "clixon_xml_changelog.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
|
|
|
||||||
851
lib/src/clixon_xml_io.c
Normal file
851
lib/src/clixon_xml_io.c
Normal file
|
|
@ -0,0 +1,851 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
||||||
|
Copyright (C) 2017-2019 Olof Hagsand
|
||||||
|
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC
|
||||||
|
|
||||||
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Alternatively, the contents of this file may be used under the terms of
|
||||||
|
the GNU General Public License Version 3 or later (the "GPL"),
|
||||||
|
in which case the provisions of the GPL are applicable instead
|
||||||
|
of those above. If you wish to allow use of your version of this file only
|
||||||
|
under the terms of the GPL, and not to allow others to
|
||||||
|
use your version of this file under the terms of Apache License version 2,
|
||||||
|
indicate your decision by deleting the provisions above and replace them with
|
||||||
|
the notice and other provisions required by the GPL. If you do not delete
|
||||||
|
the provisions above, a recipient may use your version of this file under
|
||||||
|
the terms of any one of the Apache License version 2 or the GPL.
|
||||||
|
|
||||||
|
***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
|
* Clixon XML object parse and print functions
|
||||||
|
* @see https://www.w3.org/TR/2008/REC-xml-20081126
|
||||||
|
* https://www.w3.org/TR/2009/REC-xml-names-20091208
|
||||||
|
* Canonical XML version (just for info)
|
||||||
|
* https://www.w3.org/TR/xml-c14n
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/* cligen */
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
/* clixon */
|
||||||
|
#include "clixon_err.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
|
#include "clixon_queue.h"
|
||||||
|
#include "clixon_hash.h"
|
||||||
|
#include "clixon_handle.h"
|
||||||
|
#include "clixon_log.h"
|
||||||
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_options.h" /* xml_spec_populate */
|
||||||
|
#include "clixon_yang_module.h"
|
||||||
|
#include "clixon_xml_map.h" /* xml_spec_populate */
|
||||||
|
#include "clixon_xml_vec.h"
|
||||||
|
#include "clixon_xml_sort.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
|
#include "clixon_xml_parse.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constants
|
||||||
|
*/
|
||||||
|
/* Size of xml read buffer */
|
||||||
|
#define BUFLEN 1024
|
||||||
|
/* Indentation for xml pretty-print. Consider option? */
|
||||||
|
#define XML_INDENT 3
|
||||||
|
/* Name of xml top object created by xml parse functions */
|
||||||
|
#define XML_TOP_SYMBOL "top"
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------
|
||||||
|
* XML printing functions. Output a parse tree to file, string cligen buf
|
||||||
|
*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*! Print an XML tree structure to an output stream and encode chars "<>&"
|
||||||
|
*
|
||||||
|
* @param[in] f UNIX output stream
|
||||||
|
* @param[in] xn clicon xml tree
|
||||||
|
* @param[in] level how many spaces to insert before each line
|
||||||
|
* @param[in] prettyprint insert \n and spaces tomake the xml more readable.
|
||||||
|
* @see clicon_xml2cbuf
|
||||||
|
* One can use clicon_xml2cbuf to get common code, but using fprintf is
|
||||||
|
* much faster than using cbuf and then printing that,...
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clicon_xml2file(FILE *f,
|
||||||
|
cxobj *x,
|
||||||
|
int level,
|
||||||
|
int prettyprint)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *name;
|
||||||
|
char *namespace;
|
||||||
|
cxobj *xc;
|
||||||
|
int hasbody;
|
||||||
|
int haselement;
|
||||||
|
char *val;
|
||||||
|
char *encstr = NULL; /* xml encoded string */
|
||||||
|
|
||||||
|
if (x == NULL)
|
||||||
|
goto ok;
|
||||||
|
name = xml_name(x);
|
||||||
|
namespace = xml_prefix(x);
|
||||||
|
switch(xml_type(x)){
|
||||||
|
case CX_BODY:
|
||||||
|
if ((val = xml_value(x)) == NULL) /* incomplete tree */
|
||||||
|
break;
|
||||||
|
if (xml_chardata_encode(&encstr, "%s", val) < 0)
|
||||||
|
goto done;
|
||||||
|
fprintf(f, "%s", encstr);
|
||||||
|
break;
|
||||||
|
case CX_ATTR:
|
||||||
|
fprintf(f, " ");
|
||||||
|
if (namespace)
|
||||||
|
fprintf(f, "%s:", namespace);
|
||||||
|
fprintf(f, "%s=\"%s\"", name, xml_value(x));
|
||||||
|
break;
|
||||||
|
case CX_ELMNT:
|
||||||
|
fprintf(f, "%*s<", prettyprint?(level*XML_INDENT):0, "");
|
||||||
|
if (namespace)
|
||||||
|
fprintf(f, "%s:", namespace);
|
||||||
|
fprintf(f, "%s", name);
|
||||||
|
hasbody = 0;
|
||||||
|
haselement = 0;
|
||||||
|
xc = NULL;
|
||||||
|
/* print attributes only */
|
||||||
|
while ((xc = xml_child_each(x, xc, -1)) != NULL) {
|
||||||
|
switch (xml_type(xc)){
|
||||||
|
case CX_ATTR:
|
||||||
|
if (clicon_xml2file(f, xc, level+1, prettyprint) <0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
case CX_BODY:
|
||||||
|
hasbody=1;
|
||||||
|
break;
|
||||||
|
case CX_ELMNT:
|
||||||
|
haselement=1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Check for special case <a/> instead of <a></a>:
|
||||||
|
* Ie, no CX_BODY or CX_ELMNT child.
|
||||||
|
*/
|
||||||
|
if (hasbody==0 && haselement==0)
|
||||||
|
fprintf(f, "/>");
|
||||||
|
else{
|
||||||
|
fprintf(f, ">");
|
||||||
|
if (prettyprint && hasbody == 0)
|
||||||
|
fprintf(f, "\n");
|
||||||
|
xc = NULL;
|
||||||
|
while ((xc = xml_child_each(x, xc, -1)) != NULL) {
|
||||||
|
if (xml_type(xc) != CX_ATTR)
|
||||||
|
if (clicon_xml2file(f, xc, level+1, prettyprint) <0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (prettyprint && hasbody==0)
|
||||||
|
fprintf(f, "%*s", level*XML_INDENT, "");
|
||||||
|
fprintf(f, "</");
|
||||||
|
if (namespace)
|
||||||
|
fprintf(f, "%s:", namespace);
|
||||||
|
fprintf(f, "%s>", name);
|
||||||
|
}
|
||||||
|
if (prettyprint)
|
||||||
|
fprintf(f, "\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}/* switch */
|
||||||
|
ok:
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (encstr)
|
||||||
|
free(encstr);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Print an XML tree structure to an output stream
|
||||||
|
*
|
||||||
|
* Uses clicon_xml2file internally
|
||||||
|
*
|
||||||
|
* @param[in] f UNIX output stream
|
||||||
|
* @param[in] xn clicon xml tree
|
||||||
|
* @see clicon_xml2cbuf
|
||||||
|
* @see clicon_xml2file
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_print(FILE *f,
|
||||||
|
cxobj *xn)
|
||||||
|
{
|
||||||
|
return clicon_xml2file(f, xn, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Print an XML tree structure to a cligen buffer and encode chars "<>&"
|
||||||
|
*
|
||||||
|
* @param[in,out] cb Cligen buffer to write to
|
||||||
|
* @param[in] xn Clicon xml tree
|
||||||
|
* @param[in] level Indentation level for prettyprint
|
||||||
|
* @param[in] prettyprint insert \n and spaces tomake the xml more readable.
|
||||||
|
* @param[in] depth Limit levels of child resources: -1 is all, 0 is none, 1 is node itself
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* cbuf *cb;
|
||||||
|
* cb = cbuf_new();
|
||||||
|
* if (clicon_xml2cbuf(cb, xn, 0, 1, -1) < 0)
|
||||||
|
* goto err;
|
||||||
|
* fprintf(stderr, "%s", cbuf_get(cb));
|
||||||
|
* cbuf_free(cb);
|
||||||
|
* @endcode
|
||||||
|
* @see clicon_xml2file
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clicon_xml2cbuf(cbuf *cb,
|
||||||
|
cxobj *x,
|
||||||
|
int level,
|
||||||
|
int prettyprint,
|
||||||
|
int32_t depth)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *xc;
|
||||||
|
char *name;
|
||||||
|
int hasbody;
|
||||||
|
int haselement;
|
||||||
|
char *namespace;
|
||||||
|
char *encstr = NULL; /* xml encoded string */
|
||||||
|
char *val;
|
||||||
|
|
||||||
|
if (depth == 0)
|
||||||
|
goto ok;
|
||||||
|
name = xml_name(x);
|
||||||
|
namespace = xml_prefix(x);
|
||||||
|
switch(xml_type(x)){
|
||||||
|
case CX_BODY:
|
||||||
|
if ((val = xml_value(x)) == NULL) /* incomplete tree */
|
||||||
|
break;
|
||||||
|
if (xml_chardata_encode(&encstr, "%s", val) < 0)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "%s", encstr);
|
||||||
|
break;
|
||||||
|
case CX_ATTR:
|
||||||
|
cprintf(cb, " ");
|
||||||
|
if (namespace)
|
||||||
|
cprintf(cb, "%s:", namespace);
|
||||||
|
cprintf(cb, "%s=\"%s\"", name, xml_value(x));
|
||||||
|
break;
|
||||||
|
case CX_ELMNT:
|
||||||
|
cprintf(cb, "%*s<", prettyprint?(level*XML_INDENT):0, "");
|
||||||
|
if (namespace)
|
||||||
|
cprintf(cb, "%s:", namespace);
|
||||||
|
cprintf(cb, "%s", name);
|
||||||
|
hasbody = 0;
|
||||||
|
haselement = 0;
|
||||||
|
xc = NULL;
|
||||||
|
/* print attributes only */
|
||||||
|
while ((xc = xml_child_each(x, xc, -1)) != NULL)
|
||||||
|
switch (xml_type(xc)){
|
||||||
|
case CX_ATTR:
|
||||||
|
if (clicon_xml2cbuf(cb, xc, level+1, prettyprint, -1) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
case CX_BODY:
|
||||||
|
hasbody=1;
|
||||||
|
break;
|
||||||
|
case CX_ELMNT:
|
||||||
|
haselement=1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Check for special case <a/> instead of <a></a> */
|
||||||
|
if (hasbody==0 && haselement==0)
|
||||||
|
cprintf(cb, "/>");
|
||||||
|
else{
|
||||||
|
cprintf(cb, ">");
|
||||||
|
if (prettyprint && hasbody == 0)
|
||||||
|
cprintf(cb, "\n");
|
||||||
|
xc = NULL;
|
||||||
|
while ((xc = xml_child_each(x, xc, -1)) != NULL)
|
||||||
|
if (xml_type(xc) != CX_ATTR)
|
||||||
|
if (clicon_xml2cbuf(cb, xc, level+1, prettyprint, depth-1) < 0)
|
||||||
|
goto done;
|
||||||
|
if (prettyprint && hasbody == 0)
|
||||||
|
cprintf(cb, "%*s", level*XML_INDENT, "");
|
||||||
|
cprintf(cb, "</");
|
||||||
|
if (namespace)
|
||||||
|
cprintf(cb, "%s:", namespace);
|
||||||
|
cprintf(cb, "%s>", name);
|
||||||
|
}
|
||||||
|
if (prettyprint)
|
||||||
|
cprintf(cb, "\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}/* switch */
|
||||||
|
ok:
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (encstr)
|
||||||
|
free(encstr);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Print actual xml tree datastructures (not xml), mainly for debugging
|
||||||
|
* @param[in,out] cb Cligen buffer to write to
|
||||||
|
* @param[in] xn Clicon xml tree
|
||||||
|
* @param[in] level Indentation level
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmltree2cbuf(cbuf *cb,
|
||||||
|
cxobj *x,
|
||||||
|
int level)
|
||||||
|
{
|
||||||
|
cxobj *xc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<level*XML_INDENT; i++)
|
||||||
|
cprintf(cb, " ");
|
||||||
|
if (xml_type(x) != CX_BODY)
|
||||||
|
cprintf(cb, "%s", xml_type2str(xml_type(x)));
|
||||||
|
if (xml_prefix(x)==NULL)
|
||||||
|
cprintf(cb, " %s", xml_name(x));
|
||||||
|
else
|
||||||
|
cprintf(cb, " %s:%s", xml_prefix(x), xml_name(x));
|
||||||
|
if (xml_value(x))
|
||||||
|
cprintf(cb, " value:\"%s\"", xml_value(x));
|
||||||
|
if (xml_flag(x, 0xff))
|
||||||
|
cprintf(cb, " flags:0x%x", xml_flag(x, 0xff));
|
||||||
|
if (xml_child_nr(x))
|
||||||
|
cprintf(cb, " {");
|
||||||
|
cprintf(cb, "\n");
|
||||||
|
xc = NULL;
|
||||||
|
while ((xc = xml_child_each(x, xc, -1)) != NULL)
|
||||||
|
xmltree2cbuf(cb, xc, level+1);
|
||||||
|
if (xml_child_nr(x)){
|
||||||
|
for (i=0; i<level*XML_INDENT; i++)
|
||||||
|
cprintf(cb, " ");
|
||||||
|
cprintf(cb, "}\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------
|
||||||
|
* XML parsing functions. Create XML parse tree from string and file.
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
/*! Common internal xml parsing function string to parse-tree
|
||||||
|
*
|
||||||
|
* Given a string containing XML, parse into existing XML tree and return
|
||||||
|
* @param[in] str Pointer to string containing XML definition.
|
||||||
|
* @param[in] yb How to bind yang to XML top-level when parsing
|
||||||
|
* @param[in] yspec Yang specification (only if bind is TOP or CONFIG)
|
||||||
|
* @param[in,out] xtop Top of XML parse tree. Assume created. Holds new tree.
|
||||||
|
* @param[out] xerr Reason for failure (yang assignment not made)
|
||||||
|
* @retval 1 Parse OK and all yang assignment made
|
||||||
|
* @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set
|
||||||
|
* @retval -1 Error with clicon_err called. Includes parse error
|
||||||
|
* @see xml_parse_file
|
||||||
|
* @see xml_parse_string
|
||||||
|
* @see xml_parse_va
|
||||||
|
* @see _json_parse
|
||||||
|
* @note special case is empty XML where the parser is not invoked.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
_xml_parse(const char *str,
|
||||||
|
enum yang_bind yb,
|
||||||
|
yang_stmt *yspec,
|
||||||
|
cxobj *xt,
|
||||||
|
cxobj **xerr)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
clixon_xml_yacc xy = {0,};
|
||||||
|
cxobj *x;
|
||||||
|
int ret;
|
||||||
|
int failed = 0; /* yang assignment */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
clicon_debug(1, "%s %s", __FUNCTION__, str);
|
||||||
|
if (strlen(str) == 0)
|
||||||
|
return 0; /* OK */
|
||||||
|
if (xt == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "Unexpected NULL XML");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((xy.xy_parse_string = strdup(str)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
xy.xy_xtop = xt;
|
||||||
|
xy.xy_xparent = xt;
|
||||||
|
xy.xy_yspec = yspec;
|
||||||
|
if (clixon_xml_parsel_init(&xy) < 0)
|
||||||
|
goto done;
|
||||||
|
if (clixon_xml_parseparse(&xy) != 0) /* yacc returns 1 on error */
|
||||||
|
goto done;
|
||||||
|
/* Purge all top-level body objects */
|
||||||
|
x = NULL;
|
||||||
|
while ((x = xml_find_type(xt, NULL, "body", CX_BODY)) != NULL)
|
||||||
|
xml_purge(x);
|
||||||
|
/* Traverse new objects */
|
||||||
|
for (i = 0; i < xy.xy_xlen; i++) {
|
||||||
|
x = xy.xy_xvec[i];
|
||||||
|
/* Verify namespaces after parsing */
|
||||||
|
if (xml_apply0(x, CX_ELMNT, xml_localname_check, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Populate, ie associate xml nodes with yang specs
|
||||||
|
*/
|
||||||
|
switch (yb){
|
||||||
|
case YB_RPC:
|
||||||
|
case YB_UNKNOWN:
|
||||||
|
case YB_NONE:
|
||||||
|
break;
|
||||||
|
case YB_PARENT:
|
||||||
|
/* xt:n Has spec
|
||||||
|
* x: <a> <-- populate from parent
|
||||||
|
*/
|
||||||
|
if ((ret = xml_spec_populate0_parent(x, xerr)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
failed++;
|
||||||
|
break;
|
||||||
|
case YB_TOP:
|
||||||
|
/* xt:<top> nospec
|
||||||
|
* x: <a> <-- populate from modules
|
||||||
|
*/
|
||||||
|
#ifdef XMLDB_CONFIG_HACK
|
||||||
|
if (strcmp(xml_name(x),"config") == 0){
|
||||||
|
/* xt:<top> nospec
|
||||||
|
* x: <config>
|
||||||
|
* <a> <-- populate from modules
|
||||||
|
*/
|
||||||
|
if ((ret = xml_spec_populate(x, yspec, xerr)) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if ((ret = xml_spec_populate0(x, yspec, xerr)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
failed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Sort the complete tree after parsing. Sorting is less meaningful if Yang not bound */
|
||||||
|
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = (failed==0) ? 1 : 0;
|
||||||
|
done:
|
||||||
|
clixon_xml_parsel_exit(&xy);
|
||||||
|
if (xy.xy_parse_string != NULL)
|
||||||
|
free(xy.xy_parse_string);
|
||||||
|
if (xy.xy_xvec)
|
||||||
|
free(xy.xy_xvec);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Read an XML definition from file and parse it into a parse-tree.
|
||||||
|
*
|
||||||
|
* @param[in] fd A file descriptor containing the XML file (as ASCII characters)
|
||||||
|
* @param[in] yspec Yang specification, or NULL
|
||||||
|
* @param[in,out] xt Pointer to XML parse tree. If empty, create.
|
||||||
|
* @retval 1 Parse OK and all yang assignment made
|
||||||
|
* @retval 0 Parse OK but yang assigment not made (or only partial)
|
||||||
|
* @retval -1 Error with clicon_err called. Includes parse error *
|
||||||
|
* @code
|
||||||
|
* cxobj *xt = NULL;
|
||||||
|
* int fd;
|
||||||
|
* fd = open(filename, O_RDONLY);
|
||||||
|
* xml_parse_file(fd, yspec, &xt);
|
||||||
|
* xml_free(xt);
|
||||||
|
* @endcode
|
||||||
|
* @see xml_parse_string
|
||||||
|
* @see xml_parse_va
|
||||||
|
* @note, If xt empty, a top-level symbol will be added so that <tree../> will be: <top><tree.../></tree></top>
|
||||||
|
* @note May block on file I/O
|
||||||
|
* @see xml_parse_file2 for a more advanced API
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_parse_file(int fd,
|
||||||
|
yang_stmt *yspec,
|
||||||
|
cxobj **xt)
|
||||||
|
{
|
||||||
|
enum yang_bind yb = YB_PARENT;
|
||||||
|
|
||||||
|
if (xt==NULL){
|
||||||
|
clicon_err(OE_XML, EINVAL, "xt is NULL");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (*xt==NULL)
|
||||||
|
yb = YB_TOP;
|
||||||
|
return xml_parse_file2(fd, yb, yspec, NULL, xt, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! FSM to detect substring
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
FSM(char *tag,
|
||||||
|
char ch,
|
||||||
|
int state)
|
||||||
|
{
|
||||||
|
if (tag[state] == ch)
|
||||||
|
return state+1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Read an XML definition from file and parse it into a parse-tree, advanced API
|
||||||
|
*
|
||||||
|
* @param[in] fd A file descriptor containing the XML file (as ASCII characters)
|
||||||
|
* @param[in] yb How to bind yang to XML top-level when parsing
|
||||||
|
* @param[in] yspec Yang specification (only if bind is TOP or CONFIG)
|
||||||
|
* @param[in] endtag Read until encounter "endtag" in the stream, or NULL
|
||||||
|
* @param[in,out] xt Pointer to XML parse tree. If empty, create.
|
||||||
|
* @retval 1 Parse OK and all yang assignment made
|
||||||
|
* @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set
|
||||||
|
* @retval -1 Error with clicon_err called. Includes parse error
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* cxobj *xt = NULL;
|
||||||
|
* cxobj *xerr = NULL;
|
||||||
|
* int fd;
|
||||||
|
* fd = open(filename, O_RDONLY);
|
||||||
|
* if ((ret = xml_parse_file2(fd, YB_TOP, yspec, "</config>", &xt, &xerr)) < 0)
|
||||||
|
* err;
|
||||||
|
* xml_free(xt);
|
||||||
|
* @endcode
|
||||||
|
* @see xml_parse_string
|
||||||
|
* @see xml_parse_file
|
||||||
|
* @note, If xt empty, a top-level symbol will be added so that <tree../> will be: <top><tree.../></tree></top>
|
||||||
|
* @note May block on file I/O
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_parse_file2(int fd,
|
||||||
|
enum yang_bind yb,
|
||||||
|
yang_stmt *yspec,
|
||||||
|
char *endtag,
|
||||||
|
cxobj **xt,
|
||||||
|
cxobj **xerr)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
int ret;
|
||||||
|
int len = 0;
|
||||||
|
char ch;
|
||||||
|
char *xmlbuf = NULL;
|
||||||
|
char *ptr;
|
||||||
|
int xmlbuflen = BUFLEN; /* start size */
|
||||||
|
int endtaglen = 0;
|
||||||
|
int state = 0;
|
||||||
|
int oldxmlbuflen;
|
||||||
|
int failed = 0;
|
||||||
|
|
||||||
|
if (endtag != NULL)
|
||||||
|
endtaglen = strlen(endtag);
|
||||||
|
if ((xmlbuf = malloc(xmlbuflen)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "malloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memset(xmlbuf, 0, xmlbuflen);
|
||||||
|
ptr = xmlbuf;
|
||||||
|
while (1){
|
||||||
|
if ((ret = read(fd, &ch, 1)) < 0){
|
||||||
|
clicon_err(OE_XML, errno, "read: [pid:%d]",
|
||||||
|
(int)getpid());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret != 0){
|
||||||
|
if (endtag)
|
||||||
|
state = FSM(endtag, ch, state);
|
||||||
|
xmlbuf[len++] = ch;
|
||||||
|
}
|
||||||
|
if (ret == 0 ||
|
||||||
|
(endtag && (state == endtaglen))){
|
||||||
|
state = 0;
|
||||||
|
if (*xt == NULL)
|
||||||
|
if ((*xt = xml_new(XML_TOP_SYMBOL, NULL, NULL)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if ((ret = _xml_parse(ptr, yb, yspec, *xt, xerr)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0)
|
||||||
|
failed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (len>=xmlbuflen-1){ /* Space: one for the null character */
|
||||||
|
oldxmlbuflen = xmlbuflen;
|
||||||
|
xmlbuflen *= 2;
|
||||||
|
if ((xmlbuf = realloc(xmlbuf, xmlbuflen)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "realloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memset(xmlbuf+oldxmlbuflen, 0, xmlbuflen-oldxmlbuflen);
|
||||||
|
ptr = xmlbuf;
|
||||||
|
}
|
||||||
|
} /* while */
|
||||||
|
retval = (failed==0) ? 1 : 0;
|
||||||
|
done:
|
||||||
|
if (retval < 0 && *xt){
|
||||||
|
free(*xt);
|
||||||
|
*xt = NULL;
|
||||||
|
}
|
||||||
|
if (xmlbuf)
|
||||||
|
free(xmlbuf);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Read an XML definition from string and parse it into a parse-tree, advanced API
|
||||||
|
*
|
||||||
|
* @param[in] str String containing XML definition.
|
||||||
|
* @param[in] yb How to bind yang to XML top-level when parsing
|
||||||
|
* @param[in] yspec Yang specification, or NULL
|
||||||
|
* @param[in,out] xt Pointer to XML parse tree. If empty will be created.
|
||||||
|
* @param[out] xerr Reason for failure (yang assignment not made)
|
||||||
|
* @retval 1 Parse OK and all yang assignment made
|
||||||
|
* @retval 0 Parse OK but yang assigment not made (or only partial)
|
||||||
|
* @retval -1 Error with clicon_err called. Includes parse error
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* cxobj *xt = NULL;
|
||||||
|
* cxobj *xerr = NULL;
|
||||||
|
* if (xml_parse_string2(str, YB_TOP, yspec, &xt, &xerr) < 0)
|
||||||
|
* err;
|
||||||
|
* if (xml_rootchild(xt, 0, &xt) < 0) # If you want to remove TOP
|
||||||
|
* err;
|
||||||
|
* @endcode
|
||||||
|
* @see xml_parse_file
|
||||||
|
* @see xml_parse_va
|
||||||
|
* @note You need to free the xml parse tree after use, using xml_free()
|
||||||
|
* @note If empty on entry, a new TOP xml will be created named "top"
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_parse_string2(const char *str,
|
||||||
|
enum yang_bind yb,
|
||||||
|
yang_stmt *yspec,
|
||||||
|
cxobj **xt,
|
||||||
|
cxobj **xerr)
|
||||||
|
{
|
||||||
|
if (xt==NULL){
|
||||||
|
clicon_err(OE_XML, EINVAL, "xt is NULL");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (*xt == NULL){
|
||||||
|
if ((*xt = xml_new(XML_TOP_SYMBOL, NULL, NULL)) == NULL)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _xml_parse(str, yb, yspec, *xt, xerr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Read an XML definition from string and parse it into a parse-tree
|
||||||
|
*
|
||||||
|
* @param[in] str String containing XML definition.
|
||||||
|
* @param[in] yspec Yang specification, or NULL
|
||||||
|
* @param[in,out] xt Pointer to XML parse tree. If empty will be created.
|
||||||
|
* @retval 1 Parse OK and all yang assignment made
|
||||||
|
* @retval 0 Parse OK but yang assigment not made (or only partial)
|
||||||
|
* @retval -1 Error with clicon_err called. Includes parse error
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* cxobj *xt = NULL;
|
||||||
|
* if (xml_parse_string(str, yspec, &xt) < 0)
|
||||||
|
* err;
|
||||||
|
* if (xml_rootchild(xt, 0, &xt) < 0) # If you want to remove TOP
|
||||||
|
* err;
|
||||||
|
* @endcode
|
||||||
|
* @see xml_parse_file
|
||||||
|
* @see xml_parse_va
|
||||||
|
* @note You need to free the xml parse tree after use, using xml_free()
|
||||||
|
* @note If xt is empty on entry, a new TOP xml will be created named "top" and yang binding
|
||||||
|
* assumed to be TOP
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_parse_string(const char *str,
|
||||||
|
yang_stmt *yspec,
|
||||||
|
cxobj **xt)
|
||||||
|
{
|
||||||
|
enum yang_bind yb = YB_PARENT;
|
||||||
|
|
||||||
|
if (xt==NULL){
|
||||||
|
clicon_err(OE_XML, EINVAL, "xt is NULL");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (*xt == NULL){
|
||||||
|
yb = YB_TOP; /* ad-hoc #1 */
|
||||||
|
if ((*xt = xml_new(XML_TOP_SYMBOL, NULL, NULL)) == NULL)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (xml_spec(*xt) == NULL)
|
||||||
|
yb = YB_TOP; /* ad-hoc #2 */
|
||||||
|
}
|
||||||
|
return _xml_parse(str, yb, yspec, *xt, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Read XML from var-arg list and parse it into xml tree
|
||||||
|
*
|
||||||
|
* Utility function using stdarg instead of static string.
|
||||||
|
* @param[in,out] xtop Top of XML parse tree. If it is NULL, top element
|
||||||
|
called 'top' will be created. Call xml_free() after use
|
||||||
|
* @param[in] yspec Yang specification, or NULL
|
||||||
|
* @param[in] format Format string for stdarg according to printf(3)
|
||||||
|
* @retval 1 Parse OK and all yang assignment made
|
||||||
|
* @retval 0 Parse OK but yang assigment not made (or only partial)
|
||||||
|
* @retval -1 Error with clicon_err called. Includes parse error
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* cxobj *xt = NULL;
|
||||||
|
* if (xml_parse_va(&xt, NULL, "<xml>%d</xml>", 22) < 0)
|
||||||
|
* err;
|
||||||
|
* xml_free(xt);
|
||||||
|
* @endcode
|
||||||
|
* @see xml_parse_string
|
||||||
|
* @see xml_parse_file
|
||||||
|
* @note If vararg list is empty, consider using xml_parse_string()
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_parse_va(cxobj **xtop,
|
||||||
|
yang_stmt *yspec,
|
||||||
|
const char *format, ...)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
va_list args;
|
||||||
|
char *str = NULL;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
len = vsnprintf(NULL, 0, format, args) + 1;
|
||||||
|
va_end(args);
|
||||||
|
if ((str = malloc(len)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memset(str, 0, len);
|
||||||
|
va_start(args, format);
|
||||||
|
len = vsnprintf(str, len, format, args) + 1;
|
||||||
|
va_end(args);
|
||||||
|
retval = xml_parse_string(str, yspec, xtop); /* xml_parse_string2 */
|
||||||
|
done:
|
||||||
|
if (str)
|
||||||
|
free(str);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef NOTUSED
|
||||||
|
/*! Generic parse function for xml values
|
||||||
|
* @param[in] xb xml tree body node, ie containing a value to be parsed
|
||||||
|
* @param[in] type Type of value to be parsed in value
|
||||||
|
* @param[out] cvp CLIgen variable containing the parsed value
|
||||||
|
* @note free cv with cv_free after use.
|
||||||
|
* @see xml_body_int32 etc, for type-specific parse functions
|
||||||
|
* @note range check failure returns 0
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xml_body_parse(cxobj *xb,
|
||||||
|
enum cv_type type,
|
||||||
|
cg_var **cvp)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cg_var *cv = NULL;
|
||||||
|
int cvret;
|
||||||
|
char *bstr;
|
||||||
|
char *reason = NULL;
|
||||||
|
|
||||||
|
if ((bstr = xml_body(xb)) == NULL){
|
||||||
|
clicon_err(OE_XML, 0, "No body found");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((cv = cv_new(type)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cv_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((cvret = cv_parse1(bstr, cv, &reason)) < 0){
|
||||||
|
clicon_err(OE_XML, errno, "cv_parse");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (cvret == 0){ /* parsing failed */
|
||||||
|
clicon_err(OE_XML, errno, "Parsing CV: %s", reason);
|
||||||
|
if (reason)
|
||||||
|
free(reason);
|
||||||
|
}
|
||||||
|
*cvp = cv;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (retval < 0 && cv != NULL)
|
||||||
|
cv_free(cv);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Parse an xml body as int32
|
||||||
|
* The real parsing functions are in the cligen code
|
||||||
|
* @param[in] xb xml tree body node, ie containing a value to be parsed
|
||||||
|
* @param[out] val Value after parsing
|
||||||
|
* @retval 0 OK, parsed value in 'val'
|
||||||
|
* @retval -1 Error, one of: body not found, parse error,
|
||||||
|
* alloc error.
|
||||||
|
* @note extend to all other cligen var types and generalize
|
||||||
|
* @note use yang type info?
|
||||||
|
* @note range check failure returns 0
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_body_int32(cxobj *xb,
|
||||||
|
int32_t *val)
|
||||||
|
{
|
||||||
|
cg_var *cv = NULL;
|
||||||
|
|
||||||
|
if (xml_body_parse(xb, CGV_INT32, &cv) < 0)
|
||||||
|
return -1;
|
||||||
|
*val = cv_int32_get(cv);
|
||||||
|
cv_free(cv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Parse an xml body as uint32
|
||||||
|
* The real parsing functions are in the cligen code
|
||||||
|
* @param[in] xb xml tree body node, ie containing a value to be parsed
|
||||||
|
* @param[out] val Value after parsing
|
||||||
|
* @retval 0 OK, parsed value in 'val'
|
||||||
|
* @retval -1 Error, one of: body not found, parse error,
|
||||||
|
* alloc error.
|
||||||
|
* @note extend to all other cligen var types and generalize
|
||||||
|
* @note use yang type info?
|
||||||
|
* @note range check failure returns 0
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_body_uint32(cxobj *xb,
|
||||||
|
uint32_t *val)
|
||||||
|
{
|
||||||
|
cg_var *cv = NULL;
|
||||||
|
|
||||||
|
if (xml_body_parse(xb, CGV_UINT32, &cv) < 0)
|
||||||
|
return -1;
|
||||||
|
*val = cv_uint32_get(cv);
|
||||||
|
cv_free(cv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* NOTUSED */
|
||||||
|
|
@ -66,6 +66,7 @@
|
||||||
#include "clixon_log.h"
|
#include "clixon_log.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
|
|
||||||
/*! Create and initialize XML namespace context
|
/*! Create and initialize XML namespace context
|
||||||
|
|
@ -408,3 +409,224 @@ xml_nsctx_yangspec(yang_stmt *yspec,
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Given an xml tree return URI namespace recursively : default or localname given
|
||||||
|
*
|
||||||
|
* Given an XML tree and a prefix (or NULL) return URI namespace.
|
||||||
|
* @param[in] x XML tree
|
||||||
|
* @param[in] prefix prefix/ns localname. If NULL then return default.
|
||||||
|
* @param[out] namespace URI namespace (or NULL). Note pointer into xml tree
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @code
|
||||||
|
* if (xml2ns(xt, NULL, &namespace) < 0)
|
||||||
|
* err;
|
||||||
|
* @endcode
|
||||||
|
* @see xmlns_check
|
||||||
|
* @see xmlns_set cache is set
|
||||||
|
* @note, this function uses a cache.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml2ns(cxobj *x,
|
||||||
|
char *prefix,
|
||||||
|
char **namespace)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *ns = NULL;
|
||||||
|
cxobj *xp;
|
||||||
|
|
||||||
|
if ((ns = nscache_get(x, prefix)) != NULL)
|
||||||
|
goto ok;
|
||||||
|
if (prefix != NULL) /* xmlns:<prefix>="<uri>" */
|
||||||
|
ns = xml_find_type_value(x, "xmlns", prefix, CX_ATTR);
|
||||||
|
else{ /* xmlns="<uri>" */
|
||||||
|
ns = xml_find_type_value(x, NULL, "xmlns", CX_ATTR);
|
||||||
|
}
|
||||||
|
/* namespace not found, try parent */
|
||||||
|
if (ns == NULL){
|
||||||
|
if ((xp = xml_parent(x)) != NULL){
|
||||||
|
if (xml2ns(xp, prefix, &ns) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* If no parent, return default namespace if defined */
|
||||||
|
#ifdef USE_NETCONF_NS_AS_DEFAULT
|
||||||
|
else{
|
||||||
|
if (prefix == NULL)
|
||||||
|
ns = NETCONF_BASE_NAMESPACE;
|
||||||
|
else
|
||||||
|
ns = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/* Set default namespace cache (since code is at this point,
|
||||||
|
* no cache was found */
|
||||||
|
if (ns && nscache_set(x, prefix, ns) < 0)
|
||||||
|
goto done;
|
||||||
|
ok:
|
||||||
|
if (namespace)
|
||||||
|
*namespace = ns;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Add a namespace attribute to an XML node, either default or specific prefix
|
||||||
|
* @param[in] x XML tree
|
||||||
|
* @param[in] prefix prefix/ns localname. If NULL then set default xmlns
|
||||||
|
* @param[in] ns URI namespace (or NULL). Will be copied
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @see xml2ns
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmlns_set(cxobj *x,
|
||||||
|
char *prefix,
|
||||||
|
char *ns)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *xa;
|
||||||
|
|
||||||
|
if (prefix != NULL){ /* xmlns:<prefix>="<uri>" */
|
||||||
|
if ((xa = xml_new(prefix, x, NULL)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xml_prefix_set(xa, "xmlns") < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else{ /* xmlns="<uri>" */
|
||||||
|
if ((xa = xml_new("xmlns", x, NULL)) == NULL)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
xml_type_set(xa, CX_ATTR);
|
||||||
|
if (xml_value_set(xa, ns) < 0)
|
||||||
|
goto done;
|
||||||
|
/* (re)set namespace cache (as used in xml2ns) */
|
||||||
|
if (ns && nscache_set(x, prefix, ns) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Get namespace given prefix recursively
|
||||||
|
* @param[in] xn XML node
|
||||||
|
* @param[in] namespace Namespace
|
||||||
|
* @param[out] prefixp Pointer to prefix if found
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 No namespace found
|
||||||
|
* @retval 1 Namespace found, prefix returned in prefixp
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml2prefix(cxobj *xn,
|
||||||
|
char *namespace,
|
||||||
|
char **prefixp)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *xa = NULL;
|
||||||
|
cxobj *xp;
|
||||||
|
char *prefix = NULL;
|
||||||
|
char *xaprefix;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (nscache_get_prefix(xn, namespace, &prefix) == 1) /* found */
|
||||||
|
goto found;
|
||||||
|
xa = NULL;
|
||||||
|
while ((xa = xml_child_each(xn, xa, CX_ATTR)) != NULL) {
|
||||||
|
/* xmlns=namespace */
|
||||||
|
if (strcmp("xmlns", xml_name(xa)) == 0){
|
||||||
|
if (strcmp(xml_value(xa), namespace) == 0){
|
||||||
|
if (nscache_set(xn, NULL, namespace) < 0)
|
||||||
|
goto done;
|
||||||
|
prefix = NULL; /* Maybe should set all caches in ns:s children? */
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* xmlns:prefix=namespace */
|
||||||
|
else if ((xaprefix=xml_prefix(xa)) != NULL &&
|
||||||
|
strcmp("xmlns", xaprefix) == 0){
|
||||||
|
if (strcmp(xml_value(xa), namespace) == 0){
|
||||||
|
prefix = xml_name(xa);
|
||||||
|
if (nscache_set(xn, prefix, namespace) < 0)
|
||||||
|
goto done;
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((xp = xml_parent(xn)) != NULL){
|
||||||
|
if ((ret = xml2prefix(xp, namespace, &prefix)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 1){
|
||||||
|
if (nscache_set(xn, prefix, namespace) < 0)
|
||||||
|
goto done;
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
found:
|
||||||
|
*prefixp = prefix;
|
||||||
|
retval = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! See if xmlns:[<localname>=]<uri> exists, if so return <uri>
|
||||||
|
*
|
||||||
|
* @param[in] xn XML node
|
||||||
|
* @param[in] nsn Namespace name
|
||||||
|
* @retval URI return associated URI if found
|
||||||
|
* @retval NULL No namespace name binding found for nsn
|
||||||
|
* @see xml2ns XXX coordinate
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
xmlns_check(cxobj *xn,
|
||||||
|
char *nsn)
|
||||||
|
{
|
||||||
|
cxobj *x = NULL;
|
||||||
|
char *xns;
|
||||||
|
|
||||||
|
while ((x = xml_child_each(xn, x, CX_ATTR)) != NULL)
|
||||||
|
if ((xns = xml_prefix(x)) && strcmp(xns, "xmlns")==0 &&
|
||||||
|
strcmp(xml_name(x), nsn) == 0)
|
||||||
|
return xml_value(x);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Check namespace of xml node by searching recursively among ancestors
|
||||||
|
* @param[in] xn xml node
|
||||||
|
* @param[in] namespace check validity of namespace
|
||||||
|
* @retval 0 Found / validated or no yang spec
|
||||||
|
* @retval -1 Not found
|
||||||
|
* @note This function is grossly inefficient
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_localname_check(cxobj *xn,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
cxobj *xp = NULL;
|
||||||
|
char *nsn;
|
||||||
|
char *n;
|
||||||
|
yang_stmt *ys = xml_spec(xn);
|
||||||
|
|
||||||
|
/* No namespace name - comply */
|
||||||
|
if ((nsn = xml_prefix(xn)) == NULL)
|
||||||
|
return 0;
|
||||||
|
/* Check if NSN defined in same node */
|
||||||
|
if (xmlns_check(xn, nsn) != NULL)
|
||||||
|
return 0;
|
||||||
|
/* Check if NSN defined in some ancestor */
|
||||||
|
while ((xp = xml_parent(xn)) != NULL) {
|
||||||
|
if (xmlns_check(xp, nsn) != NULL)
|
||||||
|
return 0;
|
||||||
|
xn = xp;
|
||||||
|
}
|
||||||
|
/* Check if my namespace */
|
||||||
|
if ((n = yang_find_myprefix(ys)) != NULL && strcmp(nsn,n)==0)
|
||||||
|
return 0;
|
||||||
|
/* Check if any imported module */
|
||||||
|
if (yang_find_module_by_prefix(ys, nsn) != NULL)
|
||||||
|
return 0;
|
||||||
|
/* Not found, error */
|
||||||
|
clicon_err(OE_XML, ENOENT, "Namespace name %s in %s:%s not found",
|
||||||
|
nsn, nsn, xml_name(xn));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
#include "clixon_xpath.h"
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@
|
||||||
#include "clixon_log.h"
|
#include "clixon_log.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_xml_vec.h"
|
#include "clixon_xml_vec.h"
|
||||||
|
|
||||||
//typedef struct clixon_xml_vec clixon_xvec; /* struct defined in clicon_xml_vec.c */
|
//typedef struct clixon_xml_vec clixon_xvec; /* struct defined in clicon_xml_vec.c */
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_hash.h"
|
#include "clixon_hash.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_yang_module.h"
|
#include "clixon_yang_module.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_data.h"
|
#include "clixon_data.h"
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@
|
||||||
#include "clixon_file.h"
|
#include "clixon_file.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xml_io.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
#include "clixon_xpath.h"
|
#include "clixon_xpath.h"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue