diff --git a/README b/README index 4a0f36f..595c209 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ libujson - A Json library for C++ developers. Utility applications for handling JSON documents: ujson-verify - Verify the syntax of one or more JSON documents. -ujson-get - Get a specific value from a JSON document. +ujson-get - Get a specific value from a JSON document using a JSON pointer. JSON pointers are described in RFC 6901. ujson-cmp - Check if two JSON documents are equal. ujson-print - Print a JSON document to standard output in a few different ways. -ujson-merge - Merge two or more JSON documents. +ujson-patch - Patch JSON documents. JSON patches are described in RFC 6902. diff --git a/utils/Makefile.am b/utils/Makefile.am index ad16c8b..e6c59a8 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -38,9 +38,6 @@ ujson_cmp_SOURCES = ujson-cmp.cpp bin_PROGRAMS += ujson-get ujson_get_SOURCES = ujson-get.cpp -bin_PROGRAMS += ujson-merge -ujson_merge_SOURCES = ujson-merge.cpp - bin_PROGRAMS += ujson-patch ujson_patch_SOURCES = ujson-patch.cpp @@ -49,7 +46,6 @@ dist_man1_MANS += ujson-verify.man dist_man1_MANS += ujson-print.man dist_man1_MANS += ujson-cmp.man dist_man1_MANS += ujson-get.man -dist_man1_MANS += ujson-merge.man -#dist_man1_MANS += ujson-patch.man +dist_man1_MANS += ujson-patch.man endif diff --git a/utils/ujson-cmp.man b/utils/ujson-cmp.man index 5a72309..1d39bc5 100644 --- a/utils/ujson-cmp.man +++ b/utils/ujson-cmp.man @@ -73,7 +73,7 @@ Example of a JSON document that is allowed in relaxed mode: .EE .SH SEE ALSO -ujson-verify(1) ujson-print(1) ujson-get(1) ujson-merge(1) +ujson-print(1) ujson-get(1) ujson-verify(1) ujson-patch(1) .SH AUTHOR diff --git a/utils/ujson-get.man b/utils/ujson-get.man index dbbc083..09ea061 100644 --- a/utils/ujson-get.man +++ b/utils/ujson-get.man @@ -36,7 +36,7 @@ A JSON Pointer as described in RFC 6901. A pointer specifies a specific value in a JSON document. Is is a string containing zero or more reference tokens separated by '/'. If a '/' is part of a token it is encoded as '~1'. And if a '~' is parf of a token it is encoded as '~0'. .SH SEE ALSO -ujson-verify(1) ujson-cmp(1) ujson-print(1) ujson-merge(1) +ujson-print(1) ujson-verify(1) ujson-cmp(1) ujson-patch(1) .SH AUTHOR diff --git a/utils/ujson-merge.cpp b/utils/ujson-merge.cpp deleted file mode 100644 index cd2dddf..0000000 --- a/utils/ujson-merge.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2021 Dan Arrhenius - * - * This file is part of ujson. - * - * ujson is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published - * by the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace std; - -static constexpr const char* prog_name = "ujson-merge"; - -struct appargs_t { - bool compact; - bool relaxed; - bool type_check; - string master_filename; - vector slave_filenames; - string master_pointer; - string slave_pointer; - - appargs_t () { - compact = false; - relaxed = false; - type_check = false; - } -}; - - -/* - * Merge rules: - * - * Merge a slave instance into a master instance. - * - * A number will be replaced by the slave value. - * A null will be replaced by the slave value. - * A boolean will be replaced by the slave value. - * A string will be replaced by the slave value. - * An array will be replaced by the slave value. - * An object: - * - If a member name in the slave object exitst in the master object, - * the value of that member will be merged according to theese rules. - * - If a member name in the slave object doesn't exitst in the master object, - * the slave member will be added to the master object. - */ - - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -static void print_usage_and_exit (std::ostream& out, int exit_code) -{ - out << endl; - out << "Merge one or more JSON document into a target document.." << endl; - out << endl; - out << "Usage: " << prog_name << " [OPTIONS] [MASTER_FILE] [SLAVE_FILE...]" << endl; - out << endl; - out << "MASTER_FILE: This JSON document serves as the base for the merge." <(ifs)), istreambuf_iterator()); - auto slave_root = j.parse_string (slave_document, !opt.relaxed); - if (!slave_root.valid()) { - if (slave_filename.empty()) - cerr << "Parse error on input: " << j.error() << endl; - else - cerr << "Parse error, " << slave_filename << ": " << j.error() << endl; - return 1; - } - - auto& slave = ujson::find_jvalue (slave_root, opt.slave_pointer); - if (!slave.valid()) { - if (slave_filename.empty()) - cerr << "Invalid pointer in input document: " << opt.slave_pointer << endl; - else - cerr << "Invalid pointer in document " - << slave_filename << ": " << opt.slave_pointer << endl; - return 1; - } - return merge_instance (master, slave, opt.type_check); -} - - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -int main (int argc, char* argv[]) -{ - appargs_t opt; - parse_args (argc, argv, opt); - - // Parse the master file - // - ujson::Json j; - auto master_root = j.parse_file (opt.master_filename, !opt.relaxed); - if (!master_root.valid()) { - cerr << "Parse error, " << opt.master_filename << ": " << j.error() << endl; - exit (1); - } - - // Get the pointer in the master instance - // - auto& master = ujson::find_jvalue (master_root, opt.master_pointer); - if (!master.valid()) { - cerr << "Invalid pointer in document " - << opt.master_filename << ": " << opt.master_pointer << endl; - exit (1); - } - - // Merge slave file(s) - // - int result = 0; - if (opt.slave_filenames.empty()) { - // Merge from standard input - result = parse_and_merge (opt, master, cin); - }else{ - // Merge from file(s) - for (auto& filename : opt.slave_filenames) { - ifstream ifs (filename); - result = parse_and_merge (opt, master, ifs, filename); - ifs.close (); - if (result) - break; - } - } - - if (!result) - cout << master_root.describe(!opt.compact, !opt.relaxed) << endl; - - return result; -} diff --git a/utils/ujson-merge.man b/utils/ujson-merge.man deleted file mode 100644 index 60a24a3..0000000 --- a/utils/ujson-merge.man +++ /dev/null @@ -1,132 +0,0 @@ -.\" Manpage for ujson-verify -.\" Contact dan@ultramarin.se to correct errors or types. -.TH ujson-merge 1 "" "" "User Commands" - - -.SH NAME -ujson-merge \- Merge multiple JSON documents into one. - - -.SH SYNOPSIS -.B ujson-merge -[OPTIONS] MASTER_FILE [SLAVE_FILE...] - - -.SH DESCRIPTION -ujson-merge joins one or more JSON documents into one master JSON document and prints the result to standard output. -If only a master document is present on the command line, it will be merged from standard input. -.PP -When merging JSON instance B into JSON instance A, the following rules apply: -.nf -- If A is a number, it will be replaced by the instance B. -- If A is null, it will be replaced by the instance B. -- If A is a boolean, it will be replaced by the instance B. -- If A is a string, it will be replaced by the instance B. -- If A is an array, it will be replaced by the instance B. -- If A is an object and B is not an object, A will be replaced by instance B. -- If both A and B are objects: - - If a member name in B exitst in A, then B will be merged into A using theese rules. - - If a member name in B doesn't exitst A, that member will be added to A, - - -.SH OPTIONS -.TP -.B -c, --compact -Print the resulting JSON document without whitespaces. -.TP -.B -r, --relaxed -Parse JSON documents in relaxed mode. - -.TP -.B -d, --dst-pointer=POINTER -Merge into this specific place in the master document. - -.TP -.B -s, --src-pointer=POINTER -Merge from this specific place in the slave document(s). - -.TP -.B -m, --match-type -All values that are merged must be of the same type. Note that the content in two arrays may be of different types. - -.TP -.B -h, --help -Print help and exit. - - -.SH POINTER -A JSON Pointer as described in RFC 6901. -A pointer specifies a specific value in a JSON document. Is is a string containing zero or more reference tokens separated by '/'. If a '/' is part of a token it is encodec as '~1'. And if a '~' is parf of a token it is encoded as '~0'. - - -.SH EXAMPLES -Given the following JSON documents: -.PP -Document A.json: -.EX -{ - "name": "master", - "value": 0, - "list": [1, 2, 3], - "obj": { - "desc": null, - "place": "home" - } -} -.EE -.PP -Document B.json: -.EX -{ - "name": "replacement", - "obj": { - "desc": "Hello World!", - "misc": [true, false] - }, - "meaning": 42 -} -.EE - -.pp -Result of runnning command "ujson-merge A.json B.json": -.EX -{ - "name": "replacement", - "value": 0, - "list": [1, 2, 3], - "obj": { - "desc": "Hello World!", - "place": "home", - "misc": [true, false] - }, - "meaning": 42 -} -.EE - -.pp -Result of runnning command "ujson-merge --match-type A.json B.json": -.EX -JSON type mismatch. Trying to assign a value of type string to an instance of type null -.EE - -.pp -Result of runnning command "ujson-merge --dst-pointer=/list --src-pointer=/obj/misc A.json B.json": -.EX -{ - "name": "master", - "value": 0, - "list": [true, false], - "obj": { - "desc": null, - "place": "home" - } -} -.EE - - -.SH SEE ALSO -ujson-verify(1) ujson-cmp(1) ujson-print(1) ujson-get(1) - - -.SH AUTHOR -Dan Arrhenius (dan@ultramarin.se) diff --git a/utils/ujson-patch.man b/utils/ujson-patch.man new file mode 100644 index 0000000..28d47f9 --- /dev/null +++ b/utils/ujson-patch.man @@ -0,0 +1,44 @@ +.\" Manpage for ujson-verify +.\" Contact dan@ultramarin.se to correct errors or types. +.TH ujson-patch 1 "" "" "User Commands" + + +.SH NAME +ujson-patch \- Apply JSON patches to a JSON document. + + +.SH SYNOPSIS +.B ujson-patch +[OPTIONS] JSON_FILE [JSON_PATCH_FILE] + + +.SH DESCRIPTION +ujson-patch applies JSON patches as described by RFC 6902 and prints the resulting JSON document to standard output. +If any patch is unsuccessful, an error for each unsuccessful patch is written to standard error and the application returns with an error code. +.PP +Patch definitions are described in RFC 6902 - JavaScript Object Notation (JSON) Patch. +.PP +JSON_FILE is a JSON document we want to apply patches on. +.PP +JSON_PATCH_FILE is a JSON document containing the patches to apply. It no patch file is given, the patch definition is read from standard input. + +.SH OPTIONS +.TP +.B -c, --compact +Print the resulting JSON document without whitespaces. +.TP +.B -r, --relaxed +Parse JSON input files in relaxed mode. +.TP +.B -q, --quiet +No errors are written to standard error. On errors, of failed patch test operations, the application exits with an error code. If the patch definition only contains patch operations of type 'test', nothing is written to standard output. If the patch definition contains operations other than 'test', the resulting JSON document is still printed to standard output. +.TP +.B -h, --help +Print help and exit. + +.SH SEE ALSO +ujson-print(1) ujson-get(1) ujson-verify(1) ujson-cmp(1) + + +.SH AUTHOR +Dan Arrhenius (dan@ultramarin.se) diff --git a/utils/ujson-print.man b/utils/ujson-print.man index e44f11a..49505c3 100644 --- a/utils/ujson-print.man +++ b/utils/ujson-print.man @@ -35,7 +35,7 @@ Print help and exit. .SH SEE ALSO -ujson-verify(1) ujson-cmp(1) ujson-get(1) ujson-merge(1) +ujson-get(1) ujson-verify(1) ujson-cmp(1) ujson-patch(1) .SH AUTHOR diff --git a/utils/ujson-verify.man b/utils/ujson-verify.man index ec9659f..f7518c3 100644 --- a/utils/ujson-verify.man +++ b/utils/ujson-verify.man @@ -77,7 +77,7 @@ Example of a JSON document that is allowed in relaxed mode: .SH SEE ALSO -ujson-cmp(1) ujson-print(1) ujson-get(1) ujson-merge(1) +ujson-print(1) ujson-get(1) ujson-cmp(1) ujson-patch(1) .SH AUTHOR