[Libguestfs] [PATCH v3 1/4] mltools: Rename Yajl module as JSON_parser and move to common/mltools.

Richard W.M. Jones
Fri, 17 Aug 2018 15:16:10 -0000

Commit bd1c5c9f4dcf38458099db8a0bf4659a07ef055d changed all the code
to use Jansson instead of yajl.  However it didn't change the OCaml
API name (which was still Yajl).

This commit changes the module to a neutral name ("JSON_parser") and
moves it into common/mltools so it can be used by other tools.

This leaves us in a slightly awkward situation of having two JSON-ish
OCaml modules (JSON for creating trees and JSON_parser for parsing
them) with incompatible types.  That is left for future work to
resolve.  (It should be easier to do now that both modules live in the
same directory.)

This is just renaming and general refactoring.  There should be no
change in functionality.
---
 .gitignore                                    |  2 +-
 builder/Makefile.am                           | 57 ++++---------------
 builder/index_parser.ml                       |  2 +-
 builder/repository_main.ml                    |  2 +-
 builder/simplestreams_parser.ml               |  6 +-
 builder/utils.ml                              |  2 +-
 builder/utils.mli                             |  4 +-
 .../mltools/JSON_parser-c.c                   |  8 +--
 .../yajl.ml => common/mltools/JSON_parser.ml  | 38 ++++++-------
 .../mltools/JSON_parser.mli                   | 42 +++++++-------
 .../mltools/JSON_parser_tests.ml              | 56 +++++++++---------
 common/mltools/Makefile.am                    | 39 ++++++++++++-
 docs/C_SOURCE_FILES                           |  4 +-
 po/POTFILES                                   |  3 +-
 po/POTFILES-ml                                |  4 +-
 15 files changed, 135 insertions(+), 134 deletions(-)

diff --git a/.gitignore b/.gitignore
index 41219f4a1..b714b1a43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -113,7 +113,6 @@ Makefile.in
 /builder/virt-index-validate
 /builder/virt-index-validate.1
 /builder/*.xz
-/builder/yajl_tests
 /cat/stamp-virt-*.pod
 /cat/virt-cat
 /cat/virt-cat.1
@@ -146,6 +145,7 @@ Makefile.in
 /common/mltools/.depend
 /common/mltools/getopt_tests
 /common/mltools/JSON_tests
+/common/mltools/JSON_parser_tests
 /common/mltools/tools_utils_tests
 /common/mltools/oUnit-*
 /common/mlutils/.depend
diff --git a/builder/Makefile.am b/builder/Makefile.am
index 7ede544b7..f64750c7f 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -45,8 +45,7 @@ EXTRA_DIST = \
 	test-virt-index-validate-good-4 \
 	virt-builder.pod \
 	virt-builder-repository.pod \
-	virt-index-validate.pod \
-	yajl_tests.ml
+	virt-index-validate.pod

 SOURCES_MLI = \
 	builder.mli \
@@ -67,11 +66,9 @@ SOURCES_MLI = \
 	sigchecker.mli \
 	simplestreams_parser.mli \
 	sources.mli \
-	utils.mli \
-	yajl.mli
+	utils.mli

 SOURCES_ML = \
-	yajl.ml \
 	utils.ml \
 	osinfo_config.ml \
 	osinfo.ml \
@@ -97,11 +94,9 @@ SOURCES_C = \
 	index-parse.c \
 	index-parser-c.c \
 	pxzcat-c.c \
-	setlocale-c.c \
-	yajl-c.c
+	setlocale-c.c

 REPOSITORY_SOURCES_ML = \
-	yajl.ml \
 	utils.ml \
 	index.ml \
 	cache.ml \
@@ -122,15 +117,13 @@ REPOSITORY_SOURCES_MLI = \
 	index_parser.mli \
 	ini_reader.mli \
 	sigchecker.mli \
-	sources.mli \
-	yajl.mli
+	sources.mli

 REPOSITORY_SOURCES_C = \
 	index-scan.c \
 	index-struct.c \
 	index-parse.c \
-	index-parser-c.c \
-	yajl-c.c
+	index-parser-c.c

 man_MANS  noinst_DATA @@ -156,8 +149,7 @@ virt_builder_CFLAGS = \
 	-Wno-unused-macros \
 	$(LIBLZMA_CFLAGS) \
 	$(LIBTINFO_CFLAGS) \
-	$(LIBXML2_CFLAGS) \
-	$(JANSSON_CFLAGS)
+	$(LIBXML2_CFLAGS)

 BOBJECTS = $(SOURCES_ML:.ml=.cmo)
 XOBJECTS = $(BOBJECTS:.cmo=.cmx)
@@ -175,8 +167,7 @@ virt_builder_repository_CFLAGS = \
 	$(WARN_CFLAGS) $(WERROR_CFLAGS) \
 	-Wno-unused-macros \
 	$(LIBTINFO_CFLAGS) \
-	$(LIBXML2_CFLAGS) \
-	$(YAJL_CFLAGS)
+	$(LIBXML2_CFLAGS)
 REPOSITORY_BOBJECTS = $(REPOSITORY_SOURCES_ML:.ml=.cmo)
 REPOSITORY_XOBJECTS = $(REPOSITORY_BOBJECTS:.cmo=.cmx)

@@ -323,22 +314,13 @@ fedora.qcow2.xz: fedora.qcow2
 	xz --best -c $< > $@-t
 	mv $@-t $@

-yajl_tests_SOURCES = yajl-c.c
-yajl_tests_CPPFLAGS = $(virt_builder_CPPFLAGS)
-yajl_tests_BOBJECTS = \
-	yajl.cmo \
-	yajl_tests.cmo
-yajl_tests_XOBJECTS = $(yajl_tests_BOBJECTS:.cmo=.cmx)
-
 index_parser_tests_SOURCES = \
 	index-scan.c \
 	index-struct.c \
 	index-parser-c.c \
-	index-parse.c \
-	yajl-c.c
+	index-parse.c
 index_parser_tests_CPPFLAGS = $(virt_builder_CPPFLAGS)
 index_parser_tests_BOBJECTS = \
-	yajl.cmo \
 	utils.cmo \
 	index.cmo \
 	cache.cmo \
@@ -351,32 +333,13 @@ index_parser_tests_XOBJECTS =
$(index_parser_tests_BOBJECTS:.cmo=.cmx)

 # Can't call the following as <test>_OBJECTS because automake gets
confused.
 if HAVE_OCAMLOPT
-yajl_tests_THEOBJECTS = $(yajl_tests_XOBJECTS)
-yajl_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
-
 index_parser_tests_THEOBJECTS = $(index_parser_tests_XOBJECTS)
 index_parser_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
 else
-yajl_tests_THEOBJECTS = $(yajl_tests_BOBJECTS)
-yajl_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
-
 index_parser_tests_THEOBJECTS = $(index_parser_tests_BOBJECTS)
 index_parser_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
 endif

-yajl_tests_DEPENDENCIES = \
-	$(yajl_tests_THEOBJECTS) \
-	../common/mlpcre/mlpcre.$(MLARCHIVE) \
-	../common/mlstdutils/mlstdutils.$(MLARCHIVE) \
-	../common/mlutils/mlcutils.$(MLARCHIVE) \
-	../common/mltools/mltools.$(MLARCHIVE) \
-	../customize/customize.$(MLARCHIVE) \
-	$(top_srcdir)/ocaml-link.sh
-yajl_tests_LINK = \
-	$(top_srcdir)/ocaml-link.sh -cclib '$(OCAMLCLIBS)' -- \
-	  $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) $(OCAMLPACKAGES) $(OCAMLPACKAGES_TESTS)
$(OCAMLLINKFLAGS) \
-	  $(yajl_tests_THEOBJECTS) -o $@
-
 index_parser_tests_DEPENDENCIES = \
 	$(index_parser_tests_THEOBJECTS) \
 	../common/mltools/mltools.$(MLARCHIVE) \
@@ -400,8 +363,8 @@ if ENABLE_APPLIANCE
 TESTS += test-virt-builder.sh
 endif ENABLE_APPLIANCE
 if HAVE_OCAML_PKG_OUNIT
-check_PROGRAMS += yajl_tests index_parser_tests
-TESTS += yajl_tests index_parser_tests
+check_PROGRAMS += index_parser_tests
+TESTS += index_parser_tests
 endif

 check-valgrind:
diff --git a/builder/index_parser.ml b/builder/index_parser.ml
index 79653a91b..59fa5097d 100644
--- a/builder/index_parser.ml
+++ b/builder/index_parser.ml
@@ -140,7 +140,7 @@ let get_index ~downloader ~sigchecker ?(template = false) {
Sources.uri; proxy }
               match detect_file_type filepath with
               | `Unknown ->
                 let infos = Utils.get_image_infos filepath in
-                Yajl.object_get_number "virtual-size" infos
+                JSON_parser.object_get_number "virtual-size" infos
               | `XZ | `GZip | `Tar | ` Zip ->
                 eprintf (f_"%s: cannot determine the virtual size of %s
due to compression")
                         prog filepath;
diff --git a/builder/repository_main.ml b/builder/repository_main.ml
index 5dc4d57cd..43f749c5a 100644
--- a/builder/repository_main.ml
+++ b/builder/repository_main.ml
@@ -22,7 +22,7 @@ open Tools_utils
 open Unix_utils
 open Getopt.OptionName
 open Utils
-open Yajl
+open JSON_parser
 open Xpath_helpers

 open Printf
diff --git a/builder/simplestreams_parser.ml b/builder/simplestreams_parser.ml
index 18f45a6fd..fa5b887ac 100644
--- a/builder/simplestreams_parser.ml
+++ b/builder/simplestreams_parser.ml
@@ -20,7 +20,7 @@ open Std_utils
 open Tools_utils
 open Common_gettext.Gettext

-open Yajl
+open JSON_parser
 open Utils

 open Printf
@@ -44,7 +44,7 @@ let get_index ~downloader ~sigchecker { Sources.uri; proxy }
| Some f -> f
       ) else
         tmpfile in
-    yajl_tree_parse (read_whole_file file) in
+    json_parser_tree_parse (read_whole_file file) in

   let downloads      let uri_index @@ -106,7 +106,7 @@ let get_index
~downloader ~sigchecker { Sources.uri; proxy }                     * the ones
related to checksums, explicitly filter
                    * the supported checksums.
                    *)
-                  | ("sha256"|"sha512" as t, Yajl_string c)
->
+                  | ("sha256"|"sha512" as t,
JSON_parser_string c) ->
                     Some (Checksums.of_string t c)
                   | _ -> None
                 ) disk_item in
diff --git a/builder/utils.ml b/builder/utils.ml
index 1446561b0..538a43be9 100644
--- a/builder/utils.ml
+++ b/builder/utils.ml
@@ -43,4 +43,4 @@ let get_image_infos filepath    let qemuimg_cmd =
"qemu-img info --output json " ^ quote filepath in
   let lines = external_command qemuimg_cmd in
   let line = String.concat "\n" lines in
-  Yajl.yajl_tree_parse line
+  JSON_parser.json_parser_tree_parse line
diff --git a/builder/utils.mli b/builder/utils.mli
index 4249fd956..5dde43a01 100644
--- a/builder/utils.mli
+++ b/builder/utils.mli
@@ -29,9 +29,9 @@ and revision  val string_of_revision : revision -> string
 (** Convert a {!revision} into a string. *)

-val get_image_infos : string -> Yajl.yajl_val
+val get_image_infos : string -> JSON_parser.json_parser_val
 (** [get_image_infos path] Run qemu-img info on the image pointed at
-    path as YAJL tree. *)
+    path as JSON tree. *)

 val increment_revision : revision -> revision
 (** Add one to the revision number *)
diff --git a/builder/yajl-c.c b/common/mltools/JSON_parser-c.c
similarity index 94%
rename from builder/yajl-c.c
rename to common/mltools/JSON_parser-c.c
index e53755f55..32432dc5b 100644
--- a/builder/yajl-c.c
+++ b/common/mltools/JSON_parser-c.c
@@ -1,5 +1,5 @@
-/* virt-builder
- * Copyright (C) 2015 Red Hat Inc.
+/* JSON parser
+ * Copyright (C) 2015-2018 Red Hat Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@

 #define Val_none (Val_int (0))

-value virt_builder_yajl_tree_parse (value stringv);
+value virt_builder_json_parser_tree_parse (value stringv);

 static value
 convert_json_t (json_t *val, int level)
@@ -95,7 +95,7 @@ convert_json_t (json_t *val, int level)
 }

 value
-virt_builder_yajl_tree_parse (value stringv)
+virt_builder_json_parser_tree_parse (value stringv)
 {
   CAMLparam1 (stringv);
   CAMLlocal1 (rv);
diff --git a/builder/yajl.ml b/common/mltools/JSON_parser.ml
similarity index 75%
rename from builder/yajl.ml
rename to common/mltools/JSON_parser.ml
index d95f3932a..a82127454 100644
--- a/builder/yajl.ml
+++ b/common/mltools/JSON_parser.ml
@@ -1,5 +1,5 @@
-(* virt-builder
- * Copyright (C) 2015 Red Hat Inc.
+(* JSON parser
+ * Copyright (C) 2015-2018 Red Hat Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,19 +20,19 @@ open Std_utils
 open Tools_utils
 open Common_gettext.Gettext

-type yajl_val -| Yajl_null
-| Yajl_string of string
-| Yajl_number of int64
-| Yajl_double of float
-| Yajl_object of (string * yajl_val) array
-| Yajl_array of yajl_val array
-| Yajl_bool of bool
+type json_parser_val +| JSON_parser_null
+| JSON_parser_string of string
+| JSON_parser_number of int64
+| JSON_parser_double of float
+| JSON_parser_object of (string * json_parser_val) array
+| JSON_parser_array of json_parser_val array
+| JSON_parser_bool of bool

-external yajl_tree_parse : string -> yajl_val =
"virt_builder_yajl_tree_parse"
+external json_parser_tree_parse : string -> json_parser_val =
"virt_builder_json_parser_tree_parse"

 let object_find_optional key = function
-  | Yajl_object o ->
+  | JSON_parser_object o ->
     (match List.filter (fun (k, _) -> k = key) (Array.to_list o) with
     | [(k, v)] -> Some v
     | [] -> None
@@ -46,27 +46,27 @@ let object_find key yv
 let object_get_string key yv    match object_find key yv with
-  | Yajl_string s -> s
+  | JSON_parser_string s -> s
   | _ -> error (f_"the value for the key ‘%s’ is not a string")
key

 let object_find_object key yv    match object_find key yv with
-  | Yajl_object _ as o -> o
+  | JSON_parser_object _ as o -> o
   | _ -> error (f_"the value for the key ‘%s’ is not an object")
key

 let object_find_objects fn = function
-  | Yajl_object o -> List.filter_map fn (Array.to_list o)
+  | JSON_parser_object o -> List.filter_map fn (Array.to_list o)
   | _ -> error (f_"the value is not an object")

 let object_get_object key yv    match object_find_object key yv with
-  | Yajl_object o -> o
+  | JSON_parser_object o -> o
   | _ -> assert false (* object_find_object already errors out. *)

 let object_get_number key yv    match object_find key yv with
-  | Yajl_number n -> n
-  | Yajl_double d -> Int64.of_float d
+  | JSON_parser_number n -> n
+  | JSON_parser_double d -> Int64.of_float d
   | _ -> error (f_"the value for the key ‘%s’ is not an integer")
key

 let objects_get_string key yvs @@ -74,7 +74,7 @@ let objects_get_string key yvs
| [] -> None
     | x :: xs ->
       (match object_find_optional key x with
-      | Some (Yajl_string s) -> Some s
+      | Some (JSON_parser_string s) -> Some s
       | Some _ -> error (f_"the value for key ‘%s’ is not a string as
expected") key
       | None -> loop xs
       )
diff --git a/builder/yajl.mli b/common/mltools/JSON_parser.mli
similarity index 60%
rename from builder/yajl.mli
rename to common/mltools/JSON_parser.mli
index ca0eb92f4..f505953f2 100644
--- a/builder/yajl.mli
+++ b/common/mltools/JSON_parser.mli
@@ -1,5 +1,5 @@
-(* virt-builder
- * Copyright (C) 2015 Red Hat Inc.
+(* JSON parser
+ * Copyright (C) 2015-2018 Red Hat Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,43 +16,43 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *)

-type yajl_val -| Yajl_null
-| Yajl_string of string
-| Yajl_number of int64
-| Yajl_double of float
-| Yajl_object of (string * yajl_val) array
-| Yajl_array of yajl_val array
-| Yajl_bool of bool
+type json_parser_val +| JSON_parser_null
+| JSON_parser_string of string
+| JSON_parser_number of int64
+| JSON_parser_double of float
+| JSON_parser_object of (string * json_parser_val) array
+| JSON_parser_array of json_parser_val array
+| JSON_parser_bool of bool

-val yajl_tree_parse : string -> yajl_val
+val json_parser_tree_parse : string -> json_parser_val
 (** Parse the JSON string. *)

-val object_get_string : string -> yajl_val -> string
+val object_get_string : string -> json_parser_val -> string
 (** [object_get_string key yv] gets the value of the [key] field as a string
     in the [yv] structure *)

-val object_find_object : string -> yajl_val -> yajl_val
-(** [object_get_object key yv] gets the value of the [key] field as a yajl
+val object_find_object : string -> json_parser_val -> json_parser_val
+(** [object_get_object key yv] gets the value of the [key] field as a JSON
     value in the [yv] structure.

     Mind the returned type is different from [object_get_object] *)

-val object_get_object : string -> yajl_val -> (string * yajl_val) array
-(** [object_get_object key yv] gets the value of the [key] field as a Yajl
+val object_get_object : string -> json_parser_val -> (string *
json_parser_val) array
+(** [object_get_object key yv] gets the value of the [key] field as a JSON
     object in the [yv] structure *)

-val object_get_number : string -> yajl_val -> int64
+val object_get_number : string -> json_parser_val -> int64
 (** [object_get_number key yv] gets the value of the [key] field as an
     integer in the [yv] structure *)

-val objects_get_string : string -> yajl_val list -> string
+val objects_get_string : string -> json_parser_val list -> string
 (** [objects_get_string key yvs] gets the value of the [key] field as a string
-    in an [yvs] list of yajl_val structure.
+    in an [yvs] list of json_parser_val structure.

     The key may not be found at all in the list, in which case an error
     is raised *)

-val object_find_objects : ((string * yajl_val) -> 'a option) ->
yajl_val -> 'a list
-(** [object_find_objects fn obj] returns all the Yajl objects matching the [fn]
+val object_find_objects : ((string * json_parser_val) -> 'a option)
-> json_parser_val -> 'a list
+(** [object_find_objects fn obj] returns all the JSON objects matching the [fn]
     function in [obj] list. *)
diff --git a/builder/yajl_tests.ml b/common/mltools/JSON_parser_tests.ml
similarity index 73%
rename from builder/yajl_tests.ml
rename to common/mltools/JSON_parser_tests.ml
index f5a44f2fa..42045122d 100644
--- a/builder/yajl_tests.ml
+++ b/common/mltools/JSON_parser_tests.ml
@@ -16,10 +16,10 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *)

-(* This file tests the Yajl module. *)
+(* This file tests the JSON_parser module. *)

 open OUnit2
-open Yajl
+open JSON_parser

 (* Utils. *)
 let assert_equal_string = assert_equal ~printer:(fun x -> x)
@@ -27,16 +27,16 @@ let assert_equal_int = assert_equal ~printer:(fun x ->
string_of_int x)
 let assert_equal_int64 = assert_equal ~printer:(fun x -> Int64.to_string x)
 let assert_equal_bool = assert_equal ~printer:(fun x -> string_of_bool x)

-let string_of_yajl_val_type = function
-  | Yajl_null -> "null"
-  | Yajl_string _ -> "string"
-  | Yajl_number _ -> "number"
-  | Yajl_double _ -> "float"
-  | Yajl_object _ -> "object"
-  | Yajl_array _ -> "array"
-  | Yajl_bool _ -> "bool"
+let string_of_json_parser_val_type = function
+  | JSON_parser_null -> "null"
+  | JSON_parser_string _ -> "string"
+  | JSON_parser_number _ -> "number"
+  | JSON_parser_double _ -> "float"
+  | JSON_parser_object _ -> "object"
+  | JSON_parser_array _ -> "array"
+  | JSON_parser_bool _ -> "bool"
 let type_mismatch_string exp value -  Printf.sprintf "value is not %s but
%s" exp (string_of_yajl_val_type value)
+  Printf.sprintf "value is not %s but %s" exp
(string_of_json_parser_val_type value)

 let assert_raises_invalid_argument str    (* Replace the Invalid_argument
string with a fixed one, just to check
@@ -44,37 +44,37 @@ let assert_raises_invalid_argument str     *)
   let mock = "parse_error" in
   let wrapped_tree_parse str -    try yajl_tree_parse str
+    try json_parser_tree_parse str
     with Invalid_argument _ -> raise (Invalid_argument mock) in
   assert_raises (Invalid_argument mock) (fun () -> wrapped_tree_parse str)
 let assert_raises_nested str    let err = "too many levels of object/array
nesting" in
-  assert_raises (Invalid_argument err) (fun () -> yajl_tree_parse str)
+  assert_raises (Invalid_argument err) (fun () -> json_parser_tree_parse
str)

 let assert_is_object value    assert_bool
     (type_mismatch_string "object" value)
-    (match value with | Yajl_object _ -> true | _ -> false)
+    (match value with | JSON_parser_object _ -> true | _ -> false)
 let assert_is_string exp = function
-  | Yajl_string s -> assert_equal_string exp s
+  | JSON_parser_string s -> assert_equal_string exp s
   | _ as v -> assert_failure (type_mismatch_string "string" v)
 let assert_is_number exp = function
-  | Yajl_number n -> assert_equal_int64 exp n
-  | Yajl_double d -> assert_equal_int64 exp (Int64.of_float d)
+  | JSON_parser_number n -> assert_equal_int64 exp n
+  | JSON_parser_double d -> assert_equal_int64 exp (Int64.of_float d)
   | _ as v -> assert_failure (type_mismatch_string "number/double"
v)
 let assert_is_array value    assert_bool
     (type_mismatch_string "array" value)
-    (match value with | Yajl_array _ -> true | _ -> false)
+    (match value with | JSON_parser_array _ -> true | _ -> false)
 let assert_is_bool exp = function
-  | Yajl_bool b -> assert_equal_bool exp b
+  | JSON_parser_bool b -> assert_equal_bool exp b
   | _ as v -> assert_failure (type_mismatch_string "bool" v)

 let get_object_list = function
-  | Yajl_object x -> x
+  | JSON_parser_object x -> x
   | _ as v -> assert_failure (type_mismatch_string "object" v)
 let get_array = function
-  | Yajl_array x -> x
+  | JSON_parser_array x -> x
   | _ as v -> assert_failure (type_mismatch_string "array" v)


@@ -90,29 +90,29 @@ let test_tree_parse_invalid ctx    assert_raises_nested str

 let test_tree_parse_basic ctx -  let value = yajl_tree_parse "{}" in
+  let value = json_parser_tree_parse "{}" in
   assert_is_object value;

-  let value = yajl_tree_parse "\"foo\"" in
+  let value = json_parser_tree_parse "\"foo\"" in
   assert_is_string "foo" value;

-  let value = yajl_tree_parse "[]" in
+  let value = json_parser_tree_parse "[]" in
   assert_is_array value

 let test_tree_parse_inspect ctx -  let value = yajl_tree_parse
"{\"foo\":5}" in
+  let value = json_parser_tree_parse "{\"foo\":5}" in
   let l = get_object_list value in
   assert_equal_int 1 (Array.length l);
   assert_equal_string "foo" (fst (l.(0)));
   assert_is_number 5_L (snd (l.(0)));

-  let value = yajl_tree_parse "[\"foo\", true]" in
+  let value = json_parser_tree_parse "[\"foo\", true]" in
   let a = get_array value in
   assert_equal_int 2 (Array.length a);
   assert_is_string "foo" (a.(0));
   assert_is_bool true (a.(1));

-  let value = yajl_tree_parse "{\"foo\":[false, {}, 10],
\"second\":2}" in
+  let value = json_parser_tree_parse "{\"foo\":[false, {}, 10],
\"second\":2}" in
   let l = get_object_list value in
   assert_equal_int 2 (Array.length l);
   assert_equal_string "foo" (fst (l.(0)));
@@ -126,7 +126,7 @@ let test_tree_parse_inspect ctx
 (* Suites declaration. *)
 let suite -  "builder Yajl" >:::
+  "mltools JSON_parser" >:::
     [
       "tree_parse.invalid" >:: test_tree_parse_invalid;
       "tree_parse.basic" >:: test_tree_parse_basic;
diff --git a/common/mltools/Makefile.am b/common/mltools/Makefile.am
index 66b18f5de..ac5f53651 100644
--- a/common/mltools/Makefile.am
+++ b/common/mltools/Makefile.am
@@ -23,6 +23,7 @@ EXTRA_DIST = \
 	$(SOURCES_C) \
 	getopt_tests.ml \
 	JSON_tests.ml \
+	JSON_parser_tests.ml \
 	test-getopt.sh \
 	tools_utils_tests.ml

@@ -31,6 +32,7 @@ SOURCES_MLI = \
 	curl.mli \
 	getopt.mli \
 	JSON.mli \
+	JSON_parser.mli \
 	planner.mli \
 	regedit.mli \
 	registry.mli \
@@ -47,6 +49,7 @@ SOURCES_ML = \
 	registry.ml \
 	regedit.ml \
 	JSON.ml \
+	JSON_parser.ml \
 	curl.ml \
 	checksums.ml \
 	xpath_helpers.ml \
@@ -57,6 +60,7 @@ SOURCES_C = \
 	../options/keys.c \
 	../options/uri.c \
 	getopt-c.c \
+	JSON_parser-c.c \
 	tools_utils-c.c \
 	uri-c.c

@@ -94,6 +98,7 @@ libmltools_a_CPPFLAGS = \
 libmltools_a_CFLAGS = \
 	$(WARN_CFLAGS) $(WERROR_CFLAGS) \
 	$(LIBVIRT_CFLAGS) $(LIBXML2_CFLAGS) \
+	$(JANSSON_CFLAGS) \
 	-fPIC

 BOBJECTS = $(SOURCES_ML:.ml=.cmo)
@@ -128,6 +133,7 @@ OCAMLCLIBS = \
 	$(LIBCRYPT_LIBS) \
 	$(LIBVIRT_LIBS) \
 	$(LIBXML2_LIBS) \
+	$(JANSSON_LIBS) \
 	$(LIBINTL) \
 	-lgnu

@@ -169,6 +175,16 @@ JSON_tests_SOURCES = dummy.c
 JSON_tests_BOBJECTS = JSON_tests.cmo
 JSON_tests_XOBJECTS = $(JSON_tests_BOBJECTS:.cmo=.cmx)

+JSON_parser_tests_SOURCES = dummy.c
+JSON_parser_tests_CPPFLAGS = \
+	-I . \
+	-I$(top_builddir) \
+	-I$(shell $(OCAMLC) -where) \
+	-I$(top_srcdir)/lib
+JSON_parser_tests_BOBJECTS = \
+	JSON_parser_tests.cmo
+JSON_parser_tests_XOBJECTS = $(JSON_parser_tests_BOBJECTS:.cmo=.cmx)
+
 # Can't call the following as <test>_OBJECTS because automake gets
confused.
 if !HAVE_OCAMLOPT
 tools_utils_tests_THEOBJECTS = $(tools_utils_tests_BOBJECTS)
@@ -179,6 +195,9 @@ getopt_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)

 JSON_tests_THEOBJECTS = $(JSON_tests_BOBJECTS)
 JSON_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
+
+JSON_parser_tests_THEOBJECTS = $(JSON_parser_tests_BOBJECTS)
+JSON_parser_tests.cmo: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
 else
 tools_utils_tests_THEOBJECTS = $(tools_utils_tests_XOBJECTS)
 tools_utils_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
@@ -188,6 +207,9 @@ getopt_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)

 JSON_tests_THEOBJECTS = $(JSON_tests_XOBJECTS)
 JSON_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
+
+JSON_parser_tests_THEOBJECTS = $(JSON_parser_tests_XOBJECTS)
+JSON_parser_tests.cmx: OCAMLPACKAGES += $(OCAMLPACKAGES_TESTS)
 endif

 OCAMLLINKFLAGS = \
@@ -237,6 +259,19 @@ JSON_tests_LINK = \
 	  $(OCAMLPACKAGES) $(OCAMLPACKAGES_TESTS) \
 	  $(JSON_tests_THEOBJECTS) -o $@

+JSON_parser_tests_DEPENDENCIES = \
+	$(JSON_parser_tests_THEOBJECTS) \
+	../mlstdutils/mlstdutils.$(MLARCHIVE) \
+	../mlgettext/mlgettext.$(MLARCHIVE) \
+	../mlpcre/mlpcre.$(MLARCHIVE) \
+	$(MLTOOLS_CMA) \
+	$(top_srcdir)/ocaml-link.sh
+JSON_parser_tests_LINK = \
+	$(top_srcdir)/ocaml-link.sh -cclib '$(OCAMLCLIBS)' -- \
+	  $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) $(OCAMLLINKFLAGS) \
+	  $(OCAMLPACKAGES) $(OCAMLPACKAGES_TESTS) \
+	  $(JSON_parser_tests_THEOBJECTS) -o $@
+
 TESTS_ENVIRONMENT = $(top_builddir)/run --test

 TESTS = \
@@ -245,8 +280,8 @@ check_PROGRAMS = \
 	getopt_tests

 if HAVE_OCAML_PKG_OUNIT
-check_PROGRAMS += JSON_tests tools_utils_tests
-TESTS += JSON_tests tools_utils_tests
+check_PROGRAMS += JSON_tests JSON_parser_tests tools_utils_tests
+TESTS += JSON_tests JSON_parser_tests tools_utils_tests
 endif

 check-valgrind:
diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES
index f0d1f6c9d..b1db59cf5 100644
--- a/docs/C_SOURCE_FILES
+++ b/docs/C_SOURCE_FILES
@@ -5,7 +5,6 @@ builder/index-struct.h
 builder/index-validate.c
 builder/pxzcat-c.c
 builder/setlocale-c.c
-builder/yajl-c.c
 cat/cat.c
 cat/filesystems.c
 cat/log.c
@@ -21,6 +20,7 @@ common/mlpcre/dummy.c
 common/mlpcre/pcre-c.c
 common/mlprogress/progress-c.c
 common/mlstdutils/dummy.c
+common/mltools/JSON_parser-c.c
 common/mltools/dummy.c
 common/mltools/getopt-c.c
 common/mltools/tools_utils-c.c
@@ -62,6 +62,8 @@ common/utils/cleanups.h
 common/utils/gnulib-cleanups.c
 common/utils/guestfs-utils.h
 common/utils/libxml2-cleanups.c
+common/utils/libxml2-utils.c
+common/utils/libxml2-utils.h
 common/utils/utils.c
 common/visit/visit.c
 common/visit/visit.h
diff --git a/po/POTFILES b/po/POTFILES
index 55d7e6894..4e53b694f 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -6,7 +6,6 @@ builder/index-struct.c
 builder/index-validate.c
 builder/pxzcat-c.c
 builder/setlocale-c.c
-builder/yajl-c.c
 cat/cat.c
 cat/filesystems.c
 cat/log.c
@@ -22,6 +21,7 @@ common/mlpcre/dummy.c
 common/mlpcre/pcre-c.c
 common/mlprogress/progress-c.c
 common/mlstdutils/dummy.c
+common/mltools/JSON_parser-c.c
 common/mltools/dummy.c
 common/mltools/getopt-c.c
 common/mltools/tools_utils-c.c
@@ -51,6 +51,7 @@ common/structs/structs-print.c
 common/utils/cleanups.c
 common/utils/gnulib-cleanups.c
 common/utils/libxml2-cleanups.c
+common/utils/libxml2-utils.c
 common/utils/utils.c
 common/visit/visit.c
 common/windows/windows.c
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index b18ff7410..de07e37d4 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -18,8 +18,6 @@ builder/sigchecker.ml
 builder/simplestreams_parser.ml
 builder/sources.ml
 builder/utils.ml
-builder/yajl.ml
-builder/yajl_tests.ml
 common/mlaugeas/augeas.ml
 common/mlgettext/common_gettext.ml
 common/mlpcre/PCRE.ml
@@ -31,6 +29,8 @@ common/mlstdutils/std_utils_tests.ml
 common/mlstdutils/stringMap.ml
 common/mlstdutils/stringSet.ml
 common/mltools/JSON.ml
+common/mltools/JSON_parser.ml
+common/mltools/JSON_parser_tests.ml
 common/mltools/JSON_tests.ml
 common/mltools/URI.ml
 common/mltools/checksums.ml
--
2.18.0