├── Images ├── Depth-First-Search.gif ├── json-graph.png ├── json-tree.png └── value.png ├── LICENSE ├── README.md ├── src ├── atwood.json ├── contact.json ├── depth.json ├── example01.json ├── json-array00.c ├── json-array01.c ├── json-array02.c ├── json-array03.c ├── json-array04.c ├── json-edit00.c ├── json-equal00.c ├── json-error00.c ├── json-file00.c ├── json-file01.c ├── json-mem00.c ├── json-mem01.c ├── json-new00.c ├── json-new01.c ├── json-parse00.c ├── json-parse01.c ├── json-parse02.c ├── json-parse03.c ├── json-parse04.c ├── json-parse05.c ├── json-parse06.c ├── json-parse07.c ├── json-parse08.c ├── json-parse10.c ├── json-parse11.c ├── json-str00.c ├── json-type00.c ├── json-version.c ├── json00.c ├── names.json ├── sample00.json └── tree.py └── tutorial ├── File.md ├── Intro.md ├── Json-c.md ├── circular01.md ├── edit.md ├── edit2.md ├── equal.md ├── index.md ├── legacy.md ├── list.md ├── memory.md ├── memory01.md ├── new.md ├── parsing2.md ├── parsing3.md ├── parsing4.md ├── parsing5.md ├── parsing6.md ├── sort.md ├── types.md └── url.txt /Images/Depth-First-Search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbtylee/tutorial-jsonc/d03d95e286fb2b91b240e2d46688bcf8fea08ce6/Images/Depth-First-Search.gif -------------------------------------------------------------------------------- /Images/json-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbtylee/tutorial-jsonc/d03d95e286fb2b91b240e2d46688bcf8fea08ce6/Images/json-graph.png -------------------------------------------------------------------------------- /Images/json-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbtylee/tutorial-jsonc/d03d95e286fb2b91b240e2d46688bcf8fea08ce6/Images/json-tree.png -------------------------------------------------------------------------------- /Images/value.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbtylee/tutorial-jsonc/d03d95e286fb2b91b240e2d46688bcf8fea08ce6/Images/value.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Attribution 4.0 International 2 | CC BY 4.0 3 | 4 | ======================================================================= 5 | 6 | Creative Commons Corporation ("Creative Commons") is not a law firm and 7 | does not provide legal services or legal advice. Distribution of 8 | Creative Commons public licenses does not create a lawyer-client or 9 | other relationship. Creative Commons makes its licenses and related 10 | information available on an "as-is" basis. Creative Commons gives no 11 | warranties regarding its licenses, any material licensed under their 12 | terms and conditions, or any related information. Creative Commons 13 | disclaims all liability for damages resulting from their use to the 14 | fullest extent possible. 15 | 16 | Using Creative Commons Public Licenses 17 | 18 | Creative Commons public licenses provide a standard set of terms and 19 | conditions that creators and other rights holders may use to share 20 | original works of authorship and other material subject to copyright 21 | and certain other rights specified in the public license below. The 22 | following considerations are for informational purposes only, are not 23 | exhaustive, and do not form part of our licenses. 24 | 25 | Considerations for licensors: Our public licenses are 26 | intended for use by those authorized to give the public 27 | permission to use material in ways otherwise restricted by 28 | copyright and certain other rights. Our licenses are 29 | irrevocable. Licensors should read and understand the terms 30 | and conditions of the license they choose before applying it. 31 | Licensors should also secure all rights necessary before 32 | applying our licenses so that the public can reuse the 33 | material as expected. Licensors should clearly mark any 34 | material not subject to the license. This includes other CC- 35 | licensed material, or material used under an exception or 36 | limitation to copyright. More considerations for licensors: 37 | wiki.creativecommons.org/Considerations_for_licensors 38 | 39 | Considerations for the public: By using one of our public 40 | licenses, a licensor grants the public permission to use the 41 | licensed material under specified terms and conditions. If 42 | the licensor's permission is not necessary for any reason--for 43 | example, because of any applicable exception or limitation to 44 | copyright--then that use is not regulated by the license. Our 45 | licenses grant only permissions under copyright and certain 46 | other rights that a licensor has authority to grant. Use of 47 | the licensed material may still be restricted for other 48 | reasons, including because others have copyright or other 49 | rights in the material. A licensor may make special requests, 50 | such as asking that all changes be marked or described. 51 | Although not required by our licenses, you are encouraged to 52 | respect those requests where reasonable. More_considerations 53 | for the public: 54 | wiki.creativecommons.org/Considerations_for_licensees 55 | 56 | ======================================================================= 57 | 58 | Creative Commons Attribution 4.0 International Public License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution 4.0 International Public License ("Public License"). To the 63 | extent this Public License may be interpreted as a contract, You are 64 | granted the Licensed Rights in consideration of Your acceptance of 65 | these terms and conditions, and the Licensor grants You such rights in 66 | consideration of benefits the Licensor receives from making the 67 | Licensed Material available under these terms and conditions. 68 | 69 | 70 | Section 1 -- Definitions. 71 | 72 | a. Adapted Material means material subject to Copyright and Similar 73 | Rights that is derived from or based upon the Licensed Material 74 | and in which the Licensed Material is translated, altered, 75 | arranged, transformed, or otherwise modified in a manner requiring 76 | permission under the Copyright and Similar Rights held by the 77 | Licensor. For purposes of this Public License, where the Licensed 78 | Material is a musical work, performance, or sound recording, 79 | Adapted Material is always produced where the Licensed Material is 80 | synched in timed relation with a moving image. 81 | 82 | b. Adapter's License means the license You apply to Your Copyright 83 | and Similar Rights in Your contributions to Adapted Material in 84 | accordance with the terms and conditions of this Public License. 85 | 86 | c. Copyright and Similar Rights means copyright and/or similar rights 87 | closely related to copyright including, without limitation, 88 | performance, broadcast, sound recording, and Sui Generis Database 89 | Rights, without regard to how the rights are labeled or 90 | categorized. For purposes of this Public License, the rights 91 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 92 | Rights. 93 | 94 | d. Effective Technological Measures means those measures that, in the 95 | absence of proper authority, may not be circumvented under laws 96 | fulfilling obligations under Article 11 of the WIPO Copyright 97 | Treaty adopted on December 20, 1996, and/or similar international 98 | agreements. 99 | 100 | e. Exceptions and Limitations means fair use, fair dealing, and/or 101 | any other exception or limitation to Copyright and Similar Rights 102 | that applies to Your use of the Licensed Material. 103 | 104 | f. Licensed Material means the artistic or literary work, database, 105 | or other material to which the Licensor applied this Public 106 | License. 107 | 108 | g. Licensed Rights means the rights granted to You subject to the 109 | terms and conditions of this Public License, which are limited to 110 | all Copyright and Similar Rights that apply to Your use of the 111 | Licensed Material and that the Licensor has authority to license. 112 | 113 | h. Licensor means the individual(s) or entity(ies) granting rights 114 | under this Public License. 115 | 116 | i. Share means to provide material to the public by any means or 117 | process that requires permission under the Licensed Rights, such 118 | as reproduction, public display, public performance, distribution, 119 | dissemination, communication, or importation, and to make material 120 | available to the public including in ways that members of the 121 | public may access the material from a place and at a time 122 | individually chosen by them. 123 | 124 | j. Sui Generis Database Rights means rights other than copyright 125 | resulting from Directive 96/9/EC of the European Parliament and of 126 | the Council of 11 March 1996 on the legal protection of databases, 127 | as amended and/or succeeded, as well as other essentially 128 | equivalent rights anywhere in the world. 129 | 130 | k. You means the individual or entity exercising the Licensed Rights 131 | under this Public License. Your has a corresponding meaning. 132 | 133 | 134 | Section 2 -- Scope. 135 | 136 | a. License grant. 137 | 138 | 1. Subject to the terms and conditions of this Public License, 139 | the Licensor hereby grants You a worldwide, royalty-free, 140 | non-sublicensable, non-exclusive, irrevocable license to 141 | exercise the Licensed Rights in the Licensed Material to: 142 | 143 | a. reproduce and Share the Licensed Material, in whole or 144 | in part; and 145 | 146 | b. produce, reproduce, and Share Adapted Material. 147 | 148 | 2. Exceptions and Limitations. For the avoidance of doubt, where 149 | Exceptions and Limitations apply to Your use, this Public 150 | License does not apply, and You do not need to comply with 151 | its terms and conditions. 152 | 153 | 3. Term. The term of this Public License is specified in Section 154 | 6(a). 155 | 156 | 4. Media and formats; technical modifications allowed. The 157 | Licensor authorizes You to exercise the Licensed Rights in 158 | all media and formats whether now known or hereafter created, 159 | and to make technical modifications necessary to do so. The 160 | Licensor waives and/or agrees not to assert any right or 161 | authority to forbid You from making technical modifications 162 | necessary to exercise the Licensed Rights, including 163 | technical modifications necessary to circumvent Effective 164 | Technological Measures. For purposes of this Public License, 165 | simply making modifications authorized by this Section 2(a) 166 | (4) never produces Adapted Material. 167 | 168 | 5. Downstream recipients. 169 | 170 | a. Offer from the Licensor -- Licensed Material. Every 171 | recipient of the Licensed Material automatically 172 | receives an offer from the Licensor to exercise the 173 | Licensed Rights under the terms and conditions of this 174 | Public License. 175 | 176 | b. No downstream restrictions. You may not offer or impose 177 | any additional or different terms or conditions on, or 178 | apply any Effective Technological Measures to, the 179 | Licensed Material if doing so restricts exercise of the 180 | Licensed Rights by any recipient of the Licensed 181 | Material. 182 | 183 | 6. No endorsement. Nothing in this Public License constitutes or 184 | may be construed as permission to assert or imply that You 185 | are, or that Your use of the Licensed Material is, connected 186 | with, or sponsored, endorsed, or granted official status by, 187 | the Licensor or others designated to receive attribution as 188 | provided in Section 3(a)(1)(A)(i). 189 | 190 | b. Other rights. 191 | 192 | 1. Moral rights, such as the right of integrity, are not 193 | licensed under this Public License, nor are publicity, 194 | privacy, and/or other similar personality rights; however, to 195 | the extent possible, the Licensor waives and/or agrees not to 196 | assert any such rights held by the Licensor to the limited 197 | extent necessary to allow You to exercise the Licensed 198 | Rights, but not otherwise. 199 | 200 | 2. Patent and trademark rights are not licensed under this 201 | Public License. 202 | 203 | 3. To the extent possible, the Licensor waives any right to 204 | collect royalties from You for the exercise of the Licensed 205 | Rights, whether directly or through a collecting society 206 | under any voluntary or waivable statutory or compulsory 207 | licensing scheme. In all other cases the Licensor expressly 208 | reserves any right to collect such royalties. 209 | 210 | 211 | Section 3 -- License Conditions. 212 | 213 | Your exercise of the Licensed Rights is expressly made subject to the 214 | following conditions. 215 | 216 | a. Attribution. 217 | 218 | 1. If You Share the Licensed Material (including in modified 219 | form), You must: 220 | 221 | a. retain the following if it is supplied by the Licensor 222 | with the Licensed Material: 223 | 224 | i. identification of the creator(s) of the Licensed 225 | Material and any others designated to receive 226 | attribution, in any reasonable manner requested by 227 | the Licensor (including by pseudonym if 228 | designated); 229 | 230 | ii. a copyright notice; 231 | 232 | iii. a notice that refers to this Public License; 233 | 234 | iv. a notice that refers to the disclaimer of 235 | warranties; 236 | 237 | v. a URI or hyperlink to the Licensed Material to the 238 | extent reasonably practicable; 239 | 240 | b. indicate if You modified the Licensed Material and 241 | retain an indication of any previous modifications; and 242 | 243 | c. indicate the Licensed Material is licensed under this 244 | Public License, and include the text of, or the URI or 245 | hyperlink to, this Public License. 246 | 247 | 2. You may satisfy the conditions in Section 3(a)(1) in any 248 | reasonable manner based on the medium, means, and context in 249 | which You Share the Licensed Material. For example, it may be 250 | reasonable to satisfy the conditions by providing a URI or 251 | hyperlink to a resource that includes the required 252 | information. 253 | 254 | 3. If requested by the Licensor, You must remove any of the 255 | information required by Section 3(a)(1)(A) to the extent 256 | reasonably practicable. 257 | 258 | 4. If You Share Adapted Material You produce, the Adapter's 259 | License You apply must not prevent recipients of the Adapted 260 | Material from complying with this Public License. 261 | 262 | 263 | Section 4 -- Sui Generis Database Rights. 264 | 265 | Where the Licensed Rights include Sui Generis Database Rights that 266 | apply to Your use of the Licensed Material: 267 | 268 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 269 | to extract, reuse, reproduce, and Share all or a substantial 270 | portion of the contents of the database; 271 | 272 | b. if You include all or a substantial portion of the database 273 | contents in a database in which You have Sui Generis Database 274 | Rights, then the database in which You have Sui Generis Database 275 | Rights (but not its individual contents) is Adapted Material; and 276 | 277 | c. You must comply with the conditions in Section 3(a) if You Share 278 | all or a substantial portion of the contents of the database. 279 | 280 | For the avoidance of doubt, this Section 4 supplements and does not 281 | replace Your obligations under this Public License where the Licensed 282 | Rights include other Copyright and Similar Rights. 283 | 284 | 285 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 286 | 287 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 288 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 289 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 290 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 291 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 292 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 293 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 294 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 295 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 296 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 297 | 298 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 299 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 300 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 301 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 302 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 303 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 304 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 305 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 306 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 307 | 308 | c. The disclaimer of warranties and limitation of liability provided 309 | above shall be interpreted in a manner that, to the extent 310 | possible, most closely approximates an absolute disclaimer and 311 | waiver of all liability. 312 | 313 | 314 | Section 6 -- Term and Termination. 315 | 316 | a. This Public License applies for the term of the Copyright and 317 | Similar Rights licensed here. However, if You fail to comply with 318 | this Public License, then Your rights under this Public License 319 | terminate automatically. 320 | 321 | b. Where Your right to use the Licensed Material has terminated under 322 | Section 6(a), it reinstates: 323 | 324 | 1. automatically as of the date the violation is cured, provided 325 | it is cured within 30 days of Your discovery of the 326 | violation; or 327 | 328 | 2. upon express reinstatement by the Licensor. 329 | 330 | For the avoidance of doubt, this Section 6(b) does not affect any 331 | right the Licensor may have to seek remedies for Your violations 332 | of this Public License. 333 | 334 | c. For the avoidance of doubt, the Licensor may also offer the 335 | Licensed Material under separate terms or conditions or stop 336 | distributing the Licensed Material at any time; however, doing so 337 | will not terminate this Public License. 338 | 339 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 340 | License. 341 | 342 | 343 | Section 7 -- Other Terms and Conditions. 344 | 345 | a. The Licensor shall not be bound by any additional or different 346 | terms or conditions communicated by You unless expressly agreed. 347 | 348 | b. Any arrangements, understandings, or agreements regarding the 349 | Licensed Material not stated herein are separate from and 350 | independent of the terms and conditions of this Public License. 351 | 352 | 353 | Section 8 -- Interpretation. 354 | 355 | a. For the avoidance of doubt, this Public License does not, and 356 | shall not be interpreted to, reduce, limit, restrict, or impose 357 | conditions on any use of the Licensed Material that could lawfully 358 | be made without permission under this Public License. 359 | 360 | b. To the extent possible, if any provision of this Public License is 361 | deemed unenforceable, it shall be automatically reformed to the 362 | minimum extent necessary to make it enforceable. If the provision 363 | cannot be reformed, it shall be severed from this Public License 364 | without affecting the enforceability of the remaining terms and 365 | conditions. 366 | 367 | c. No term or condition of this Public License will be waived and no 368 | failure to comply consented to unless expressly agreed to by the 369 | Licensor. 370 | 371 | d. Nothing in this Public License constitutes or may be interpreted 372 | as a limitation upon, or waiver of, any privileges and immunities 373 | that apply to the Licensor or You, including from the legal 374 | processes of any jurisdiction or authority. 375 | 376 | 377 | ======================================================================= 378 | 379 | Creative Commons is not a party to its public 380 | licenses. Notwithstanding, Creative Commons may elect to apply one of 381 | its public licenses to material it publishes and in those instances 382 | will be considered the “Licensor.” The text of the Creative Commons 383 | public licenses is dedicated to the public domain under the CC0 Public 384 | Domain Dedication. Except for the limited purpose of indicating that 385 | material is shared under a Creative Commons public license or as 386 | otherwise permitted by the Creative Commons policies published at 387 | creativecommons.org/policies, Creative Commons does not authorize the 388 | use of the trademark "Creative Commons" or any other trademark or logo 389 | of Creative Commons without its prior written consent including, 390 | without limitation, in connection with any unauthorized modifications 391 | to any of its public licenses or any other arrangements, 392 | understandings, or agreements concerning use of licensed material. For 393 | the avoidance of doubt, this paragraph does not form part of the 394 | public licenses. 395 | 396 | Creative Commons may be contacted at creativecommons.org. 397 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/paypalme/rbtylee) 2 | 3 | # tutorial-jsonc 4 | 5 | My tutorial on using the [json-c library](https://github.com/json-c/json-c) 6 | 7 | Please see the [Index](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/index.md) 8 | 9 | This is still a work in progress. 10 | -------------------------------------------------------------------------------- /src/atwood.json: -------------------------------------------------------------------------------- 1 | ["z10.txt", "z15.txt", "z5.txt", "z7.txt", "z100.txt", "z12.txt", "z4.txt", "z20.txt", "z11.txt", "z3.txt", "z9.txt", "z18.txt", "z19.txt", "z101.txt", "z13.txt", "z6.txt", "z102.txt", "z17.txt", "z16.txt", "z2.txt", "z1.txt", "z14.txt", "z8.txt"] 2 | -------------------------------------------------------------------------------- /src/contact.json: -------------------------------------------------------------------------------- 1 | { 2 | "firstName": "John", 3 | "lastName": "Smith", 4 | "isAlive": true, 5 | "age": 27, 6 | "address": { 7 | "streetAddress": "21 2nd Street", 8 | "city": "New York", 9 | "state": "NY", 10 | "postalCode": "10021-3100" 11 | }, 12 | "phoneNumbers": [ 13 | { 14 | "type": "home", 15 | "number": "212 555-1234" 16 | }, 17 | { 18 | "type": "office", 19 | "number": "646 555-4567" 20 | } 21 | ], 22 | "children": [], 23 | "spouse": null 24 | } 25 | -------------------------------------------------------------------------------- /src/depth.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": { 3 | "2": { 4 | "3": { 5 | "4": 4 6 | } 7 | }, 8 | "5": { 9 | "6": { 10 | "7": 7 11 | }, 12 | "8": 8 13 | }, 14 | "9": { 15 | "10": 10 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/example01.json: -------------------------------------------------------------------------------- 1 | {"items":[{"id":3201,"status":"online","location":{"latitude":-117.125,"longitude":31.125}},{"id":4678,"status":"online","location":{"latitude":-117.125,"longitude":31.125}},{"id":9823,"status":"offline","location":{"latitude":-111.625,"longitude":35.625}}]} -------------------------------------------------------------------------------- /src/json-array00.c: -------------------------------------------------------------------------------- 1 | // gcc json-array00.c -ljson-c -o json-array00 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | json_object *root = json_tokener_parse("[\"foo\", \"bar\", 32, null]"); 10 | printf("The json string:\n\n%s\n\n", json_object_to_json_string(root)); 11 | 12 | printf("The json object to string:\n\n%s\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 13 | 14 | json_object_put(root); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/json-array01.c: -------------------------------------------------------------------------------- 1 | // gcc json-array01.c -ljson-c -o json-array01 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | json_object *root = json_tokener_parse("[\"foo\", \"bar\", 32, null]"); 10 | 11 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 12 | 13 | int val = json_object_get_int(json_object_array_get_idx(root, 2)); 14 | printf("The third value of the array is: %d\n\n", val); 15 | 16 | printf("Modifying the third value and deleting the fourth.\n\n"); 17 | json_object_array_put_idx(root, 2, json_object_new_string("foobar")); 18 | json_object_array_del_idx(root, 3, 1); 19 | 20 | printf("The json representation is now:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 21 | 22 | json_object_put(root); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /src/json-array02.c: -------------------------------------------------------------------------------- 1 | // gcc json-array02.c -ljson-c -o json-array02 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | const char *str; 10 | json_object *root = json_tokener_parse("[\"foo\", \"bar\", 32, null]"); 11 | 12 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 13 | 14 | int n = json_object_array_length(root); 15 | for (int i=0;i 4 | #include 5 | #include 6 | 7 | #define NUM_KEYS 2 8 | 9 | static int 10 | sort_fn(const void *j1, const void *j2) 11 | { 12 | json_object *const *jso1, *const *jso2; 13 | const char *str1, *str2; 14 | 15 | jso1 = (json_object *const *) j1; 16 | jso2 = (json_object *const *) j2; 17 | 18 | if (!*jso1 && !*jso2) 19 | return 0; 20 | if (!*jso1) 21 | return -1; 22 | if (!*jso2) 23 | return 1; 24 | 25 | str1 = json_object_get_string(*jso1); 26 | str2 = json_object_get_string(*jso2); 27 | 28 | return strcmp(str1, str2); 29 | } 30 | 31 | int 32 | main(void) 33 | { 34 | json_object *str, *temp; 35 | char *keys[NUM_KEYS] = {"Vladimir", "Nathaniel"}; 36 | 37 | json_object *root = json_object_from_file("names.json"); 38 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 39 | 40 | json_object_array_sort(root, sort_fn); 41 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 42 | 43 | for(int i=0; i 4 | #include 5 | #include 6 | 7 | static int 8 | print_str(json_object *jso, int flags, json_object *parent, const char *key, 9 | size_t *index, void *data) 10 | { 11 | if (index) 12 | printf("The value at %ld position is: %s\n", (long)* index, json_object_get_string(jso)); 13 | return JSON_C_VISIT_RETURN_CONTINUE; 14 | } 15 | 16 | int 17 | main(void) 18 | { 19 | json_object *root = json_object_from_file("names.json"); 20 | json_c_visit(root, 0, print_str, NULL); 21 | 22 | json_object_put(root); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/json-edit00.c: -------------------------------------------------------------------------------- 1 | // gcc json-edit00.c -ljson-c -o json-edit00 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | json_object *root = json_object_from_file("contact.json"); 10 | 11 | printf("The json file:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 12 | // Edit age 13 | json_object *age = json_object_object_get(root, "age"); 14 | json_object_int_inc(age, 1); 15 | 16 | // Edit office phone number 17 | json_object *phone_numbers = json_object_object_get(root, "phoneNumbers"); 18 | json_object *office = json_object_array_get_idx(phone_numbers, 1); 19 | json_object *number = json_object_object_get(office,"number"); 20 | json_object_set_string(number, "843 276-3583"); 21 | // Add Daughter 22 | json_object *children = json_object_object_get(root, "children"); 23 | json_object *paige = json_object_new_object(); 24 | json_object_object_add(paige, "name", json_object_new_string("Paige Crawford")); 25 | json_object_object_add(paige, "age", json_object_new_int(15)); 26 | json_object_array_add(children, paige); 27 | 28 | // Add Wife 29 | json_object *spouse = json_object_object_get(root, "spouse"); 30 | json_object_object_del(root,"spouse"); 31 | json_object_object_add(root,"spouse",json_object_new_string("Kate Smith")); 32 | printf("The Edited JSON:\n\n%s\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 33 | 34 | 35 | json_object_put(root); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /src/json-equal00.c: -------------------------------------------------------------------------------- 1 | // gcc json-equal00.c -ljson-c -o json-equal00 2 | 3 | // Need more research in this referencing stuff 4 | // purpose to show 2 attributes can have the same json obj as value 5 | 6 | 7 | #include 8 | #include 9 | 10 | int 11 | main(void) 12 | { 13 | const char *filename = "example01.json"; 14 | json_object *item, *location; 15 | 16 | json_object *doc1 = json_object_new_object(); 17 | // JSON Document 1 18 | json_object_object_add(doc1, "firstName", json_object_new_string("John")); 19 | json_object_object_add(doc1, "lastName", json_object_new_string("Smith")); 20 | json_object_object_add(doc1, "age", json_object_new_int(27)); 21 | printf("Document 1:\n\n%s\n\n", json_object_to_json_string_ext(doc1, JSON_C_TO_STRING_PRETTY)); 22 | json_object *doc2 = json_object_new_object(); 23 | // JSON Document 2 24 | json_object_object_add(doc2, "age", json_object_new_int(27)); 25 | json_object_object_add(doc2, "firstName", json_object_new_string("John")); 26 | json_object_object_add(doc2, "lastName", json_object_new_string("Smith")); 27 | printf("Document 2:\n\n%s\n\n", json_object_to_json_string_ext(doc2, JSON_C_TO_STRING_PRETTY)); 28 | 29 | if (json_object_equal(doc1,doc2)) 30 | printf("Documents are equal!"); 31 | else 32 | printf("Documents are NOT equal!"); 33 | // cleanup and exit 34 | json_object_put(doc1); 35 | json_object_put(doc2); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /src/json-error00.c: -------------------------------------------------------------------------------- 1 | // gcc json-json_error00.c -ljson-c -o json_error00 2 | // This program illustrates a circular reference. It will crash if you run it!! 3 | #include 4 | #include 5 | #include 6 | int 7 | main(void) 8 | { 9 | json_object *root = json_object_new_object(); 10 | if (!root) 11 | return 1; 12 | 13 | // main array 14 | json_object *items = json_object_new_object(); 15 | json_object_object_add(root, "items", items); 16 | // item 1 17 | 18 | json_object *properties = json_object_new_object(); 19 | json_object_object_add(items, "properties", properties); 20 | json_object *name = json_object_new_object(); 21 | json_object_object_add(properties, "name", name); 22 | json_object *type = json_object_new_string("unknown"); 23 | json_object_object_add(name, "type", type); 24 | 25 | items = json_object_new_object(); 26 | json_object_object_add(root, "common", items); 27 | json_object_object_add(items, "properties", root); 28 | 29 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 30 | 31 | // cleanup and exit 32 | json_object_put(root); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /src/json-file00.c: -------------------------------------------------------------------------------- 1 | // gcc json-file00.c -ljson-c -o json-file00 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | json_object *root = json_object_from_file("contact.json"); 10 | printf("The json file:\n\n%s\n", json_object_to_json_string(root)); 11 | 12 | printf("The json file:\n\n%s\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 13 | json_object_put(root); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /src/json-file01.c: -------------------------------------------------------------------------------- 1 | // gcc json-file01.c -ljson-c -o json-file01 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | json_object *root = json_object_from_file("contact.json"); 10 | if (!root) 11 | return 1; 12 | printf("The json file:\n\n%s\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 13 | json_object_put(root); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /src/json-mem00.c: -------------------------------------------------------------------------------- 1 | //gcc json-mem00.c -ljson-c -o json-mem00 2 | 3 | #include 4 | #include 5 | #include 6 | int 7 | main(void) 8 | { 9 | json_object *items, *item, *str; 10 | 11 | json_object *root = json_object_new_object(); 12 | if (!root) 13 | return 1; 14 | 15 | // main array 16 | items = json_object_new_array(); 17 | json_object_object_add(root, "items", items); 18 | // item 1 19 | item = json_object_new_object(); 20 | json_object_object_add(item, "id", json_object_new_int(3201)); 21 | str = json_object_new_string("online"); 22 | json_object_object_add(item, "status", str); 23 | json_object_array_add(items, item); 24 | 25 | // item 2 26 | item = json_object_new_object(); 27 | json_object_object_add(item, "id", json_object_new_int(4678)); 28 | json_object_get(str); 29 | json_object_object_add(item, "status", str); 30 | json_object_array_add(items, item); 31 | 32 | 33 | // item 3 34 | item = json_object_new_object(); 35 | json_object_object_add(item, "id", json_object_new_int(2345)); 36 | json_object_get(str); 37 | json_object_object_add(item, "status", str); 38 | json_object_array_add(items, item); 39 | 40 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 41 | 42 | // cleanup and exit 43 | json_object_put(root); 44 | //printf("SHIT %d\n", str->_ref_count); 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /src/json-mem01.c: -------------------------------------------------------------------------------- 1 | //gcc json-mem01.c -ljson-c -o json-mem01 2 | 3 | #include 4 | #include 5 | 6 | #define NUM_ID_ITEMS 3 7 | 8 | json_object * 9 | new_item(int id, json_object *str) 10 | { 11 | json_object *item = json_object_new_object(); 12 | json_object_object_add(item, "id", json_object_new_int(id)); 13 | json_object_object_add(item, "status", json_object_get(str)); 14 | return item; 15 | } 16 | 17 | int 18 | main(void) 19 | { 20 | json_object *items, *str; 21 | int id[3] = {3201, 4678, 2345}; 22 | 23 | json_object *root = json_object_new_object(); 24 | if (!root) 25 | return 1; 26 | 27 | // main array 28 | items = json_object_new_array(); 29 | json_object_object_add(root, "items", items); 30 | str = json_object_new_string("online"); 31 | 32 | // Add Items 33 | for(int i=0; i 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | const char *filename = "contact2.json"; 10 | json_object *root = json_object_new_object(); 11 | if (!root) 12 | return 1; 13 | 14 | // basic data 15 | json_object_object_add(root, "firstName", json_object_new_string("Bart")); 16 | json_object_object_add(root, "lastName", json_object_new_string("Johnson")); 17 | json_object_object_add(root, "isAlive", json_object_new_boolean(TRUE)); 18 | json_object_object_add(root, "age", json_object_new_int(57)); 19 | // address json 20 | json_object *address = json_object_new_object(); 21 | json_object_object_add(address, "streetAddress", json_object_new_string("105 Murdock")); 22 | json_object_object_add(address, "city", json_object_new_string("Princeton")); 23 | json_object_object_add(address, "state", json_object_new_string("WV")); 24 | json_object_object_add(address, "postalCode", json_object_new_string("24740")); 25 | json_object_object_add(root, "address", address); 26 | // phone numbers array 27 | json_object *phone_numbers = json_object_new_array(); 28 | json_object_object_add(root, "phoneNumbers", phone_numbers); 29 | // home 30 | json_object *phone_home = json_object_new_object(); 31 | json_object_object_add(phone_home, "type", json_object_new_string("home")); 32 | json_object_object_add(phone_home, "number", json_object_new_string("304-888-5686")); 33 | json_object_array_add(phone_numbers, phone_home); 34 | // cell 35 | json_object *phone_cell = json_object_new_object(); 36 | json_object_object_add(phone_cell, "type", json_object_new_string("cell")); 37 | json_object_object_add(phone_cell, "number", json_object_new_string("304-888-3023")); 38 | json_object_array_add(phone_numbers, phone_cell); 39 | 40 | // children array 41 | json_object *children = json_object_new_array(); 42 | json_object_object_add(root, "children", children); 43 | // daughter 44 | json_object *justine = json_object_new_object(); 45 | json_object_object_add(justine, "name", json_object_new_string("Justine Johnson")); 46 | json_object_object_add(justine, "age", json_object_new_int(29)); 47 | json_object_array_add(children, justine); 48 | 49 | // spouse 50 | json_object_object_add(root, "spouse", json_object_new_string("Bobbi Johnson")); 51 | 52 | // print json 53 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 54 | // save json 55 | if (json_object_to_file(filename, root)) 56 | printf("Error: failed to save %s!!\n", filename); 57 | else 58 | printf("%s saved.\n", filename); 59 | 60 | // cleanup and exit 61 | json_object_put(root); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /src/json-new01.c: -------------------------------------------------------------------------------- 1 | // gcc json-new01.c -ljson-c -o json-new01 2 | 3 | // Need more research in this referencing stuff 4 | // purpose to show 2 attributes can have the same json obj as value 5 | // from docs: Remember, when using json_object_object_add or json_object_array_put_idx, ownership will transfer to the object/array. Call json_object_get if you want to maintain shared ownership or also add this object as a child of multiple objects or arrays. 6 | 7 | 8 | #include 9 | #include 10 | 11 | int 12 | main(void) 13 | { 14 | const char *filename = "example01.json"; 15 | json_object *item, *location; 16 | 17 | json_object *root = json_object_new_object(); 18 | if (!root) 19 | return 1; 20 | 21 | // main array 22 | json_object *items = json_object_new_array(); 23 | json_object_object_add(root, "items", items); 24 | // item 1 25 | item = json_object_new_object(); 26 | json_object_object_add(item, "id", json_object_new_int(3201)); 27 | json_object_object_add(item, "status", json_object_new_string("online")); 28 | json_object_array_add(items, item); 29 | location = json_object_new_object(); 30 | 31 | json_object_object_add(location, "latitude", json_object_new_double(-117.125)); 32 | json_object_object_add(location, "longitude", json_object_new_double(31.125)); 33 | json_object_object_add(item, "location", location); 34 | json_object_get(location); 35 | // item 2 36 | item = json_object_new_object(); 37 | json_object_object_add(item, "id", json_object_new_int(4678)); 38 | json_object_object_add(item, "status", json_object_new_string("online")); 39 | json_object_array_add(items, item); 40 | json_object_object_add(item, "location", location); 41 | 42 | // item 3 43 | item = json_object_new_object(); 44 | json_object_object_add(item, "id", json_object_new_int(9823)); 45 | json_object_object_add(item, "status", json_object_new_string("offline")); 46 | json_object_array_add(items, item); 47 | location = json_object_new_object(); 48 | json_object_object_add(location, "latitude", json_object_new_double(-111.625)); 49 | json_object_object_add(location, "longitude", json_object_new_double(35.625)); 50 | json_object_object_add(item, "location", location); 51 | 52 | // print json 53 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 54 | // save json 55 | if (json_object_to_file(filename, root)) 56 | printf("Error: failed to save %s!!\n", filename); 57 | else 58 | printf("%s saved.\n", filename); 59 | 60 | // cleanup and exit 61 | 62 | json_object_put(root); 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /src/json-parse00.c: -------------------------------------------------------------------------------- 1 | // gcc json-parse00.c -ljson-c -o json-parse00 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | json_object *root = json_object_from_file("contact.json"); 10 | if (!root) 11 | return 1; 12 | 13 | json_object *first_name = json_object_object_get(root, "firstName"); 14 | json_object *last_name = json_object_object_get(root, "lastName"); 15 | printf("%s, %s\n", json_object_get_string(last_name), json_object_get_string(first_name)); 16 | 17 | json_object_put(root); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/json-parse01.c: -------------------------------------------------------------------------------- 1 | // gcc json-parse01.c -ljson-c -o json-parse01 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int 8 | main(void) 9 | { 10 | char *fname, *lname; 11 | json_object *root = json_object_from_file("contact.json"); 12 | if (!root) 13 | return 1; 14 | 15 | json_object *first_name = json_object_object_get(root, "firstName"); 16 | json_object *last_name = json_object_object_get(root, "lastName"); 17 | // Store the string values of these json_objects in our char arrays 18 | fname = strdup(json_object_get_string(first_name)); 19 | lname = strdup(json_object_get_string(last_name)); 20 | // Lose ownership of our json_objects first_name and last_name 21 | json_object_put(root); 22 | // Verify our char arrays still have the proper values 23 | printf("%s, %s\n", fname, lname); 24 | // Cleanup 25 | free(fname); 26 | free(lname); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /src/json-parse02.c: -------------------------------------------------------------------------------- 1 | // gcc json-parse02.c -ljson-c -o json-parse02 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | json_object *first_name, *last_name; 10 | json_object *root = json_object_from_file("contact.json"); 11 | if (!root) 12 | return 1; 13 | 14 | json_object_object_get_ex(root, "firstName", &first_name); 15 | json_object_object_get_ex(root, "lastName", &last_name); 16 | printf("%s, %s\n", json_object_get_string(last_name), json_object_get_string(first_name)); 17 | json_object_put(root); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/json-parse03.c: -------------------------------------------------------------------------------- 1 | // gcc json-parse03.c -ljson-c -o json-parse03 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | json_object *root = json_object_from_file("contact.json"); 10 | if (!root) 11 | return 1; 12 | 13 | json_object *first_name = json_object_object_get(root, "firstName"); 14 | json_object *last_name = json_object_object_get(root, "lastName"); 15 | 16 | printf("%s, %s\n", json_object_get_string(last_name), json_object_get_string(first_name)); 17 | json_object_put(root); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/json-parse04.c: -------------------------------------------------------------------------------- 1 | // gcc json-parse04.c -ljson-c -o json-parse04 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | int temp_n; 10 | json_object *root, *temp; 11 | 12 | root = json_object_from_file("contact.json"); 13 | if (!root) 14 | return 1; 15 | 16 | json_object *first_name = json_object_object_get(root, "firstName"); 17 | printf("First name: %s\n", json_object_get_string(first_name)); 18 | json_object *last_name = json_object_object_get(root, "lastName"); 19 | printf("Last name: %s\n", json_object_get_string(last_name)); 20 | json_object *is_alive = json_object_object_get(root, "isAlive"); 21 | printf("Is Alive: %s\n", json_object_get_boolean(is_alive)? "yes": "No"); 22 | json_object *age = json_object_object_get(root, "age"); 23 | printf("Age: %d\n", json_object_get_int(age)); 24 | 25 | printf("Address:\n"); 26 | json_object *address = json_object_object_get(root, "address"); 27 | json_object *st_address = json_object_object_get(address, "streetAddress"); 28 | printf("\tStreet Address: %s\n", json_object_get_string(st_address)); 29 | json_object *city = json_object_object_get(address, "city"); 30 | printf("\tCity: %s\n", json_object_get_string(city)); 31 | json_object *state = json_object_object_get(address, "state"); 32 | printf("\tState: %s\n", json_object_get_string(state)); 33 | json_object *zip = json_object_object_get(address, "postalCode"); 34 | printf("\tZip Code %s\n", json_object_get_string(zip)); 35 | 36 | printf("Phone Numbers:\n"); 37 | json_object *phone_numbers = json_object_object_get(root, "phoneNumbers"); 38 | temp_n = json_object_array_length(phone_numbers); 39 | for (int i = 0; i < temp_n; i++) 40 | { 41 | temp = json_object_array_get_idx(phone_numbers, i); 42 | json_object *type = json_object_object_get(temp, "type"); 43 | json_object *number = json_object_object_get(temp, "number"); 44 | printf("\tPhone number %d: %s: %s\n", i, json_object_get_string(type), json_object_get_string(number)); 45 | } 46 | 47 | printf("Children:\n"); 48 | json_object *children = json_object_object_get(root, "children"); 49 | if (json_object_get_type(children) == json_type_null) 50 | printf("\tNo children\n"); 51 | else 52 | { 53 | temp_n = json_object_array_length(children); 54 | if (temp_n) 55 | for (int i = 0; i < temp_n; i++) 56 | { 57 | temp = json_object_array_get_idx(children, i); 58 | json_object *name = json_object_object_get(temp, "name"); 59 | printf("\t Name: %s\n", json_object_get_string(name)); 60 | age = json_object_object_get(temp, "age"); 61 | printf("\t Age: %d\n\n", json_object_get_int(age)); 62 | } 63 | else 64 | printf("\tUnknown\n"); 65 | } 66 | 67 | printf("Spouse:\n"); 68 | json_object *spouse = json_object_object_get(root, "spouse"); 69 | if (json_object_get_type(spouse) == json_type_null) 70 | printf("\tNo Spouse Known\n"); 71 | else 72 | { 73 | json_object *name = json_object_object_get(spouse, "name"); 74 | printf("\t Name: %s\n", json_object_get_string(name)); 75 | age = json_object_object_get(spouse, "age"); 76 | printf("\t Age: %d\n\n", json_object_get_int(age)); 77 | } 78 | 79 | json_object_put(root); 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /src/json-parse05.c: -------------------------------------------------------------------------------- 1 | // gcc json-parse05.c -ljson-c -o json-parse05 2 | 3 | #include 4 | #include 5 | #define SAMPLE_JSON \ 6 | "{" \ 7 | " \"firstName\": \"John\"," \ 8 | " \"lastName\": \"Smith\"," \ 9 | " \"isAlive\": true," \ 10 | " \"age\": 27," \ 11 | " \"address\": {" \ 12 | " \"streetAddress\": \"21 2nd Street\"," \ 13 | " \"city\": \"New York\"," \ 14 | " \"state\": \"NY\"," \ 15 | " \"postalCode\": \"10021-3100\"" \ 16 | " }," \ 17 | " \"phoneNumbers\": [" \ 18 | " {" \ 19 | " \"type\": \"home\"," \ 20 | " \"number\": \"212 555-1234\"" \ 21 | " }," \ 22 | " {" \ 23 | " \"type\": \"office\"," \ 24 | " \"number\": \"646 555-4567\"" \ 25 | " }" \ 26 | " ]," \ 27 | " \"children\": [" \ 28 | " {" \ 29 | " \"name\": \"Tammy Smith\"," \ 30 | " \"age\": 3" \ 31 | " }," \ 32 | " {" \ 33 | " \"name\": \"Judah Smith\"," \ 34 | " \"age\": 7" \ 35 | " }" \ 36 | " ]," \ 37 | " \"spouse\": {" \ 38 | " \"name\": \"Amanda Smith\"," \ 39 | " \"age\": 23" \ 40 | " }" \ 41 | "}" 42 | 43 | int 44 | main(void) 45 | { 46 | int temp_n; 47 | json_object *root, *temp; 48 | 49 | root = json_tokener_parse(SAMPLE_JSON); 50 | if (!root) 51 | { 52 | printf("Root is null\n"); 53 | return 1; 54 | } 55 | 56 | json_object *first_name = json_object_object_get(root, "firstName"); 57 | printf("First name: %s\n", json_object_get_string(first_name)); 58 | json_object *last_name = json_object_object_get(root, "lastName"); 59 | printf("Last name: %s\n", json_object_get_string(last_name)); 60 | json_object *is_alive = json_object_object_get(root, "isAlive"); 61 | printf("Is Alive: %s\n", json_object_get_boolean(is_alive)? "yes": "No"); 62 | json_object *age = json_object_object_get(root, "age"); 63 | printf("Age: %d\n", json_object_get_int(age)); 64 | 65 | printf("Address:\n"); 66 | json_object *address = json_object_object_get(root, "address"); 67 | json_object *st_address = json_object_object_get(address, "streetAddress"); 68 | printf("\tStreet Address: %s\n", json_object_get_string(st_address)); 69 | json_object *city = json_object_object_get(address, "city"); 70 | printf("\tCity: %s\n", json_object_get_string(city)); 71 | json_object *state = json_object_object_get(address, "state"); 72 | printf("\tState: %s\n", json_object_get_string(state)); 73 | json_object *zip = json_object_object_get(address, "postalCode"); 74 | printf("\tZip Code %s\n", json_object_get_string(zip)); 75 | 76 | printf("Phone Numbers:\n"); 77 | json_object *phone_numbers = json_object_object_get(root, "phoneNumbers"); 78 | temp_n = json_object_array_length(phone_numbers); 79 | for (int i = 0; i < temp_n; i++) 80 | { 81 | temp = json_object_array_get_idx(phone_numbers, i); 82 | json_object *type = json_object_object_get(temp, "type"); 83 | json_object *number = json_object_object_get(temp, "number"); 84 | printf("\tPhone number %d: %s: %s\n", i, json_object_get_string(type), json_object_get_string(number)); 85 | } 86 | 87 | printf("Children:\n"); 88 | json_object *children = json_object_object_get(root, "children"); 89 | if (json_object_get_type(children) == json_type_null) 90 | printf("\tNo children\n"); 91 | else 92 | { 93 | temp_n = json_object_array_length(children); 94 | if (temp_n) 95 | for (int i = 0; i < temp_n; i++) 96 | { 97 | temp = json_object_array_get_idx(children, i); 98 | json_object *name = json_object_object_get(temp, "name"); 99 | printf("\t Name: %s\n", json_object_get_string(name)); 100 | age = json_object_object_get(temp, "age"); 101 | printf("\t Age: %d\n\n", json_object_get_int(age)); 102 | } 103 | else 104 | printf("\tUnknown\n"); 105 | } 106 | 107 | printf("Spouse:\n"); 108 | json_object *spouse = json_object_object_get(root, "spouse"); 109 | if (json_object_get_type(spouse) == json_type_null) 110 | printf("\tNo Spouse Known\n"); 111 | else 112 | { 113 | json_object *name = json_object_object_get(spouse, "name"); 114 | printf("\t Name: %s\n", json_object_get_string(name)); 115 | age = json_object_object_get(spouse, "age"); 116 | printf("\t Age: %d\n\n", json_object_get_int(age)); 117 | } 118 | 119 | json_object_put(root); 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /src/json-parse06.c: -------------------------------------------------------------------------------- 1 | // gcc json-parse06.c -ljson-c -o json-parse06 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int 8 | main(void) 9 | { 10 | json_object *root = json_object_from_file("contact.json"); 11 | json_object_object_foreach(root, key, val) 12 | printf("%s -> %s\n", key, json_object_get_string(val)); 13 | 14 | json_object_put(root); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /src/json-parse07.c: -------------------------------------------------------------------------------- 1 | // gcc json-parse07.c -ljson-c -o json-parse07 2 | 3 | #include 4 | #include 5 | 6 | void doarray(json_object *obj); 7 | 8 | void 9 | doit(json_object *obj) 10 | { 11 | json_object_object_foreach(obj, key, val) 12 | { 13 | switch (json_object_get_type(val)) 14 | { 15 | case json_type_array: 16 | printf("\n%s \n\n", key); 17 | doarray(val); 18 | break; 19 | 20 | case json_type_object: 21 | printf("\n%s \n\n", key); 22 | doit(val); 23 | break; 24 | 25 | default: 26 | printf("%s: %s\n", key, json_object_get_string(val)); 27 | } 28 | } 29 | } 30 | 31 | void 32 | doarray(json_object *obj) 33 | { 34 | int temp_n = json_object_array_length(obj); 35 | for (int i = 0; i < temp_n; i++) 36 | doit(json_object_array_get_idx(obj, i)); 37 | } 38 | 39 | int 40 | main(void) 41 | { 42 | json_object *root = json_object_from_file("contact.json"); 43 | 44 | if (!root) 45 | return 1; 46 | doit(root); 47 | 48 | json_object_put(root); 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /src/json-parse08.c: -------------------------------------------------------------------------------- 1 | // gcc json-parse08.c -ljson-c -o json-parse08 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | struct json_object_iterator it; 10 | struct json_object_iterator itEnd; 11 | 12 | json_object *root = json_object_from_file("contact.json"); 13 | it = json_object_iter_init_default(); 14 | it = json_object_iter_begin(root); 15 | itEnd = json_object_iter_end(root); 16 | 17 | while (!json_object_iter_equal(&it, &itEnd)) 18 | { 19 | const char* key = json_object_iter_peek_name(&it); 20 | json_object* val = json_object_iter_peek_value(&it); 21 | printf("%s -> %s\n", key, json_object_get_string(val)); 22 | json_object_iter_next(&it); 23 | } 24 | json_object_put(root); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /src/json-parse10.c: -------------------------------------------------------------------------------- 1 | // gcc json-parse10.c -L/usr/local/lib -I/usr/local/include/json-c -ljson-c -o json-parse10 2 | // see json-parse07.c 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | static int 9 | doit(json_object *obj, int flags, json_object *parent, const char *key, 10 | size_t *index, void *data) 11 | { 12 | if (!parent || flags==JSON_C_VISIT_SECOND) return JSON_C_VISIT_RETURN_CONTINUE; 13 | printf("key: %s, value: %s\n", key, json_object_to_json_string(obj)); 14 | return JSON_C_VISIT_RETURN_CONTINUE; 15 | } 16 | 17 | int 18 | main(void) 19 | { 20 | json_object *root = json_object_from_file("depth.json"); 21 | json_c_visit(root, 0, doit, NULL); 22 | 23 | json_object_put(root); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /src/json-parse11.c: -------------------------------------------------------------------------------- 1 | // gcc json-parse11.c -L/usr/local/lib -I/usr/local/include/json-c -ljson-c -o json-parse11 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define EMAIL "ptunkiny@angelfire.com" 8 | #define JSON_OBJECT_STR(obj, key) json_object_get_string(json_object_object_get(obj, key)) 9 | 10 | static int 11 | doit(json_object *obj, int flags, json_object *parent, const char *key, 12 | size_t *index, void *data) 13 | { 14 | if (!parent || flags==JSON_C_VISIT_SECOND || 15 | json_object_get_type(obj) == json_type_object || 16 | json_object_get_type(obj) == json_type_array) 17 | return JSON_C_VISIT_RETURN_CONTINUE; 18 | 19 | if (strcmp(json_object_get_string(obj), EMAIL) == 0) 20 | { 21 | printf("Found: %s %s %s\n", JSON_OBJECT_STR(parent, "first_name"), 22 | JSON_OBJECT_STR(parent, "last_name"), json_object_to_json_string(obj)); 23 | return JSON_C_VISIT_RETURN_STOP; 24 | } 25 | return JSON_C_VISIT_RETURN_CONTINUE; 26 | } 27 | 28 | int 29 | main(void) 30 | { 31 | json_object *root = json_object_from_file("sample00.json"); 32 | printf("Search for %s\n\n", EMAIL); 33 | json_c_visit(root, 0, doit, NULL); 34 | 35 | json_object_put(root); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /src/json-str00.c: -------------------------------------------------------------------------------- 1 | // gcc json-str00.c -ljson-c -o json-str00 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | char * str = "{\"firstName\" : \"John\", \"lastName\" : \"Smith\", \"email\":[{\"type\": \"personal\",\"url\": \"johnsmith0321@gmail.com\"},{\"type\": \"office\",\"url\": \"johnsmith@frankford.com\"} ] }"; 10 | json_object *root = json_tokener_parse(str); 11 | printf("The json string:\n\n%s\n\n", json_object_to_json_string(root)); 12 | 13 | printf("The json object to string:\n\n%s\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 14 | json_object_put(root); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /src/json-type00.c: -------------------------------------------------------------------------------- 1 | // gcc json-type00.c -ljson-c -o json-type00 2 | 3 | #include 4 | #include 5 | 6 | void json_object_print_type(json_object *obj, const char *key); 7 | 8 | int 9 | main(void) 10 | { 11 | json_object *root = json_object_from_file("contact.json"); 12 | if (!root) 13 | return 1; 14 | 15 | json_object *first_name = json_object_object_get(root, "firstName"); 16 | json_object_print_type(first_name, "firstName"); 17 | json_object *last_name = json_object_object_get(root, "lastName"); 18 | json_object_print_type(last_name, "lastName"); 19 | json_object *is_alive = json_object_object_get(root, "isAlive"); 20 | json_object_print_type(is_alive, "isAlive"); 21 | json_object *age = json_object_object_get(root, "age"); 22 | json_object_print_type(age, "age"); 23 | json_object *address = json_object_object_get(root, "address"); 24 | json_object_print_type(address, "address"); 25 | json_object *phone_numbers = json_object_object_get(root, "phoneNumbers"); 26 | json_object_print_type(phone_numbers, "phoneNumbers"); 27 | json_object *children = json_object_object_get(root, "children"); 28 | json_object_print_type(children, "children"); 29 | json_object *spouse = json_object_object_get(root, "spouse"); 30 | json_object_print_type(spouse, "spouse"); 31 | 32 | json_object_put(root); 33 | return 0; 34 | } 35 | 36 | void 37 | json_object_print_type(json_object *obj, const char *key) 38 | { 39 | json_type type; 40 | 41 | type = json_object_get_type(obj); /*Getting the type of the json object*/ 42 | switch (type) 43 | { 44 | case json_type_null: 45 | printf("%s is json_type_null\n", key); 46 | printf(" value: %s\n", json_object_get_string(obj)); 47 | break; 48 | 49 | case json_type_boolean: 50 | printf("%s is json_type_boolean\n", key); 51 | printf(" value: %s\n", json_object_get_boolean(obj)? "true": "false"); 52 | break; 53 | 54 | case json_type_double: 55 | printf("%s is json_type_double\n", key); 56 | printf(" value: %lf\n", json_object_get_double(obj)); 57 | break; 58 | 59 | case json_type_int: 60 | printf("%s is json_type_int\n", key); 61 | printf(" value: %d\n", json_object_get_int(obj)); 62 | break; 63 | 64 | case json_type_object: 65 | printf("%s is json_type_object\n", key); 66 | printf(" value: %s\n", json_object_get_string(obj)); 67 | break; 68 | 69 | case json_type_array: 70 | printf("%s is json_type_array\n", key); 71 | printf(" value: %s\n", json_object_get_string(obj)); 72 | break; 73 | 74 | case json_type_string: 75 | printf("%s is json_type_string\n", key); 76 | printf(" value: %s\n", json_object_get_string(obj)); 77 | break; 78 | 79 | default: 80 | printf("%s: WTF, unhandled case, type %d\n", key, type); 81 | printf(" value: %s\n", json_object_get_string(obj)); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/json-version.c: -------------------------------------------------------------------------------- 1 | // gcc json-version.c -ljson-c -o json-version 2 | #include 3 | #include 4 | 5 | int 6 | main(void) 7 | { 8 | printf("Version: %s\n", json_c_version()); 9 | printf("Version Number: %d\n", json_c_version_num()); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /src/json00.c: -------------------------------------------------------------------------------- 1 | // gcc json00.c -ljson-c -o json00 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main(void) 8 | { 9 | json_object *root = json_object_from_file("sample.json"); 10 | json_object_object_foreach(root, key, val) 11 | printf("%s -> %s\n", key, json_object_get_string(val)); 12 | 13 | json_object_put(root); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /src/names.json: -------------------------------------------------------------------------------- 1 | ["Torin", "Stefin", "Emerson", "Lisandro", "Caidan", "Toby", "Qasim", "Abdullah", "Hcen", "Obosa", "Manolo", "Aedan", "Bobby", "Calen", "Bailee", "Eoghain", "Macaulay", "Vladimir", "Noah", "Youcef"] 2 | -------------------------------------------------------------------------------- /src/sample00.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "id": 1, 3 | "first_name": "Catie", 4 | "last_name": "Gregorin", 5 | "email": "cgregorin0@elegantthemes.com", 6 | "gender": "Female", 7 | "ip_address": "172.219.194.172" 8 | }, { 9 | "id": 2, 10 | "first_name": "Hill", 11 | "last_name": "Darnbrook", 12 | "email": "hdarnbrook1@jugem.jp", 13 | "gender": "Male", 14 | "ip_address": "175.66.169.235" 15 | }, { 16 | "id": 3, 17 | "first_name": "Rosella", 18 | "last_name": "Izaac", 19 | "email": "rizaac2@usnews.com", 20 | "gender": "Female", 21 | "ip_address": "251.112.101.106" 22 | }, { 23 | "id": 4, 24 | "first_name": "Alina", 25 | "last_name": "Comi", 26 | "email": "acomi3@harvard.edu", 27 | "gender": "Female", 28 | "ip_address": "248.163.12.37" 29 | }, { 30 | "id": 5, 31 | "first_name": "Neall", 32 | "last_name": "Maris", 33 | "email": "nmaris4@craigslist.org", 34 | "gender": "Male", 35 | "ip_address": "8.136.233.240" 36 | }, { 37 | "id": 6, 38 | "first_name": "Far", 39 | "last_name": "Atkinson", 40 | "email": "fatkinson5@bigcartel.com", 41 | "gender": "Male", 42 | "ip_address": "64.54.126.203" 43 | }, { 44 | "id": 7, 45 | "first_name": "Mignon", 46 | "last_name": "Inett", 47 | "email": "minett6@hao123.com", 48 | "gender": "Female", 49 | "ip_address": "131.40.64.21" 50 | }, { 51 | "id": 8, 52 | "first_name": "Guthry", 53 | "last_name": "Kidney", 54 | "email": "gkidney7@ox.ac.uk", 55 | "gender": "Male", 56 | "ip_address": "167.244.131.101" 57 | }, { 58 | "id": 9, 59 | "first_name": "Della", 60 | "last_name": "Burrel", 61 | "email": "dburrel8@netvibes.com", 62 | "gender": "Female", 63 | "ip_address": "90.194.75.111" 64 | }, { 65 | "id": 10, 66 | "first_name": "Sunny", 67 | "last_name": "Shadfourth", 68 | "email": "sshadfourth9@moonfruit.com", 69 | "gender": "Female", 70 | "ip_address": "41.99.74.9" 71 | }, { 72 | "id": 11, 73 | "first_name": "Estrella", 74 | "last_name": "Scales", 75 | "email": "escalesa@cocolog-nifty.com", 76 | "gender": "Female", 77 | "ip_address": "21.115.92.76" 78 | }, { 79 | "id": 12, 80 | "first_name": "Gavan", 81 | "last_name": "Messham", 82 | "email": "gmesshamb@omniture.com", 83 | "gender": "Male", 84 | "ip_address": "94.231.6.66" 85 | }, { 86 | "id": 13, 87 | "first_name": "Carolina", 88 | "last_name": "Matuszak", 89 | "email": "cmatuszakc@deliciousdays.com", 90 | "gender": "Female", 91 | "ip_address": "191.215.116.2" 92 | }, { 93 | "id": 14, 94 | "first_name": "Saw", 95 | "last_name": "Vaadeland", 96 | "email": "svaadelandd@cnet.com", 97 | "gender": "Male", 98 | "ip_address": "39.223.59.173" 99 | }, { 100 | "id": 15, 101 | "first_name": "Antonella", 102 | "last_name": "Pacey", 103 | "email": "apaceye@nifty.com", 104 | "gender": "Female", 105 | "ip_address": "198.35.115.109" 106 | }, { 107 | "id": 16, 108 | "first_name": "Tyler", 109 | "last_name": "Filippyev", 110 | "email": "tfilippyevf@umn.edu", 111 | "gender": "Male", 112 | "ip_address": "80.37.142.169" 113 | }, { 114 | "id": 17, 115 | "first_name": "Andris", 116 | "last_name": "Slyman", 117 | "email": "aslymang@nifty.com", 118 | "gender": "Male", 119 | "ip_address": "226.6.89.253" 120 | }, { 121 | "id": 18, 122 | "first_name": "Inglis", 123 | "last_name": "Rounsefell", 124 | "email": "irounsefellh@huffingtonpost.com", 125 | "gender": "Male", 126 | "ip_address": "190.247.235.103" 127 | }, { 128 | "id": 19, 129 | "first_name": "Dorolice", 130 | "last_name": "Likly", 131 | "email": "dliklyi@tmall.com", 132 | "gender": "Female", 133 | "ip_address": "20.107.102.68" 134 | }, { 135 | "id": 20, 136 | "first_name": "Vitoria", 137 | "last_name": "Butten", 138 | "email": "vbuttenj@de.vu", 139 | "gender": "Female", 140 | "ip_address": "53.89.79.227" 141 | }, { 142 | "id": 21, 143 | "first_name": "Sergent", 144 | "last_name": "Prew", 145 | "email": "sprewk@cnn.com", 146 | "gender": "Male", 147 | "ip_address": "62.28.233.4" 148 | }, { 149 | "id": 22, 150 | "first_name": "Devland", 151 | "last_name": "Whitty", 152 | "email": "dwhittyl@bloglines.com", 153 | "gender": "Male", 154 | "ip_address": "84.205.35.243" 155 | }, { 156 | "id": 23, 157 | "first_name": "Carling", 158 | "last_name": "McNelis", 159 | "email": "cmcnelism@pagesperso-orange.fr", 160 | "gender": "Male", 161 | "ip_address": "144.83.191.167" 162 | }, { 163 | "id": 24, 164 | "first_name": "James", 165 | "last_name": "Brister", 166 | "email": "jbristern@nationalgeographic.com", 167 | "gender": "Male", 168 | "ip_address": "144.226.245.85" 169 | }, { 170 | "id": 25, 171 | "first_name": "Moselle", 172 | "last_name": "Mensler", 173 | "email": "mmenslero@who.int", 174 | "gender": "Female", 175 | "ip_address": "233.166.219.83" 176 | }, { 177 | "id": 26, 178 | "first_name": "Nannie", 179 | "last_name": "Aleswell", 180 | "email": "naleswellp@shutterfly.com", 181 | "gender": "Female", 182 | "ip_address": "161.139.69.42" 183 | }, { 184 | "id": 27, 185 | "first_name": "Christiane", 186 | "last_name": "Nicholson", 187 | "email": "cnicholsonq@npr.org", 188 | "gender": "Female", 189 | "ip_address": "70.6.69.159" 190 | }, { 191 | "id": 28, 192 | "first_name": "Neils", 193 | "last_name": "Mallock", 194 | "email": "nmallockr@un.org", 195 | "gender": "Male", 196 | "ip_address": "170.123.139.51" 197 | }, { 198 | "id": 29, 199 | "first_name": "Celie", 200 | "last_name": "Longmate", 201 | "email": "clongmates@wisc.edu", 202 | "gender": "Female", 203 | "ip_address": "217.17.2.196" 204 | }, { 205 | "id": 30, 206 | "first_name": "Cordie", 207 | "last_name": "McNamara", 208 | "email": "cmcnamarat@washingtonpost.com", 209 | "gender": "Female", 210 | "ip_address": "53.92.2.204" 211 | }, { 212 | "id": 31, 213 | "first_name": "Ilse", 214 | "last_name": "Ulrik", 215 | "email": "iulriku@cocolog-nifty.com", 216 | "gender": "Female", 217 | "ip_address": "3.223.234.105" 218 | }, { 219 | "id": 32, 220 | "first_name": "Benito", 221 | "last_name": "Snaden", 222 | "email": "bsnadenv@jigsy.com", 223 | "gender": "Male", 224 | "ip_address": "61.90.49.244" 225 | }, { 226 | "id": 33, 227 | "first_name": "Gib", 228 | "last_name": "Doni", 229 | "email": "gdoniw@wsj.com", 230 | "gender": "Male", 231 | "ip_address": "241.221.109.71" 232 | }, { 233 | "id": 34, 234 | "first_name": "Cynthia", 235 | "last_name": "Aloway", 236 | "email": "calowayx@amazon.co.uk", 237 | "gender": "Female", 238 | "ip_address": "17.140.95.196" 239 | }, { 240 | "id": 35, 241 | "first_name": "Palm", 242 | "last_name": "Tunkin", 243 | "email": "ptunkiny@angelfire.com", 244 | "gender": "Male", 245 | "ip_address": "12.22.143.229" 246 | }, { 247 | "id": 36, 248 | "first_name": "Cary", 249 | "last_name": "Gartin", 250 | "email": "cgartinz@vkontakte.ru", 251 | "gender": "Female", 252 | "ip_address": "6.236.220.239" 253 | }, { 254 | "id": 37, 255 | "first_name": "Francyne", 256 | "last_name": "Kasperski", 257 | "email": "fkasperski10@ow.ly", 258 | "gender": "Female", 259 | "ip_address": "24.27.105.43" 260 | }, { 261 | "id": 38, 262 | "first_name": "Roxanna", 263 | "last_name": "Cheavin", 264 | "email": "rcheavin11@rediff.com", 265 | "gender": "Female", 266 | "ip_address": "89.149.92.74" 267 | }, { 268 | "id": 39, 269 | "first_name": "Torey", 270 | "last_name": "Plail", 271 | "email": "tplail12@jalbum.net", 272 | "gender": "Male", 273 | "ip_address": "194.163.219.128" 274 | }, { 275 | "id": 40, 276 | "first_name": "Rog", 277 | "last_name": "Blint", 278 | "email": "rblint13@bloglovin.com", 279 | "gender": "Male", 280 | "ip_address": "119.117.71.212" 281 | }, { 282 | "id": 41, 283 | "first_name": "Foss", 284 | "last_name": "Dulen", 285 | "email": "fdulen14@hc360.com", 286 | "gender": "Male", 287 | "ip_address": "210.78.68.24" 288 | }, { 289 | "id": 42, 290 | "first_name": "Leonard", 291 | "last_name": "Cluer", 292 | "email": "lcluer15@senate.gov", 293 | "gender": "Male", 294 | "ip_address": "119.248.231.48" 295 | }, { 296 | "id": 43, 297 | "first_name": "Nicky", 298 | "last_name": "Ganforthe", 299 | "email": "nganforthe16@imdb.com", 300 | "gender": "Male", 301 | "ip_address": "137.180.224.159" 302 | }, { 303 | "id": 44, 304 | "first_name": "Jerome", 305 | "last_name": "Keoghan", 306 | "email": "jkeoghan17@whitehouse.gov", 307 | "gender": "Male", 308 | "ip_address": "221.237.224.222" 309 | }, { 310 | "id": 45, 311 | "first_name": "Berton", 312 | "last_name": "Cloake", 313 | "email": "bcloake18@e-recht24.de", 314 | "gender": "Male", 315 | "ip_address": "145.208.30.252" 316 | }, { 317 | "id": 46, 318 | "first_name": "Gradeigh", 319 | "last_name": "Izzard", 320 | "email": "gizzard19@baidu.com", 321 | "gender": "Male", 322 | "ip_address": "255.79.12.233" 323 | }, { 324 | "id": 47, 325 | "first_name": "Jeff", 326 | "last_name": "Stockport", 327 | "email": "jstockport1a@purevolume.com", 328 | "gender": "Male", 329 | "ip_address": "52.31.133.220" 330 | }, { 331 | "id": 48, 332 | "first_name": "Ario", 333 | "last_name": "Shelliday", 334 | "email": "ashelliday1b@youku.com", 335 | "gender": "Male", 336 | "ip_address": "157.22.23.36" 337 | }, { 338 | "id": 49, 339 | "first_name": "Ag", 340 | "last_name": "Dempsey", 341 | "email": "adempsey1c@whitehouse.gov", 342 | "gender": "Female", 343 | "ip_address": "195.99.114.173" 344 | }, { 345 | "id": 50, 346 | "first_name": "Adams", 347 | "last_name": "Divell", 348 | "email": "adivell1d@purevolume.com", 349 | "gender": "Male", 350 | "ip_address": "132.52.93.50" 351 | }, { 352 | "id": 51, 353 | "first_name": "Brien", 354 | "last_name": "Sollitt", 355 | "email": "bsollitt1e@walmart.com", 356 | "gender": "Male", 357 | "ip_address": "21.137.207.9" 358 | }, { 359 | "id": 52, 360 | "first_name": "Sergeant", 361 | "last_name": "Scole", 362 | "email": "sscole1f@toplist.cz", 363 | "gender": "Male", 364 | "ip_address": "100.171.202.239" 365 | }, { 366 | "id": 53, 367 | "first_name": "Valli", 368 | "last_name": "McRorie", 369 | "email": "vmcrorie1g@digg.com", 370 | "gender": "Female", 371 | "ip_address": "199.56.71.247" 372 | }, { 373 | "id": 54, 374 | "first_name": "Rodolfo", 375 | "last_name": "Baddam", 376 | "email": "rbaddam1h@meetup.com", 377 | "gender": "Male", 378 | "ip_address": "104.160.171.81" 379 | }, { 380 | "id": 55, 381 | "first_name": "Floria", 382 | "last_name": "Burr", 383 | "email": "fburr1i@rediff.com", 384 | "gender": "Female", 385 | "ip_address": "119.198.99.95" 386 | }, { 387 | "id": 56, 388 | "first_name": "Rebeka", 389 | "last_name": "Seathwright", 390 | "email": "rseathwright1j@dagondesign.com", 391 | "gender": "Female", 392 | "ip_address": "60.131.39.126" 393 | }, { 394 | "id": 57, 395 | "first_name": "Gabie", 396 | "last_name": "Rupert", 397 | "email": "grupert1k@bandcamp.com", 398 | "gender": "Male", 399 | "ip_address": "93.186.82.30" 400 | }, { 401 | "id": 58, 402 | "first_name": "Washington", 403 | "last_name": "Melmore", 404 | "email": "wmelmore1l@accuweather.com", 405 | "gender": "Male", 406 | "ip_address": "33.35.91.111" 407 | }, { 408 | "id": 59, 409 | "first_name": "Bertie", 410 | "last_name": "Haliburton", 411 | "email": "bhaliburton1m@soundcloud.com", 412 | "gender": "Female", 413 | "ip_address": "244.141.171.79" 414 | }, { 415 | "id": 60, 416 | "first_name": "Phillipe", 417 | "last_name": "Smoughton", 418 | "email": "psmoughton1n@purevolume.com", 419 | "gender": "Male", 420 | "ip_address": "139.167.204.5" 421 | }, { 422 | "id": 61, 423 | "first_name": "Ryley", 424 | "last_name": "Friar", 425 | "email": "rfriar1o@tinypic.com", 426 | "gender": "Male", 427 | "ip_address": "81.67.100.35" 428 | }, { 429 | "id": 62, 430 | "first_name": "Cleveland", 431 | "last_name": "Gillaspy", 432 | "email": "cgillaspy1p@mayoclinic.com", 433 | "gender": "Male", 434 | "ip_address": "171.105.170.116" 435 | }, { 436 | "id": 63, 437 | "first_name": "Ardelis", 438 | "last_name": "Chiles", 439 | "email": "achiles1q@quantcast.com", 440 | "gender": "Female", 441 | "ip_address": "35.139.191.158" 442 | }, { 443 | "id": 64, 444 | "first_name": "Chuck", 445 | "last_name": "Shirtcliffe", 446 | "email": "cshirtcliffe1r@wufoo.com", 447 | "gender": "Male", 448 | "ip_address": "164.186.17.229" 449 | }, { 450 | "id": 65, 451 | "first_name": "Parnell", 452 | "last_name": "Colman", 453 | "email": "pcolman1s@cmu.edu", 454 | "gender": "Male", 455 | "ip_address": "40.213.107.44" 456 | }, { 457 | "id": 66, 458 | "first_name": "Kacie", 459 | "last_name": "Bedow", 460 | "email": "kbedow1t@google.pl", 461 | "gender": "Female", 462 | "ip_address": "216.156.30.222" 463 | }, { 464 | "id": 67, 465 | "first_name": "Ruthe", 466 | "last_name": "Shortt", 467 | "email": "rshortt1u@state.tx.us", 468 | "gender": "Female", 469 | "ip_address": "33.240.249.100" 470 | }, { 471 | "id": 68, 472 | "first_name": "Gray", 473 | "last_name": "Hearnshaw", 474 | "email": "ghearnshaw1v@last.fm", 475 | "gender": "Male", 476 | "ip_address": "128.37.37.144" 477 | }, { 478 | "id": 69, 479 | "first_name": "Shanda", 480 | "last_name": "Ferrettino", 481 | "email": "sferrettino1w@independent.co.uk", 482 | "gender": "Female", 483 | "ip_address": "177.120.233.142" 484 | }, { 485 | "id": 70, 486 | "first_name": "Dania", 487 | "last_name": "Barbrook", 488 | "email": "dbarbrook1x@guardian.co.uk", 489 | "gender": "Female", 490 | "ip_address": "136.163.2.9" 491 | }, { 492 | "id": 71, 493 | "first_name": "Gail", 494 | "last_name": "Mourge", 495 | "email": "gmourge1y@dell.com", 496 | "gender": "Female", 497 | "ip_address": "217.181.223.216" 498 | }, { 499 | "id": 72, 500 | "first_name": "Jennee", 501 | "last_name": "Crannach", 502 | "email": "jcrannach1z@yandex.ru", 503 | "gender": "Female", 504 | "ip_address": "122.248.231.17" 505 | }, { 506 | "id": 73, 507 | "first_name": "Josephine", 508 | "last_name": "Hellings", 509 | "email": "jhellings20@army.mil", 510 | "gender": "Female", 511 | "ip_address": "12.185.145.209" 512 | }, { 513 | "id": 74, 514 | "first_name": "Damian", 515 | "last_name": "Sowley", 516 | "email": "dsowley21@biglobe.ne.jp", 517 | "gender": "Male", 518 | "ip_address": "160.249.230.252" 519 | }, { 520 | "id": 75, 521 | "first_name": "Caryl", 522 | "last_name": "McBeath", 523 | "email": "cmcbeath22@constantcontact.com", 524 | "gender": "Male", 525 | "ip_address": "172.202.18.179" 526 | }, { 527 | "id": 76, 528 | "first_name": "John", 529 | "last_name": "Dismore", 530 | "email": "jdismore23@newsvine.com", 531 | "gender": "Male", 532 | "ip_address": "59.74.28.46" 533 | }, { 534 | "id": 77, 535 | "first_name": "Molly", 536 | "last_name": "McCrann", 537 | "email": "mmccrann24@marriott.com", 538 | "gender": "Female", 539 | "ip_address": "98.14.223.108" 540 | }, { 541 | "id": 78, 542 | "first_name": "Happy", 543 | "last_name": "Leathart", 544 | "email": "hleathart25@wordpress.com", 545 | "gender": "Female", 546 | "ip_address": "180.116.158.237" 547 | }, { 548 | "id": 79, 549 | "first_name": "Rhetta", 550 | "last_name": "Herkess", 551 | "email": "rherkess26@ocn.ne.jp", 552 | "gender": "Female", 553 | "ip_address": "65.206.29.142" 554 | }, { 555 | "id": 80, 556 | "first_name": "Mariellen", 557 | "last_name": "Renyard", 558 | "email": "mrenyard27@gov.uk", 559 | "gender": "Female", 560 | "ip_address": "92.64.173.117" 561 | }, { 562 | "id": 81, 563 | "first_name": "Steward", 564 | "last_name": "Clulee", 565 | "email": "sclulee28@360.cn", 566 | "gender": "Male", 567 | "ip_address": "21.242.231.26" 568 | }, { 569 | "id": 82, 570 | "first_name": "Harriet", 571 | "last_name": "Hartill", 572 | "email": "hhartill29@paypal.com", 573 | "gender": "Female", 574 | "ip_address": "76.203.183.58" 575 | }, { 576 | "id": 83, 577 | "first_name": "Farra", 578 | "last_name": "Neenan", 579 | "email": "fneenan2a@ifeng.com", 580 | "gender": "Female", 581 | "ip_address": "57.196.13.26" 582 | }, { 583 | "id": 84, 584 | "first_name": "Cecilius", 585 | "last_name": "Huerta", 586 | "email": "chuerta2b@123-reg.co.uk", 587 | "gender": "Male", 588 | "ip_address": "114.251.113.60" 589 | }, { 590 | "id": 85, 591 | "first_name": "Friedrick", 592 | "last_name": "Skerm", 593 | "email": "fskerm2c@drupal.org", 594 | "gender": "Male", 595 | "ip_address": "199.99.12.102" 596 | }, { 597 | "id": 86, 598 | "first_name": "Bail", 599 | "last_name": "Todhunter", 600 | "email": "btodhunter2d@ow.ly", 601 | "gender": "Male", 602 | "ip_address": "12.27.130.69" 603 | }, { 604 | "id": 87, 605 | "first_name": "Maddalena", 606 | "last_name": "Mewha", 607 | "email": "mmewha2e@quantcast.com", 608 | "gender": "Female", 609 | "ip_address": "225.6.203.205" 610 | }, { 611 | "id": 88, 612 | "first_name": "Carney", 613 | "last_name": "Hurst", 614 | "email": "churst2f@yellowbook.com", 615 | "gender": "Male", 616 | "ip_address": "69.235.119.219" 617 | }, { 618 | "id": 89, 619 | "first_name": "Benedicto", 620 | "last_name": "Verman", 621 | "email": "bverman2g@cbslocal.com", 622 | "gender": "Male", 623 | "ip_address": "80.109.56.198" 624 | }, { 625 | "id": 90, 626 | "first_name": "Millicent", 627 | "last_name": "Chappelow", 628 | "email": "mchappelow2h@toplist.cz", 629 | "gender": "Female", 630 | "ip_address": "238.232.133.183" 631 | }, { 632 | "id": 91, 633 | "first_name": "Sherilyn", 634 | "last_name": "Lyddiard", 635 | "email": "slyddiard2i@wikispaces.com", 636 | "gender": "Female", 637 | "ip_address": "165.118.182.228" 638 | }, { 639 | "id": 92, 640 | "first_name": "Lana", 641 | "last_name": "Garrie", 642 | "email": "lgarrie2j@twitpic.com", 643 | "gender": "Female", 644 | "ip_address": "1.242.211.83" 645 | }, { 646 | "id": 93, 647 | "first_name": "Burtie", 648 | "last_name": "Milsap", 649 | "email": "bmilsap2k@plala.or.jp", 650 | "gender": "Male", 651 | "ip_address": "110.46.86.164" 652 | }, { 653 | "id": 94, 654 | "first_name": "Sheree", 655 | "last_name": "Cana", 656 | "email": "scana2l@sohu.com", 657 | "gender": "Female", 658 | "ip_address": "115.175.250.75" 659 | }, { 660 | "id": 95, 661 | "first_name": "Danny", 662 | "last_name": "Maasz", 663 | "email": "dmaasz2m@toplist.cz", 664 | "gender": "Male", 665 | "ip_address": "237.113.57.222" 666 | }, { 667 | "id": 96, 668 | "first_name": "Jody", 669 | "last_name": "Cicconetti", 670 | "email": "jcicconetti2n@bigcartel.com", 671 | "gender": "Female", 672 | "ip_address": "208.152.53.218" 673 | }, { 674 | "id": 97, 675 | "first_name": "Burton", 676 | "last_name": "Forster", 677 | "email": "bforster2o@weibo.com", 678 | "gender": "Male", 679 | "ip_address": "103.86.80.64" 680 | }, { 681 | "id": 98, 682 | "first_name": "Hale", 683 | "last_name": "Le Grove", 684 | "email": "hlegrove2p@yandex.ru", 685 | "gender": "Male", 686 | "ip_address": "233.141.56.182" 687 | }, { 688 | "id": 99, 689 | "first_name": "Hilliard", 690 | "last_name": "Cassam", 691 | "email": "hcassam2q@webmd.com", 692 | "gender": "Male", 693 | "ip_address": "76.41.190.160" 694 | }, { 695 | "id": 100, 696 | "first_name": "Nonnah", 697 | "last_name": "Inchbald", 698 | "email": "ninchbald2r@about.me", 699 | "gender": "Female", 700 | "ip_address": "85.119.6.147" 701 | }] 702 | -------------------------------------------------------------------------------- /src/tree.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import json 3 | import sys 4 | # https://stackoverflow.com/questions/40118113/how-to-convert-json-root-into-a-tree-image 5 | 6 | # Tree in JSON format 7 | s = '{"Harry": {"children": ["Bill", {"Jane": {"children": [{"Diane": {"children": ["Mary"]}}, "Mark"]}}]}}' 8 | 9 | # Convert JSON tree to a Python dict 10 | data = json.loads(s) 11 | 12 | # Convert back to JSON & print to stderr so we can verify that the tree is correct. 13 | print(json.dumps(data, indent=4), file=sys.stderr) 14 | 15 | # Extract tree edges from the dict 16 | edges = [] 17 | 18 | 19 | def get_edges(treedict, parent=None): 20 | # for name in tree.keys(): 21 | name = next(iter(treedict.keys())) 22 | print(name) 23 | if parent is not None: 24 | edges.append((parent, name)) 25 | for item in treedict[name]["children"]: 26 | if isinstance(item, dict): 27 | get_edges(item, parent=name) 28 | else: 29 | edges.append((name, item)) 30 | 31 | get_edges(data) 32 | 33 | # Dump edge list in Graphviz DOT format 34 | print('strict digraph tree {') 35 | for row in edges: 36 | print(' {0} -> {1};'.format(*row)) 37 | print('}') 38 | -------------------------------------------------------------------------------- /tutorial/File.md: -------------------------------------------------------------------------------- 1 | # Reading a JSON file 2 | 3 | To ease into things, let's start by creating a simple utility function to parse a JSON file; later we'll delve into how we can control the parsing in more detail. 4 | First, we consider how to read a JSON file into memory and print the file contents as a c string. For this example and many of the rest of the examples, I am going to use the JSON representation of a person taken from the aforementioned [Wikipedia article](https://en.wikipedia.org/wiki/JSON), [_*contact.json*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/contact.json): 5 | 6 | ```json 7 | { 8 | "firstName": "John", 9 | "lastName": "Smith", 10 | "isAlive": true, 11 | "age": 27, 12 | "address": { 13 | "streetAddress": "21 2nd Street", 14 | "city": "New York", 15 | "state": "NY", 16 | "postalCode": "10021-3100" 17 | }, 18 | "phoneNumbers": [ 19 | { 20 | "type": "home", 21 | "number": "212 555-1234" 22 | }, 23 | { 24 | "type": "office", 25 | "number": "646 555-4567" 26 | } 27 | ], 28 | "children": [], 29 | "spouse": null 30 | } 31 | 32 | ``` 33 | 34 | Now examine [_*json-file00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-file00.c): 35 | 36 | ```C 37 | #include 38 | #include 39 | 40 | int 41 | main(void) 42 | { 43 | json_object *root = json_object_from_file("contact.json"); 44 | if (!root) 45 | return 1; 46 | printf("The json file:\n\n%s\n", json_object_to_json_string(root)); 47 | json_object_put(root); 48 | return 0; 49 | } 50 | 51 | ``` 52 | Compile with: 53 | 54 | ``` 55 | gcc json-file00.c -ljson-c -o json-file00 56 | ``` 57 | 58 | Now run _*json-file00*_: 59 | 60 | ``` 61 | $ ./json-file00 62 | The json file: 63 | 64 | { "firstName": "John", "lastName": "Smith", "isAlive": true, "age": 27, "address": { "streetAddress": "21 2nd Street", "city": "New York", "state": "NY", "postalCode": "10021-3100" }, "phoneNumbers": [ { "type": "home", "number": "212 555-1234" }, { "type": "office", "number": "646 555-4567" } ], "children": [ ], "spouse": null } 65 | 66 | ``` 67 | 68 | Admittedly, the output is not very pretty, all extraneous whitespace has been stripped from the document. That may or may not be what you want in your application. Fortunately, json-c offers a little more control over the printing of the JSON object. 69 | 70 | Now lets look at our next program: [_*json-file01.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-file01.c). Compile with 71 | _*gcc json-file01.c -ljson-c -o json-file01*_: 72 | 73 | ```C 74 | #include 75 | #include 76 | 77 | int 78 | main(void) 79 | { 80 | json_object *root = json_object_from_file("contact.json"); 81 | if (!root) 82 | return 1; 83 | printf("The json file:\n\n%s\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 84 | json_object_put(root); 85 | return 0; 86 | } 87 | ``` 88 | 89 | The output from running _*json-file01*_ is: 90 | 91 | ``` 92 | $ ./json-file01 93 | The json file: 94 | 95 | { 96 | "firstName":"John", 97 | "lastName":"Smith", 98 | "isAlive":true, 99 | "age":27, 100 | "address":{ 101 | "streetAddress":"21 2nd Street", 102 | "city":"New York", 103 | "state":"NY", 104 | "postalCode":"10021-3100" 105 | }, 106 | "phoneNumbers":[ 107 | { 108 | "type":"home", 109 | "number":"212 555-1234" 110 | }, 111 | { 112 | "type":"office", 113 | "number":"646 555-4567" 114 | } 115 | ], 116 | "children":[ 117 | ], 118 | "spouse":null 119 | } 120 | 121 | ``` 122 | 123 | Here, the output is more readable having been reformatted somewhat, but it is certainly more suitable for human reading than before. Especially for more complex and long json files. 124 | 125 | So let's examine what we have learned from the code above. 126 | 127 | First and foremost, I have introduced a new 'type': _*json_object*_. As expected for a C program, _*json_object*_ is really an opaque structure whose internal implementation is not available in application code outside of the json-c library. Your code will only ever deal with a _pointer_ to a _*json_object*_, and all operations must be performed through the json-c API functions. Some programmers who wish to stress the idea _*json_object*_ is a *struct* would write the line of code: 128 | 129 | ```C 130 | json_object *root = json_object_from_file("contact.json"); 131 | ``` 132 | 133 | as 134 | 135 | ```C 136 | struct json_object *root = json_object_from_file("contact.json"); 137 | ``` 138 | 139 | That is a personal choice and do whichever you prefer. I prefer to leave the struct part off and think of it more like an additional basic type the library offers much like *int* or *float*. 140 | 141 | Next I introduce the function: 142 | 143 | - [json_object\* *json_object_from_file*(const char \*filename)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__util_8h.html#a03119ec0a71af4eee95318e9b2aaf05b) 144 | 145 | This function should be self-explanatory: It reads the file *filename* and returns the _*json_object*_ representing the JSON data contained in the file. If there is a failure to read the file, this function returns NULL. Of course, as we will later see json-c can also create a _*json_object*_ from a string (technically a NULL-terminated character array in C, not that I am pedantic enough to care). 146 | 147 | Now note, right before our program exits we have the function: 148 | 149 | - [void json_object_put(json_object \* obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#afabf61f932cd64a4122ca8092452eed5) 150 | 151 | We call this function on the json_object we created using *json_object_from_file*. You can think of this as freeing the memory allocated by creating the json_object. Technically though, the memory is only freed if the reference count of the object is zero. The official documentation states _*json_object_put*_ 152 | 153 | > Decrements the reference count of json\_object and frees if it reaches zero. You must have ownership of obj prior to doing this or you will cause an imbalance in the reference count. 154 | 155 | You may be thinking, "What is meant by _*ownership of an object*_?" More on that [latter](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/memory.md), but for now, note most of sample programs will follow this template: 156 | 157 | | Pseudo-Code | Ownership | 158 | | :-------------------------------------- | :------------------------------------------------------------------------------------------- | 159 | | Create or initialize a root JSON_object | _*at this point we own the object root and roots reference count is 1*_ | 160 | | Process JSON, saving or displaying JSON data as needed | _*we usually create or initialize other json objects here and transfer ownership of them to root. As longs as roots ownership is not transfered or shared with another object, roots reference count is unchanged*_ | 161 | | Dereference our JSON object | _*at this point we lose ownership of root and its reference count is decremented. If roots reference count is 0, roots memory and all objects owned by root with a reference count of 0 is freed*_ | 162 | 163 | Finally, I introduced 2 functions and a constant to convert the json_object to a string: 164 | 165 | - [const char\* json_object_to_json_string(json_object \*obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#ab7390c22baa1700d977c2af6b22d43a4) 166 | - [const char\* json_object_to_json_string_ext(json_object \*obj, int flags)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a9db613127bd4ef7db42307e43a85fc1b) 167 | - [JSON_C_TO_STRING_PRETTY](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a2025bc677c35f130e117dfda5bf1ef73) 168 | 169 | First, the constant _*JSON_C_TO_STRING_PRETTY*_ used in the function _*json_object_to_json_string_ext*_ as a _formatting flag_. There are 6 such flags, the remaining ones are: 170 | 171 | - [JSON_C_TO_STRING_PLAIN](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a3294cb92765cdeb497cfd346644d1059) 172 | - [JSON_C_TO_STRING_SPACED](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#aa821746c8668e6ad62bed90ec9e00103) 173 | - [JSON_C_TO_STRING_PRETTY_TAB](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#afc1486af21f6b1653c6f523025bdfd3b) 174 | - [JSON_C_TO_STRING_NOZERO](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a34f027c147babf69fc530d088f2b49b0) 175 | - [JSON_C_TO_STRING_NOSLASHESCAPE](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a5c11d72c55f3ab7c088f19e7bf118163) 176 | 177 | For information of the remaining flags your json-c version supports consult [the documentation](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html). 178 | 179 | These flags tell the function _*json_object_to_json_string_ext*_ how to format the JSON in the string representation. We have already seen the usage and effect of _*JSON_C_TO_STRING_PLAIN*_: The function _*json_object_to_json_string(obj)*_ is equivalent to _*json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED)*_. Here all superfluous white space is removed from the string representation. 180 | 181 | Now, to see the effect of using JSON_C_TO_STRING_SPACED edit the file json-file01.c and add it as the flag instead of _*JSON_C_TO_STRING_PRETTY*_. What do think it does? 182 | 183 | ## Problems 184 | 185 | 1. What happens if our json file contains invalid json and we run _*json-file01*_ ? Alter the program to print a message informing the user the json is invalid. 186 | -------------------------------------------------------------------------------- /tutorial/Intro.md: -------------------------------------------------------------------------------- 1 | # Intro 2 | 3 | Love it or hate it, JSON (JavaScript Object Notation) is ubiquitous these days as a file format. As its name implies, it was derived from JavaScript. Most programming languages provide support for it, either in the standard libraries or via third party libraries. JSON is simply a way of storing or exchanging data for use by a program in a human-readable text file. It is commonly used as a data format for transmitting data over the internet, as an ad hoc application configuration language and _*more*_. As a text format, JSON is completely language independent and uses conventions that are familiar to programmers of the C-family of languages. As such the data representation has a style similar to C structures. The data representation consists of name-value pairs (_*fields*_) and array data types. 4 | 5 | The following comment from [json.org](https://www.json.org/json-en.html) should clarify the concept of the JSON format for most programmers: 6 | 7 | > JSON is built on two structures: 8 | > 9 | > - A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array. 10 | > - An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence. 11 | 12 | In this tutorial, we are going to take a meandering path thru learning the [json-c](https://github.com/json-c/json-c) API. We will use functions as needed and perhaps not always do things the 'proper' way at first or at all. We will start playing with the code to get just a general sense of it, and then gradually learn more as time goes on. We'll try to keep the examples applicable to real-world problems and not just be toy snippets. It will be assumed you already know C well enough to get by and are comfortable compiling, linking, and running code. All of the needed JSON files and program source code discussed in this tutorial can be found in the [tutorial's github repo](https://github.com/rbtylee/tutorial-jsonc). 13 | 14 | If you are unfamiliar with JSON, it may be clearer to consider an actual example. The [JSON example below](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/contact.json) (taken from Wikipedia) is a possible representation of a person: 15 | 16 | ```json 17 | { 18 | "firstName": "John", 19 | "lastName": "Smith", 20 | "isAlive": true, 21 | "age": 27, 22 | "address": { 23 | "streetAddress": "21 2nd Street", 24 | "city": "New York", 25 | "state": "NY", 26 | "postalCode": "10021-3100" 27 | }, 28 | "phoneNumbers": [ 29 | { 30 | "type": "home", 31 | "number": "212 555-1234" 32 | }, 33 | { 34 | "type": "office", 35 | "number": "646 555-4567" 36 | } 37 | ], 38 | "children": [], 39 | "spouse": null 40 | } 41 | ``` 42 | 43 | The example above should be readable enough for most people to see what is going on. To make it even more clear below is the same JSON only represented as a tree, similar to the way a file manager lists your directory structure. 44 | 45 | !["JSON tree"](https://github.com/rbtylee/tutorial-jsonc/blob/master/Images/json-tree.png) 46 | 47 | For more information on JSON read the [Wikipedia article](https://en.wikipedia.org/wiki/JSON) or look over the [state diagrams](https://en.wikipedia.org/wiki/State_diagram) found on [json.org](https://www.json.org/json-en.html) describing the 'language'. The official standard describing the JSON format is [RFC 7159](https://tools.ietf.org/html/rfc7159). 48 | 49 | ## Problems 50 | 51 | 1. Create a JSON file representing three or more people, with each person containing the same attributes as the JSON example given above. Make sure you have a valid JSON file by using a JSON validation web site. 52 | 53 | - Create a C _*struct*_ to store the data contained in this JSON representation of a person. 54 | 55 | - Explain what is meant by this comment: 56 | >> "The JSON syntax is not a specification of a complete data interchange. Meaningful data interchange requires agreement between a producer and consumer on the semantics attached to a particular use of the JSON syntax. What JSON does provide is the syntactic framework to which such semantics can be attached." - [The JSON Data Interchange Syntax](https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf) 57 | 58 | - Do you have any programs installed that use JSON as a configuration file? If so examine the file. 59 | 60 | - What are some potential downsides of using JSON as a configuration file? 61 | 62 | - Do some research and find some websites with JSON as REST API responses. 63 | 64 | - Take a look at [jq](https://stedolan.github.io/jq/). Is this a tool you could use? 65 | 66 | - One of the more interesting uses of JSON is [Vega](https://vega.github.io/vega/): 67 | > Vega is a visualization grammar, a declarative language for creating, saving, and sharing interactive visualization designs. With Vega, you can describe the visual appearance and interactive behavior of a visualization in a JSON format, and generate web-based views using Canvas or SVG. 68 | 69 | Examine a few of the examples of try to implement one of them using python or javascript. 70 | -------------------------------------------------------------------------------- /tutorial/Json-c.md: -------------------------------------------------------------------------------- 1 | # json-c 2 | 3 | 4 | Json-c is a c library aiming to provide an object oriented like approach to using JSON objects in C. It aims to conform to RFC 7159 while being easy to use. Most of the memory management issues are handled by the library itself 'behind the scenes'. 5 | 6 | The home page for json-c: [https://github.com/json-c/json-c](https://github.com/json-c/json-c). 7 | 8 | This library allows one to easily construct JSON objects in C, read and write them, output them as JSON formatted strings and parse JSON formatted strings back into the C representation of JSON objects. 9 | 10 | Linux users may be able to install json-c using their OS's packaging system. However, doing so may not result in the most recent version of the library. Currently, that is **[json-c-0.15-20200726 ](https://github.com/json-c/json-c/releases/tag/json-c-0.15-20200726)**. For use with this tutorial, it is recommended you use at least version 0.13. Not all of the sample programs will compile with earlier versions. To install from source, see the installation instructions on the [json-c github page](https://github.com/json-c/json-c#buildunix). If you do install from source and wish to use the compiled version of json-c, as opposed to a version installed by your package manager, you are going to need to adjust the compilation instructions in this tutorial to reflect the prefix the compiled json-c is installed to. 11 | 12 | I will be using [Bodhi Linux 6.0](https://www.bodhilinux.com/) based on Ubuntu 20.04 as my Distro in this tutorial and gcc as my compiler. Usage of another compiler will not be discussed. Note, Bodhi 6.0 is currently unreleased but planned for this fall. So to install: 13 | 14 | ```sh 15 | sudo apt install libjson-c-dev 16 | ``` 17 | 18 | This installs all the development (header) files as well as the library itself (libjson-c4). As json-c is a commonly used library, the library itself is, in all likelihood, installed by default in a Linux distro (it is in Bodhi). 19 | 20 | For reference, the version installed is *0.13.1+dfsg-7ubuntu0.3*. Note, this corresponds to *Version 0.13.1*, released Mar 5, 2018, as is per the case for Ubuntu LTS releases. Rather dated but sufficient enough for this tutorial. 21 | 22 | Without much explanation, as it is rather self-explanatory, let's write our first json-c program, [_*json-version.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-version.c): 23 | 24 | ````C 25 | #include 26 | #include 27 | 28 | int 29 | main(void) 30 | { 31 | printf("Version: %s\n", json_c_version()); 32 | printf("Version Number: %d\n", json_c_version_num()); 33 | return 0; 34 | } 35 | ```` 36 | 37 | To compile: 38 | 39 | ``` 40 | gcc json-version.c -ljson-c -o json-version 41 | ``` 42 | 43 | The above gcc command assumes json-c was installed via the package manager. If json-c was compiled from source using the default prefix, to compile _*json-version.c*_ use the command below: 44 | 45 | ```sh 46 | gcc json-version.c -L/usr/local/lib -ljson-c -o json-version 47 | ``` 48 | 49 | Throughout the rest of this tutorial, compilation instructions are going to be given for only the case of a standard install via the package manager. 50 | 51 | Now run _*json-version*_ to see what version of json-c you have installed. Not very exciting but it is a start. 52 | 53 | Problem 54 | 55 | 1. How many packages in your distro depend upon json-c? How many of these are installed by default? Installed currently? 56 | -------------------------------------------------------------------------------- /tutorial/circular01.md: -------------------------------------------------------------------------------- 1 | # JSON Circular references 2 | 3 | After the previous two sections, you should be pretty clear on when to use json-c's _*put*_ and _*get*_ functions. In this section, we will examine one possible problem that can result from the reckless use of _*json_object_object_add*_. The problem is trying to create a JSON that contains a reference to itself. 4 | 5 | [Previously in a problem](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/new.md), you were asked to write a program to generate the following JSON: 6 | 7 | ```json 8 | { 9 | "items": 10 | { 11 | "properties": 12 | { 13 | "name": 14 | { 15 | "type": "unknown" 16 | } 17 | } 18 | }, 19 | "common": 20 | { 21 | "properties": null 22 | } 23 | } 24 | ``` 25 | 26 | Here is a possible solution, only it doesn't save the resulting JSON: 27 | 28 | ```C 29 | #include 30 | #include 31 | #include 32 | int 33 | main(void) 34 | { 35 | json_object *root = json_object_new_object(); 36 | if (!root) 37 | return 1; 38 | 39 | // main array 40 | json_object *items = json_object_new_object(); 41 | json_object_object_add(root, "items", items); 42 | // item 1 43 | 44 | json_object *properties = json_object_new_object(); 45 | json_object_object_add(items, "properties", properties); 46 | json_object *name = json_object_new_object(); 47 | json_object_object_add(properties, "name", name); 48 | json_object *type = json_object_new_string("unknown"); 49 | json_object_object_add(name, "type", type); 50 | 51 | items = json_object_new_object(); 52 | json_object_object_add(root, "common", items); 53 | json_object_object_add(items, "properties", NULL); 54 | 55 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 56 | 57 | // cleanup and exit 58 | json_object_put(root); 59 | return 0; 60 | } 61 | ``` 62 | 63 | Now change the line: 64 | ```C 65 | json_object_object_add(items, "properties", NULL 66 | ``` 67 | to 68 | ```C 69 | json_object_object_add(items, "properties", root); 70 | ``` 71 | 72 | This is a circular reference, the JSON object root contains a reference to itself in a field. The leads to infinite recursion and is an error situation. Json-c only checks for the simplist of errors of this sort. [This code](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-error00.c) will compile but naturally fails to run: 73 | 74 | ``` 75 | ~$ ./json-error00 76 | The json representation: 77 | 78 | (null) 79 | 80 | json-new02: json_object.c:189: json_object_put: Assertion `jso->_ref_count > 0' failed. 81 | Aborted (core dumped) 82 | ``` 83 | 84 | A programmer is unlikely to do anything this **obvious**. Yet by keeping or owning references to existing JSON objects and perhaps by having several pointers pointing to the same JSON object, it would be possible to introduce such a circular reference in a manner that is not so obvious. 85 | 86 | So view this section as a warning ... 87 | -------------------------------------------------------------------------------- /tutorial/edit.md: -------------------------------------------------------------------------------- 1 | # Editing a JSON objects 2 | 3 | In working with JSON, it may be the case one needs to edit an existing JSON. If it is a file, one can edit it in a text editor or by using classic Unix tools, sed et al. But it may be the case that the application you are working on needs to modify the JSON itself, whether the JSON is a file or merely an internal representation. 4 | 5 | Consider once again our _*contact.json*_, suppose John Smith got married to a young lady and adopted her daughter, plus his office phone number change and he had a birthday. Clearly, our JSON for John needs to be updated. 6 | 7 | Let's approach changing these values in the JSON in the order they appear in the JSON file. 8 | 9 | Since we are merely incrementing John's age, json-c fortunately provides an easy to use function for that: 10 | 11 | - int json_object_int_inc(json_object \*obj, int64_t val) 12 | 13 | Hence: 14 | 15 | ```C 16 | json_object *root = json_object_from_file("contact.json"); 17 | json_object *age = json_object_object_get(root, "age"); 18 | json_object_int_inc(age, 1); 19 | ``` 20 | 21 | This function can also decrement as the variable value can be negative. 22 | 23 | Next, we consider changing the office phone number in the JSON. Remember the _*phoneNumbers*_ attribute is a JSON array of two JSON objects: 24 | 25 | ```json 26 | "phoneNumbers": [ 27 | { 28 | "type": "home", 29 | "number": "212 555-1234" 30 | }, 31 | { 32 | "type": "office", 33 | "number": "646 555-4567" 34 | } 35 | ] 36 | ``` 37 | 38 | We wish to change the second JSON objects _*number*_ attribute's string to a new number, this array member has index 1. Just like C arrays, json-c starts indexing array elements at 0. Assume the new number is _843 276-3583_. 39 | 40 | The json-c library provides a set of functions of the form: _*json\_object\_set\_\**_. Such as the one we need for this case: 41 | 42 | - int json_object_set_string(json_object \*obj, const char \*new_value) 43 | 44 | Our code snippet then looks like: 45 | 46 | ```C 47 | json_object *root = json_object_from_file("contact.json"); 48 | 49 | json_object *phone_numbers = json_object_object_get(root, "phoneNumbers"); 50 | json_object *office = json_object_array_get_idx(phone_numbers, 1); 51 | json_object *number = json_object_object_get(office,"number"); 52 | json_object_set_string(number, "843 276-3583"); 53 | ``` 54 | 55 | And works as expected. 56 | 57 | Now we add the daughter. Recall the _*children*_ attribute of our JSON is also an array but in this case, it is empty: 58 | 59 | 60 | ```json 61 | "children": [] 62 | ``` 63 | 64 | Let the adopted daughter's name be _*Paige Crawford*_, age 15. As expected, the below snippet handles this case with ease: 65 | 66 | ```C 67 | json_object *root = json_object_from_file("contact.json"); 68 | 69 | json_object *children = json_object_object_get(root, "children"); 70 | json_object *paige = json_object_new_object(); 71 | json_object_object_add(paige, "name", json_object_new_string("Paige Crawford")); 72 | json_object_object_add(paige, "age", json_object_new_int(15)); 73 | json_object_array_add(children, paige); 74 | ``` 75 | 76 | Finally, let's add John's wife. If her name is Kate Smith, then you may think the problem would be as simple as: 77 | 78 | ```C 79 | json_object *root = json_object_from_file("contact.json"); 80 | json_object *spouse = json_object_object_get(root, "spouse"); 81 | json_object_set_string(spouse, "Kate Smith"); 82 | ``` 83 | 84 | But no, our JSON is unchanged by this. 85 | 86 | In both cases,in the json-c function,_*json_object_set_string*_, the JSON object type is checked and if it is not a _*json_type_string*_, 0 is returned and nothing is changed. If the type of the object is _*json_type_string*_, the object value is changed to new_value. 87 | 88 | Makes sense as _*spouse*_ is a JSON type NULL. But here it is a minor complication, solvable in this case by deleting the object first and then re-adding it: 89 | 90 | ```C 91 | json_object *root = json_object_from_file("contact.json"); 92 | json_object *spouse = json_object_object_get(root, "spouse"); 93 | json_object_object_del(root,"spouse"); 94 | json_object_object_add(root,"spouse",json_object_new_string("Kate Smith")); 95 | ``` 96 | 97 | Notice the introduction of the self-explanatory function: 98 | 99 | - void json_object_object_del (json_object \*obj, const char \*key) 100 | 101 | ## json-edit00.c 102 | 103 | Wrapping it up, our complete program, [_*json-edit00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-edit00.c): 104 | 105 | ```C 106 | #include 107 | #include 108 | 109 | int 110 | main(void) 111 | { 112 | json_object *root = json_object_from_file("contact.json"); 113 | 114 | printf("The json file:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 115 | // Edit age 116 | json_object *age = json_object_object_get(root, "age"); 117 | json_object_int_inc(age, 1); 118 | 119 | // Edit office phone number 120 | json_object *phone_numbers = json_object_object_get(root, "phoneNumbers"); 121 | json_object *office = json_object_array_get_idx(phone_numbers, 1); 122 | json_object *number = json_object_object_get(office,"number"); 123 | json_object_set_string(number, "843 276-3583"); 124 | // Add Daughter 125 | json_object *children = json_object_object_get(root, "children"); 126 | json_object *paige = json_object_new_object(); 127 | json_object_object_add(paige, "name", json_object_new_string("Paige Crawford")); 128 | json_object_object_add(paige, "age", json_object_new_int(15)); 129 | json_object_array_add(children, paige); 130 | 131 | // Add Wife 132 | json_object *spouse = json_object_object_get(root, "spouse"); 133 | json_object_object_del(root,"spouse"); 134 | json_object_object_add(root,"spouse",json_object_new_string("Kate Smith")); 135 | printf("The Edited JSON:\n\n%s\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 136 | 137 | 138 | json_object_put(root); 139 | return 0; 140 | } 141 | 142 | ``` 143 | 144 | Expected output: 145 | 146 | ``` 147 | $ ./json-edit00 148 | The json file: 149 | 150 | { 151 | "firstName":"John", 152 | "lastName":"Smith", 153 | "isAlive":true, 154 | "age":27, 155 | "address":{ 156 | "streetAddress":"21 2nd Street", 157 | "city":"New York", 158 | "state":"NY", 159 | "postalCode":"10021-3100" 160 | }, 161 | "phoneNumbers":[ 162 | { 163 | "type":"home", 164 | "number":"212 555-1234" 165 | }, 166 | { 167 | "type":"office", 168 | "number":"646 555-4567" 169 | } 170 | ], 171 | "children":[ 172 | ], 173 | "spouse":null 174 | } 175 | 176 | The Edited JSON: 177 | 178 | { 179 | "firstName":"John", 180 | "lastName":"Smith", 181 | "isAlive":true, 182 | "age":28, 183 | "address":{ 184 | "streetAddress":"21 2nd Street", 185 | "city":"New York", 186 | "state":"NY", 187 | "postalCode":"10021-3100" 188 | }, 189 | "phoneNumbers":[ 190 | { 191 | "type":"home", 192 | "number":"212 555-1234" 193 | }, 194 | { 195 | "type":"office", 196 | "number":"843 276-3583" 197 | } 198 | ], 199 | "children":[ 200 | { 201 | "name":"Paige Crawford", 202 | "age":15 203 | } 204 | ], 205 | "spouse":"Kate Smith" 206 | } 207 | 208 | ``` 209 | 210 | Problem: 211 | 212 | 1. Look over the _*json_object.h*_ header file or the documentation for other functions of the form: json\_object\_set\_* for the remaining JSON types. Write some sample code and if necessary a sample JSON files, showing how to use a few of these not adressed here. 213 | 214 | 2. What happens if the order of _*spouse*_ is not at the end of the JSON? 215 | 216 | 3. Write a function: 217 | - _json_object_set_string 218 | 219 | like the json-c library function, json_object_set_string except if the JSON obj is not a string replaces it with a string. How many arguments does it need if it is implemented as deleting the object and readding it. 220 | 221 | -------------------------------------------------------------------------------- /tutorial/edit2.md: -------------------------------------------------------------------------------- 1 | # JSON Pointers 2 | 3 | Examining [_*json-edit00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-edit00.c), one may note the code for changing John's office phone number seems unduly complex: 4 | 5 | ```C 6 | json_object *root = json_object_from_file("contact.json"); 7 | 8 | json_object *phone_numbers = json_object_object_get(root, "phoneNumbers"); 9 | json_object *office = json_object_array_get_idx(phone_numbers, 1); 10 | json_object *number = json_object_object_get(office,"number"); 11 | json_object_set_string(number, "843 276-3583"); 12 | ``` 13 | 14 | Imagine how much more complex it would become in a JSON where objects are nested much more deeply. Surely there must be an easier way to access or modify JSON objects deeply nested within another JSON object. This is where JSON pointers come in: a JSON pointer uses a string syntax for identifying a specific value within a JSON object. 15 | 16 | Consider again our example, John's Office phone number. For the JSON represented by our _*contact.json*_ file, the string "_*/phoneNumbers/1/number*_" is a JSON pointer to the value of his office number. 17 | 18 | ```json 19 | { 20 | "firstName": "John", 21 | ... 22 | "phoneNumbers": [ 23 | { 24 | "type": "home", 25 | "number": "212 555-1234" 26 | }, 27 | { 28 | "type": "office", 29 | "number": "646 555-4567" 30 | } 31 | ], 32 | ... 33 | } 34 | 35 | ``` 36 | 37 | The '1' in the JSON pointer, "_*/phoneNumbers/1/number*_" is the array index, as the JSON object _*phoneNumbers*_ is an array. The rest of the string should be clear. For a full describtion of the JSON pointer standard, see [RFC 6901](https://tools.ietf.org/html/rfc6901). Don't worry it looks more complex than it is. 38 | 39 | The json-c library, version 0.13 or later, has several functions which support this standard: 40 | 41 | - [int json_pointer_get(json_object *obj, const char *path, json_object **res)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__pointer_8h.html#aff88937e32b0ba6ffbd07cb4b1919053) 42 | - [int json_pointer_getf(json_object *obj, json_object **res, const char *path_fmt,...)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__pointer_8h.html#af0ac03df64b215d05041e8007ed0233d) 43 | 44 | - [int json_pointer_set(json_object **obj, const char *path, json_object *value)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__pointer_8h.html#aef0e651f63ce5ce35648503705e2586b) 45 | - [int json_pointer_setf(json_object **obj, json_object *value, const char *path_fmt,...)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__pointer_8h.html#a66f1f98a2ce085c19f6750193b4c726d) 46 | 47 | 48 | We have two sets of functions, one set to retrieve the value given the JSON pointer and one to set the value. 49 | 50 | For more details on these functions, please consult the [documentation](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__pointer_8h.html). 51 | 52 | So here is the original code to change the office phone number: 53 | 54 | ```C 55 | json_object *root = json_object_from_file("contact.json"); 56 | 57 | json_object *phone_numbers = json_object_object_get(root, "phoneNumbers"); 58 | json_object *office = json_object_array_get_idx(phone_numbers, 1); 59 | json_object *number = json_object_object_get(office,"number"); 60 | json_object_set_string(number, "843 276-3583"); 61 | ``` 62 | 63 | and here is the JSON pointer version: 64 | 65 | ```C 66 | json_object *root = json_object_from_file("contact.json"); 67 | 68 | json_pointer_set(&root, "/phoneNumbers/1/number", json_object_new_string("843 276-3583")); 69 | 70 | ``` 71 | 72 | As you can see the usage of these functions is pretty clear. If you need more examples look at the file [_*test_json_pointer.c*_](https://github.com/json-c/json-c/blob/master/tests/test_json_pointer.c) in the json-c source code itself. 73 | 74 | 75 | -------------------------------------------------------------------------------- /tutorial/equal.md: -------------------------------------------------------------------------------- 1 | # JSON Comparison 2 | 3 | Now for something easier. What does it mean for two JSON objects to be equal? 4 | 5 | To test for equality of two JSON objects json-c provides the function: 6 | 7 | - int json_object_equal(json_object *obj1, json_object *obj2) 8 | 9 | From the documentation: 10 | 11 | > If the passed objects are equal 1 will be returned. Equality is defined as follows: 12 | > - json_objects of different types are never equal 13 | > - json_objects of the same primitive type are equal if the c-representation of their value is equal 14 | > - json-arrays are considered equal if all values at the same indices are equal (same order) 15 | > - Complex json_objects are considered equal if all contained objects referenced by their key are equal, regardless their order. 16 | 17 | ## json-equal00.c 18 | 19 | As expected some sample code.[_*json-equal00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-equal00.c) illustrating the usage of this function: 20 | 21 | ```C 22 | #include 23 | #include 24 | 25 | int 26 | main(void) 27 | { 28 | const char *filename = "example01.json"; 29 | json_object *item, *location; 30 | 31 | json_object *doc1 = json_object_new_object(); 32 | // JSON Document 1 33 | json_object_object_add(doc1, "firstName", json_object_new_string("John")); 34 | json_object_object_add(doc1, "lastName", json_object_new_string("Smith")); 35 | json_object_object_add(doc1, "age", json_object_new_int(27)); 36 | printf("Document 1:\n\n%s\n\n", json_object_to_json_string_ext(doc1, JSON_C_TO_STRING_PRETTY)); 37 | json_object *doc2 = json_object_new_object(); 38 | // JSON Document 2 39 | json_object_object_add(doc2, "age", json_object_new_int(27)); 40 | json_object_object_add(doc2, "firstName", json_object_new_string("John")); 41 | json_object_object_add(doc2, "lastName", json_object_new_string("Smith")); 42 | printf("Document 2:\n\n%s\n\n", json_object_to_json_string_ext(doc2, JSON_C_TO_STRING_PRETTY)); 43 | 44 | if (json_object_equal(doc1,doc2)) 45 | printf("Documents are equal!\n"); 46 | else 47 | printf("Documents are NOT equal!\n"); 48 | // cleanup and exit 49 | json_object_put(doc1); 50 | json_object_put(doc2); 51 | return 0; 52 | } 53 | 54 | ``` 55 | -------------------------------------------------------------------------------- /tutorial/index.md: -------------------------------------------------------------------------------- 1 | # Json-c Tutorial Index 2 | 3 | - [Intro](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/Intro.md) 4 | * [contact.json](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/contact.json) introduced 5 | - [Json-c](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/Json-c.md) 6 | * Installation 7 | * Print version:[ _*json-version.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-version.c) 8 | - [Reading a JSON file](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/File.md) 9 | * Read contact.json from a file and print the JSON: [_*json-file00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-file00.c) 10 | * Read contact.json from a file and print the JSON: [_*json-file01.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-file01.c) 11 | - [Parsing a Json object - part 1: Intro](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/legacy.md) 12 | * Read contact.json and print 2 name/attribute pairs: [_*json-parse00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse00.c) 13 | * Simple reference count example: [_*json-parse01.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse01.c) 14 | - [JSON_types](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/types.md) 15 | * Print types of the JSON objects in contact.json: [_*json-type00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-type00.c) 16 | - [Parsing a Json object - part 2 complex parsing](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/parsing2.md) 17 | * Print all values of all objects in contact.json: [_*json-parse04.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse04.c) 18 | - [Parsing a Json object - part 3: Json strings](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/parsing3.md) 19 | * Create a JSON object from a string and print it: [_*json-str00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-str00.c) 20 | * Print all values of all objects in contact.json: [_*json-parse05.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse05.c) (left as excersise) 21 | - Curl/url example 22 | * use curl or ecore_con_url 23 | - [Parsing a Json object - part 4: Iteration through a JSON obj](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/parsing4.md) 24 | * Illustrate iteration over a JSON object: example 25 | * Print all values of all objects in contact.json yet again: [_*json-parse06.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse06.c) 26 | - [Creating and saving a JSON object](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/new.md) 27 | * Create, initialize and save a JSON: [_*json-new00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-new00.c) 28 | - [Editing a JSON Object](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/edit.md) 29 | * Change attribute values in a JSON: [_*json-edit00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-edit00.c) 30 | - [Memory management, ownership and references - part one: overview](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/memory.md) 31 | * Clarify these issues and answer the question of when to call json_object_put or json_object_get 32 | - [Memory management, ownership and references - part two: examples](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/memory01.md) 33 | * Code illustrating memory issues. 34 | * [_*json-mem00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-mem00.c) 35 | * [_*json-mem01.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-mem01.c) 36 | - [JSON Circular references](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/circular01.md) 37 | * An example of a circular reference: [_*json-error00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-error00.c) 38 | - [JSON Comparison](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/equal.md) 39 | * Compare two JSONs for equality: [_*json-equal00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-equal00.c) 40 | - JSON Copying 41 | * 42 | - [JSON Arrays: basics](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/list.md) 43 | * A JSON array by itself is valid JSON: [_*json-array00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array00.c) 44 | * Deleting a JSON array value: [_*json-array01.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array01.c) 45 | * Looping over all JSON array values: [_*json-array02.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array02.c) 46 | - [JSON Arrays: sorting and searching](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/sort.md) 47 | * Sorting and searching a JSON array: [_*json-array03.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array03.c) 48 | - [JSON Pointers](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/edit2.md) 49 | * Introduce using JSON pointers 50 | - [Parsing a Json object - part 5: Iterators](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/parsing5.md) 51 | * Bettter Encapsulation using iterators 52 | - [Parsing a Json object - part 6: Iteration yet again](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/parsing6.md) 53 | * Loop through an array: [_*json-array04.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array04.c) 54 | * Illustrate a depth-first search: [_*json-parse10.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse10.c) 55 | * Search a JSON for a particular value: [_*json-parse11.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse11.c) 56 | - Error handling 57 | - threads 58 | - debugging 59 | - automake and meson 60 | 61 | -------------------------------------------------------------------------------- /tutorial/legacy.md: -------------------------------------------------------------------------------- 1 | # Parsing a Json object - part 1: Intro 2 | 3 | Printing a json\_object is rather boring and mostly useful for debugging purposes. Naturally one would expect a JSON library to include functions to make extracting the needed data from the JSON file as easy and simple as possible. 4 | 5 | So let's examine [_*contact.json*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/contact.json) again: 6 | 7 | ```json 8 | { 9 | "firstName": "John", 10 | "lastName": "Smith", 11 | "isAlive": true, 12 | "age": 27, 13 | "address": { 14 | "streetAddress": "21 2nd Street", 15 | "city": "New York", 16 | "state": "NY", 17 | "postalCode": "10021-3100" 18 | }, 19 | "phoneNumbers": [ 20 | { 21 | "type": "home", 22 | "number": "212 555-1234" 23 | }, 24 | { 25 | "type": "office", 26 | "number": "646 555-4567" 27 | } 28 | ], 29 | "children": [], 30 | "spouse": null 31 | } 32 | ``` 33 | Suppose we wish to read this JSON file and print only the first and last name. Examine [_*json-parse00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse00.c) below. Compile with _*gcc json-parse00.c -ljson-c -o json-parse00*_: 34 | 35 | ```C 36 | #include 37 | #include 38 | 39 | int 40 | main(void) 41 | { 42 | json_object *root = json_object_from_file("contact.json"); 43 | if (!root) 44 | return 1; 45 | 46 | json_object *first_name = json_object_object_get(root, "firstName"); 47 | json_object *last_name = json_object_object_get(root, "lastName"); 48 | printf("%s, %s\n", json_object_get_string(last_name), json_object_get_string(first_name)); 49 | 50 | json_object_put(root); 51 | return 0; 52 | } 53 | ``` 54 | 55 | The expected output from execution: 56 | 57 | ``` 58 | $ ./json-parse00 59 | Smith, John 60 | 61 | ``` 62 | 63 | Now depending upon what json-c version you have installed when compiling this file you may get depreciated function warnings: 64 | 65 | ``` 66 | $ gcc json-parse00.c -ljson-c -o json-parse00 67 | json-parse00.c: In function ‘main’: 68 | json-parse00.c:13:4: warning: ‘json_object_object_get’ is deprecated [-Wdeprecated-declarations] 69 | json_object *first_name = json_object_object_get(root, "firstName"); 70 | ^~~~~~~~~~~ 71 | In file included from /usr/include/json-c/linkhash.h:16:0, 72 | from /usr/include/json-c/json.h:22, 73 | from json-parse00.c:4: 74 | /usr/include/json-c/json_object.h:290:1: note: declared here 75 | THIS_FUNCTION_IS_DEPRECATED(extern struct json_object* json_object_object_get(struct json_object* obj, 76 | 77 | ``` 78 | 79 | I will address this issue in a bit, but first let's examine the two new functions used in the code above. 80 | 81 | - [json_object\* json\_object\_object\_get(json_object \* obj, const char \*key)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a1a097805abb53b4c8a60d573730a8939) 82 | - [const char\* json_object_get_string(json_object \*obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a9ee29ca8d79896e15007131527f6002e) 83 | 84 | 85 | ## json_object_object_get 86 | The first function, _*json\_object\_object\_get(obj, key)*_, simply returns the _*json_object*_ associated with the given key. When you're done with the returned json_object there's no need to release it with a _*json_object_put()*_ as no reference counts are changed. According to the documentation, "Ownership of the returned value is retained by obj. " This means that if the owning object is freed (by a _*json_object_put(obj)*_ function call then any usage of the _*json_object*_ returned by 87 | _*json_object_object_get(obj, key)*_ will return garbage as this pointer is no longer valid. 88 | 89 | In our example, we have 90 | 91 | ```C 92 | json_object *first_name = json_object_object_get(root, "firstName"); 93 | ``` 94 | 95 | If we wish to keep the _*json_object \*first_name*_ *AFTER* executing _*json_object_put(root)*_, we must use the function _*json_object_get(first_name)* *BEFORE* executing the _*json_object_put(root)*_ command!! If we gain ownership of _*json_object \*first_name*_ and do not transfer that ownership to another JSON object, then we must latter lose that ownership with a _*json_object_put(first_name)*_ statement. 96 | 97 | This point is very important. To see this play around with the code some by moving the line _*json_object_put(root);*_ around in the source and then again after adding some _*json_object_get*_ function calls on the appropriate objects. Each time not only execute the binary file but also run the code through [_*Valgrind*_](https://www.valgrind.org/). 98 | 99 | Hopefully, all this is clear by now. If not, we will [later](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/memory.md) [examine](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/memory01.md) the concept of ownsership and references in quite a bit of detail. 100 | 101 | So let's examine what the function _*json_object_object_get(obj, key)*_ actually does. In our case the line of code: 102 | 103 | ```C 104 | json_object *first_name = json_object_object_get(root, "firstName"); 105 | ``` 106 | 107 | looks through the _*json_object*_ root, which is the internal memory representation of our file contact.json for an attribute called _*firstName*_ and returns the _*json_object*_ representing the value of this attribute: "John". 108 | 109 | You can see this if you insert the statement below into the code: 110 | 111 | ```C 112 | printf("%s\n", json_object_to_json_string_ext(first_name, JSON_C_TO_STRING_PRETTY)); 113 | ``` 114 | 115 | Why does it not simply return the string itself with no quotes? Because remember a _*json_object*_ is not necessarily always a string. It can be a number, a boolean, an array of _*json_objects*_, or even another _*json_object*_ . In general, we don't know unless we know the _*semantics*_ of the JSON data being parsed in advance or have some way of testing the _*type*_ of the _*json_object*_ . (More on JSON types latter). 116 | 117 | !["JSON state diagram for values"](https://github.com/rbtylee/tutorial-jsonc/blob/master/Images/value.png) 118 | 119 | What about error handling you might ask? What happens if the function _*json_object_object_get(obj, key)*_ is unable to find the value associate with the key in the _*json_object*_? In this case, NULL is returned. Again play with the code to see the results of such an invalid search. In production code, we would include some error handling code. 120 | 121 | ## json\_object\_get\_string 122 | 123 | It should be intuitively clear what the function _*json\_object\_get_string(obj)*_ does. It simply returns the string value (const char*) of the _*json_object*_. According to the docs: 124 | >If the passed object is not of type json\_type_string then the JSON representation of the object is returned. 125 | 126 | Hence, it is safe to call this function with a NULL object, in which case (null) is returned. 127 | 128 | It is important to note that the returned "string memory is managed by the json\_object and will be freed when the reference count of the json\_object drops to zero." Therefore, if one wishes to 'keep' the value of this string around, one has to store it in a char array. For example, [_*json-parse01.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse01.c): 129 | 130 | ```C 131 | #include 132 | #include 133 | #include 134 | #include 135 | 136 | int 137 | main(void) 138 | { 139 | char *fname, *lname; 140 | json_object *root = json_object_from_file("contact.json"); 141 | if (!root) 142 | return 1; 143 | 144 | json_object *first_name = json_object_object_get(root, "firstName"); 145 | json_object *last_name = json_object_object_get(root, "lastName"); 146 | // Store the string values of these json_objects in our char arrays 147 | fname = strdup(json_object_get_string(first_name)); 148 | lname = strdup(json_object_get_string(last_name)); 149 | // Lose ownership of our json_objects first_name and last_name 150 | json_object_put(root); 151 | // Verify our char arrays still have the proper values 152 | printf("%s, %s\n", fname, lname); 153 | // Cleanup 154 | free(fname); 155 | free(lname); 156 | return 0; 157 | } 158 | 159 | ``` 160 | 161 | Compile as usual (_*gcc json-parse01.c -ljson-c -o json-parse01*_) 162 | Verify this works as expected and does not leak memory using Valgrind. 163 | 164 | ## json_object_object_get_ex 165 | 166 | We noted the function _*json_object_object_get(obj, key)*_ may throw depreciated function warnings json-c version 0.12. This function was depreciated then but latter this warning was removed. There are no issues with using this function. 167 | 168 | However, an alternative to _*json_object_object_get(obj, key)*_ is the function _*json_object_object_get_ex*_. It will compile warning free in json-c 0.12. 169 | 170 | - [json_bool json_object_object_get_ex(json_object \*obj, const char *key, json_object \*\*value)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a90d5f16d58636f01d2ed1a6030c7366a) 171 | 172 | ## json_bool 173 | 174 | Note: this introduces a new type. _*json_bool*_, clearly as expected merely a convenience to deal with Boolean values. 175 | 176 | We have 177 | ```C 178 | typedef int json_bool; 179 | ``` 180 | While some versions of json-c have TRUE and FALSE macros defined you probably shouldn't use them as they have removed in version 0.14. Many other libraries also provide similar 'types' and values for booleans. 181 | 182 | Clearly the function _*json_object_object_get_ex(obj, key, &value)*_ returns TRUE (1) on success and FALSE (0) otherwise. 183 | 184 | ## json_object_object_get_ex 185 | 186 | So here is _*json-parse00.c*_ refactored using this new function: 187 | 188 | ```C 189 | #include 190 | #include 191 | 192 | int 193 | main(void) 194 | { 195 | json_object *first_name, *last_name; 196 | json_object *root = json_object_from_file("contact.json"); 197 | if (!root) 198 | return 1; 199 | 200 | json_object_object_get_ex(root, "firstName", &first_name); 201 | json_object_object_get_ex(root, "lastName", &last_name); 202 | printf("%s, %s\n", json_object_get_string(last_name), json_object_get_string(first_name)); 203 | json_object_put(root); 204 | return 0; 205 | } 206 | 207 | ``` 208 | 209 | As usual save this file as _*json-parse02.c*_. Compile and execute ( _*gcc json-parse02.c -ljson-c -o json-parse02*_ ). 210 | 211 | No compiler warnings and the code is only marginally more complex. 212 | 213 | ## Problems 214 | 215 | 1. Rewrite json-parse00.c with proper error checks on the returned values before the print statements. In other words, if the key is not found do not print (null) for either the first name and last name. 216 | 217 | -------------------------------------------------------------------------------- /tutorial/list.md: -------------------------------------------------------------------------------- 1 | # JSON Arrays: basics 2 | 3 | The json-c library provides some convenience functions to sort and perform a binary search of a JSON array. But first, let us review and expand upon what we currently know about JSON arrays and their implementation in the json-c library. As such JSON arrays resemble arrays in JavaScript or lists in Python. 4 | 5 | According to [The JSON Data Interchange Standard](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf): 6 | > An array structure is a pair of square bracket tokens surrounding zero or more values. The values are separated by commas. The JSON syntax does not define any specific meaning to the ordering of the values. However, the JSON array structure is often used in situations where there is some semantics to the ordering. 7 | 8 | A few valid JSON arrays: 9 | 10 | ```json 11 | ["foobar", "foo", "bar"] 12 | ``` 13 | 14 | ```json 15 | ["foo", "bar", 32, null] 16 | ``` 17 | 18 | ```json 19 | [ 20 | { 21 | "type": "home", 22 | "number": "212 555-1234" 23 | }, 24 | { 25 | "type": "office", 26 | "number": "646 555-4567" 27 | }, 28 | true 29 | ] 30 | ``` 31 | 32 | ## Arrays as JSON Objects 33 | 34 | In JSON, an array is a list of values, each a valid JSON type. This means a JSON array can not contain an attribute/value pair. For example, the following is a valid JSON: 35 | 36 | ```json 37 | { "age":32 } 38 | ``` 39 | While the below is an invalid JSON array: 40 | 41 | ```json 42 | [ "age":32 ] 43 | ``` 44 | 45 | JSON array values must be a valid JSON type, that is, of type string, number, object, array, boolean or null. Unlike arrays in C, JSON array values within an array do not all have to be the same type. However, in json-c JSON array values are all the same type, they are all _*json_objects*_. But the _*json_objects*_ an array contains in json-c have different _*json_types*_ corresonding to the C type of the data the _*json_obect*_ contains. Each data item being limited to a C type corresponding to a string, number, JSON object, JSON array, boolean or null. 46 | 47 | Recall our discussion in [JSON_types](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/types.md): 48 | 49 | The json-c library has an enumerated type [_*json_type*_](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__types_8h.html) which can be used with the appropriate function to test a _*json_object*_ in order to determine its type in advance. We have the following '_types_' defined: 50 | 51 | - json_type_null 52 | - json_type_boolean 53 | - json_type_double 54 | - json_type_int 55 | - json_type_object 56 | - json_type_array 57 | - json_type_string 58 | 59 | Note, in the JSON standards we only have one numeric type defined, _number_. Whereas in C, a [_typed_](https://en.wikipedia.org/wiki/Strong_and_weak_typing) language, we need to distinguish between ints, floats, doubles, et al. Json-c therefore distinguishes between _*json_type_int*_ and _*json_type_double*_. Furthermore, since the JSON standards have two boolean types, _true_ and _false_, and C completely lacks a boolean type, the type _*json_type_boolean*_ is in reality, an *int* in the json-c representation. Remember we have: 60 | 61 | ```C 62 | typedef int json_bool; 63 | ``` 64 | 65 | ### json-array00.c 66 | 67 | An important thing to note is a JSON array by itself is valid JSON. 68 | 69 | Consider [_*json-array00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array00.c): 70 | 71 | ```C 72 | #include 73 | #include 74 | 75 | int 76 | main(void) 77 | { 78 | json_object *root = json_tokener_parse("[\"foo\", \"bar\", 32, null]"); 79 | printf("The json string:\n\n%s\n\n", json_object_to_json_string(root)); 80 | 81 | printf("The json object to string:\n\n%s\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 82 | 83 | json_object_put(root); 84 | 85 | return 0; 86 | } 87 | ``` 88 | 89 | ## Accessing and Deleting Array Values 90 | 91 | You access the array values by using the value's index number. Json-c provides two functions to access a JSON arrays value, one to get the value, and one to set the value as well as a function to delete the value (or values) at a specified index: 92 | 93 | - [json_object\* json_object_array_get_idx(json_object \*obj, int idx)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a676711a76545d4ec65cc75f100f5fd19) 94 | - [int json_object_array_put_idx(json_object *obj, size_t idx, json_object *val)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a1ac0ccdbc13a25da7d8b2dc9e421dfad) 95 | - [int json_object_array_del_idx(json_object *obj, size_t idx, size_t count)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a722eca9f578704d3af38b97549242c1f) 96 | 97 | ### json-array01.c 98 | 99 | Notice that the _*json_object_array_get_idx*_ returns the _*json_object*_ at the specified index. For example, if json_object_array_get_idx(root, 2) returns a _*json_object*_ of type _*json_type_int*_, to actually access the integer one has to use: 100 | 101 | ```C 102 | i = json_object_get_int(json_object_array_get_idx(root, 2)) 103 | ``` 104 | 105 | Likewise, we can not set a JSON array value at a specific index unless the value is a _*json_object*_. For example, we have: 106 | 107 | ```C 108 | json_object_array_put_idx(root, 2, json_object_new_string("foobar")) 109 | ``` 110 | and not: 111 | 112 | ```C 113 | json_object_array_put_idx(root, 2, "foobar") 114 | ``` 115 | If one tries the latter, the program will compile with a warning and if executed crash: 116 | 117 | ``` 118 | Segmentation fault (core dumped) 119 | ``` 120 | Also as per the documentation, unlike a C array, one can use _*json_object_array_put_idx*_ to set an index bigger than the length of the current array: 121 | 122 | > The array size will be automatically be expanded to the size of the index if the index is larger than the current size. 123 | 124 | In this instance, all of the missing array values that will be added during the expansion of the array are NULL (_*json_type_null*_) 125 | 126 | To illustrate the usage of these functions, [_*json-array01.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array01.c): 127 | 128 | ```C 129 | #include 130 | #include 131 | 132 | int 133 | main(void) 134 | { 135 | json_object *root = json_tokener_parse("[\"foo\", \"bar\", 32, null]"); 136 | 137 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 138 | 139 | int val = json_object_get_int(json_object_array_get_idx(root, 2)); 140 | printf("The third value of the array is: %d\n\n", val); 141 | 142 | printf("Modifying the third value and deleting the fourth.\n\n"); 143 | json_object_array_put_idx(root, 2, json_object_new_string("foobar")); 144 | json_object_array_del_idx(root, 3, 1); 145 | 146 | printf("The json representation is now:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 147 | 148 | json_object_put(root); 149 | 150 | return 0; 151 | } 152 | 153 | ``` 154 | 155 | **Note:** in the section [JSON Pointers](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/edit2.md) we will see yet another method for accessing an arrays value at a specified index. 156 | 157 | ## Looping Through an Array 158 | 159 | Recall the function _*doarray*_ in program [_*json-parse07.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse07.c). Note this function loops through the given JSON array in the same fashion as one loops thru a C array. 160 | 161 | To illustrate in slightly simpler code, [_*json-array02.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array02.c): 162 | 163 | ```C 164 | #include 165 | #include 166 | 167 | int 168 | main(void) 169 | { 170 | const char *str; 171 | json_object *root = json_tokener_parse("[\"foo\", \"bar\", 32, null]"); 172 | 173 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 174 | 175 | int n = json_object_array_length(root); 176 | for (int i=0; i Increment the reference count of json_object, thereby grabbing shared ownership of obj. 24 | 25 | Recall the function _*json_object_put()*_ decrements the reference count of a JSON object: 26 | 27 | - [int json_object_put(json_object \*obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#afabf61f932cd64a4122ca8092452eed5) 28 | 29 | Again from the documentation: 30 | 31 | > Decrement the reference count of json_object and free if it reaches zero. 32 | > You must have ownership of obj prior to doing this or you will cause an imbalance in the reference count. 33 | > 34 | > An obj of NULL may be passed; in that case this call is a no-op. 35 | > 36 | > Returns 1 if the object was freed. 37 | 38 | In addition to json_object_put, we can also delete an attribute/value pair within a JSON object: 39 | 40 | - [void json_object_object_del(json_object * obj, const char *key)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#ac6605fdafca20bd5d33c84f4f80a3bda) 41 | 42 | > Deletes the given attribute/value pair within json_object *obj for the attribute key if it exist. 43 | > 44 | > The reference count will be decremented for the deleted object. If there are no more owners of the value represented by this key, then the value is freed. Otherwise, the reference to the value will remain in memory. 45 | 46 | And likewise we can do the same for one or more json objects within a JSON array: 47 | 48 | - [void json_object_array_del_idx(json_object *obj, size_t idx, size_t count) ](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a722eca9f578704d3af38b97549242c1f) 49 | 50 | > Delete count number of elements from a specified index, idx, in a JSON array. And as expected the reference count will be decremented for each of the deleted objects. If there are no more owners of an element that is being deleted, then the value is freed. Otherwise, the reference to the value will remain in memory. 51 | > 52 | >When one creates a new JSON object, its reference count is 1 and the caller of this object initially owns it. There is no need to call json_object_get on a newly created JSON object unless you lose ownership of the object but want to maintain ownership for some latter usage. 53 | 54 | You may think that for every json_object_get there should eventually follow a json_object_put, much like the classic c way of following an malloc with a free at some latter point. However, not only is this **not always the case** it is **not usually the case**. 55 | 56 | How exactly does one transfer ownership of a JSON object? 57 | 58 | By using any of the following functions: 59 | 60 | - [json_object_object_add()](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a27bd808a022251059a43f1f6370441cd) 61 | - [json_object_object_add_ex()](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a57d3e444dd7db6b4510d21bf3716a002) 62 | - [json_object_array_add()](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a18cdd9a7455e09f36cdf6e5756b7f586) 63 | 64 | >No reference counts are changed for the above functions, but the ownership is transferred. 65 | 66 | But ownership is not affected by the following functions, nor are reference counts changed: 67 | 68 | - [json_object_object_get()](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a1a097805abb53b4c8a60d573730a8939) or [json_object_object_get_ex()](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a90d5f16d58636f01d2ed1a6030c7366a) 69 | - [json_object_array_put_idx()](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a1ac0ccdbc13a25da7d8b2dc9e421dfad) 70 | 71 | As previously [noted](https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/File.md), most of sample programs will follow this template: 72 | 73 | | Pseudo-Code | Ownership | 74 | | :-------------------------------------- | :------------------------------------------------------------------------------------------- | 75 | | Create or initialize a root JSON_object | _*at this point we own the object root and roots reference count is 1*_ | 76 | | Process JSON, saving or displaying JSON data as needed | _*we usually create or initialize other json objects here and transfer ownership of them to root. As longs as roots ownership is not transfered or shared with another object, roots reference count is unchanged*_ | 77 | | Dereference our JSON object | _*at this point we lose ownership of root and its reference count is decremented. If roots reference count is 0, roots memory and all objects owned by root with a reference count of 0 is freed*_ | 78 | 79 | 80 | This is the [same point](https://github.com/json-c/json-c/issues/642#issuecomment-656326298) made by [Pierce Lopez](https://github.com/ploxiln), only his answer is more detailed. Read it carefully and make sure you understand it: 81 | 82 | > Typically, you create a tree of json objects, either by parsing text with a tokener, or by creating-and-adding them one-by-one. Typically, every object in the tree will have one reference, from it's parent. When you are done with the tree of objects, you put() just the root object, and that put()s its child objects automatically, and that frees the entire tree in a cascading manner from a single put(). This is pretty simple. You can get a reference to a single child and copy its value in just a few lines, while obviously not freeing the parent, without dealing with any reference count changes, and this is safe. 83 | > 84 | > You can take a reference to a sub-section of the object tree and use it for a non-trivial amount of time, perhaps after the original object tree was freed, by get()ing root of the sub-tree to increase it's "reference count" ... then you can treat it as an independent object tree. But you may not have to do this, depending on your application. 85 | 86 | It is highly recommended you use Valgrind to check for memory errors, especially if you are somewhat confused by the above discussion. 87 | 88 | In our next section, we will consider some concrete code examples to illustrate some of the above. 89 | -------------------------------------------------------------------------------- /tutorial/memory01.md: -------------------------------------------------------------------------------- 1 | # Memory management, ownership and references - part two: examples 2 | 3 | If you are feeling somewhat confused by the previous discussion, this section will consider some concrete examples to illustrate the concepts of _*ownership*_ and _*references*_. To best utilize this section, one needs to be somewhat familiar with using to the tool _*Valgrind*_. 4 | 5 | Recall the previous statement: 6 | >You may think that for every json_object_get there should eventually follow a json_object_put, much like the classic c way of following an malloc with a free at some latter point. However, we will see this is not always the case. 7 | 8 | The example below shows a user case where one reuses the same JSON object by adding it several times to the same JSON document. 9 | 10 | Here is the JSON document we wish to create: 11 | 12 | ```json 13 | { 14 | "items":[ 15 | { 16 | "id":3201, 17 | "status":"online" 18 | }, 19 | { 20 | "id":4678, 21 | "status":"online" 22 | }, 23 | { 24 | "id":2345, 25 | "status":"online" 26 | } 27 | ] 28 | } 29 | ``` 30 | 31 | We see the field _*"status": "online"*_ occurs three times in this JSON. Suppose we just want to create one JSON object for this attribute/pair instead of using three separate JSON objects with the same content. Examine [_*json-mem00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-mem00.c) which follows. 32 | 33 | First, create the needed JSON string: 34 | 35 | ```C 36 | json_object *str = json_object_new_string("online"); 37 | ``` 38 | 39 | At this point we _*own*_ the object _*str*_ and its reference count is 1. 40 | 41 | Next, add it the first item in the JSON array _*items*_: 42 | 43 | ```C 44 | json_object_object_add(item, "status", str); 45 | ``` 46 | 47 | After adding _*str*_ to the JSON object _*item*_, _*item*_ now _*owns*_ our JSON string, _*str*_ and _*str*_ still has a reference count of 1. We no longer own _*str*_. 48 | 49 | The documentation for _*json_object_object_add*_ states: 50 | > Upon calling this, the ownership of val transfers to obj. Thus you must make sure that you do in fact have ownership over this object. 51 | 52 | So before we can add _*str*_ to the remaining items in the JSON array _*items*_, we need to re-acquire _*ownership*_ of the JSON object. That is, we need a _*json_object_get(str)*_ statement before we try to add _*str*_ to another JSON object. So the remaining two times we add _*str*_ to an item in the _*items*_ array we must use: 53 | 54 | ```C 55 | json_object_get(str); 56 | json_object_object_add(item, "status", str); 57 | ``` 58 | 59 | Each time we do this, the reference count for _*str*_ will be incremented. 60 | Hence right before the program exits and immediately before the _*json_object_put(root)*_ statement, _str*_ has a reference count of 3. One for each time it was used in our JSON document. 61 | 62 | The statement _*json_object_put(root)*_ decrements the reference count of the JSON object _*root*_. Since _*root*_ has only been referenced once in our program by the initial _*json_object *root = json_object_new_object()*_, the reference count for _*root*_ goes to 0. Hence, _*root*_ is freed and all objects owned by root have their reference count decremented and those with a reference count of zero are also freed. The result is everything contained within _*root*_ is freed. 63 | 64 | Though you won't have explicit, individual calls to _*json_object_put()*_ in the application code, when _*json_object_put(root)*_ is executed the json-c library _*internally*_ performs roughly the following steps: 65 | 66 | * json_object_put(items) 67 | * json_object_put(item <1st one>) 68 | * json_object_put() 69 | * json_object_put(str) (refcount decremented, not yet freed) 70 | * json_object_put(item <2nd one>) 71 | * json_object_put() 72 | * json_object_put(str) (refcount decremented, not yet freed) 73 | * json_object_put(item <3rd one>) 74 | * json_object_put() 75 | * json_object_put(str) (refcount decremented, now it's 0, so it is freed) 76 | 77 | **Note:** at no point did we in the application code have to _*json_object_put(str)*_ explicitly, as the management of _*str's*_ memory was handled by the json-c library when the _*json_object_put(root)*_ statement was executed. So as promised, we can see why it is not necessarily the case that for every _*json_object_get*_ there should eventually follow a _*json_object_put*_. It all depends upon the _*ownership*_ of the object. 78 | 79 | What about the usage of _*str*_ after the execution of _*json_object_put(root)*_? The pointer _*str*_ is no longer valid. Trying to use it after the json_object_put statement is a _*use-after-free error*_, exactly as if one attempted to do: 80 | 81 | ```C 82 | char \*str = malloc(10); free(str); \*str = 'x';. 83 | ``` 84 | 85 | ## json-mem00.c 86 | 87 | ```C 88 | #include 89 | #include 90 | 91 | int 92 | main(void) 93 | { 94 | json_object *items, *item, *str; 95 | 96 | json_object *root = json_object_new_object(); 97 | if (!root) 98 | return 1; 99 | 100 | // main array 101 | items = json_object_new_array(); 102 | json_object_object_add(root, "items", items); 103 | // item 1 104 | item = json_object_new_object(); 105 | json_object_object_add(item, "id", json_object_new_int(3201)); 106 | str = json_object_new_string("online"); 107 | json_object_object_add(item, "status", str); 108 | json_object_array_add(items, item); 109 | 110 | // item 2 111 | item = json_object_new_object(); 112 | json_object_object_add(item, "id", json_object_new_int(4678)); 113 | json_object_get(str); 114 | json_object_object_add(item, "status", str); 115 | json_object_array_add(items, item); 116 | // item 3 117 | item = json_object_new_object(); 118 | json_object_object_add(item, "id", json_object_new_int(2345)); 119 | json_object_get(str); 120 | json_object_object_add(item, "status", str); 121 | json_object_array_add(items, item); 122 | 123 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 124 | 125 | // cleanup and exit 126 | json_object_put(root); 127 | return 0; 128 | } 129 | ``` 130 | 131 | As usual, compile and execute this program. Run the binary through Valgrind to ensure there are no memory errors. 132 | 133 | Now experiment with removing one or more of the _*json_object_get(str)*_ statements in _*json-mem00.c*_. Does the code compile? Does it run? What does valgrind report? 134 | 135 | 136 | ## json-mem01.c 137 | 138 | There's an alternate approach: call _*json_object_get(str)*_ before *each* of the _*json_object_object_add(item, "status", str)*_ calls, even the first one, and then add a _*json_object_put(str)*_ at the end. In a more complicated program, one where maybe the code to add each item is factored out into a separate function, this can result in a more natural flow. 139 | 140 | To illustrate this approach examine [_*json-mem01.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-mem01.c) below, each new item is added to the items array in a seperate function, _*json_object \*new_item(int id, json_object \*str)*_. The function _*new_item*_ ensures it has ownership of _*str*_ when adding _*str*_ to the JSON object _*item*_ by calling _*json_object_get(str)*_. 141 | 142 | ```C 143 | #include 144 | #include 145 | 146 | #define NUM_ID_ITEMS 3 147 | 148 | json_object * 149 | new_item(int id, json_object *str) 150 | { 151 | json_object *item = json_object_new_object(); 152 | json_object_object_add(item, "id", json_object_new_int(id)); 153 | json_object_object_add(item, "status", json_object_get(str)); 154 | return item; 155 | } 156 | 157 | int 158 | main(void) 159 | { 160 | json_object *items, *str; 161 | int id[3] = {3201, 4678, 2345}; 162 | 163 | json_object *root = json_object_new_object(); 164 | if (!root) 165 | return 1; 166 | 167 | // main array 168 | items = json_object_new_array(); 169 | json_object_object_add(root, "items", items); 170 | str = json_object_new_string("online"); 171 | 172 | // Add Items 173 | for(int i=0; i - Using an object field or array index (retrieved through _*json_object_object_get*_ or _*json_object_array_get_idx*_) beyond the lifetime of the parent object. 191 | > - Detaching an object field or array index from its parent object (using _*json_object_object_del*_ or _*json_object_array_del_idx*_) 192 | > - Sharing a json_object with multiple (not necesarily parallel) threads of execution that all expect to free it (with _*json_object_put*_) when they're done. 193 | 194 | -------------------------------------------------------------------------------- /tutorial/new.md: -------------------------------------------------------------------------------- 1 | # Creating and saving a JSON object 2 | 3 | It is perhaps traditional when discussing an Object-Oriented library to first introduce creating and deleting a new object. But, we have taken a backward approach: Introducing initializing a json\_object from a file or string first and then going to parsing the JSON data contained within. Now it is time to introducing creating a new JSON object, adding data to it and saving it as a file. 4 | 5 | ## Json Constructors 6 | 7 | Not surprisingly, the constructor for a new _*json_object*_ is: 8 | 9 | - [json_object\* json_object_new_object(void)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a68c383f54544fca19b5f2425be397600) 10 | 11 | The (latest) documentation states this function creates: 12 | 13 | >a new empty object with a reference count of 1. The caller of this object initially has sole ownership. Remember, when using json_object_object_add or json_object_array_put_idx, ownership will transfer to the object/array. Call json_object_get if you want to maintain shared ownership or also add this object as a child of multiple objects or arrays. Any ownerships you acquired but did not transfer must be released through json_object_put. 14 | 15 | 16 | Consider: 17 | 18 | ```C 19 | #include 20 | #include 21 | 22 | int 23 | main(void) 24 | { 25 | json_object *root = json_object_new_object(); 26 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 27 | 28 | json_object_put(root); 29 | return 0; 30 | } 31 | ``` 32 | 33 | The expected output of the above program: 34 | 35 | ``` 36 | $ ./json-example 37 | The json representation: 38 | 39 | { 40 | } 41 | 42 | ``` 43 | 44 | After creating a _*json\_object*_, you usually intialize it with the data you want to store in it. Remember that the data is always in name/value pairs where name is a string and value is another _*json_object*_ of a particular _*json_type*_. The json-c function for this operation is: 45 | 46 | - [void json_object_object_add(json_object *obj, const char * key, json_object *val)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a27bd808a022251059a43f1f6370441cd) 47 | 48 | 49 | Consider the code snippet: 50 | 51 | ```C 52 | json_object *root = json_object_new_object(); 53 | json_object_object_add(root, "id", NULL); 54 | ``` 55 | 56 | This creates the JSON: 57 | 58 | ```json 59 | { 60 | "id":null 61 | } 62 | ``` 63 | 64 | This example covers the user case of adding a key with _*json\_type\_null*_ value to a *_json\_object*_. 65 | 66 | Functions for adding other *_json\_types*_ are listed below and their usage should be intuitively obvious: 67 | 68 | - [json_object\* json_object_new_boolean(json_bool b)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a2e290acd80e72cca745f89fb4600fb78) 69 | - [json_object\* json_object_new_double(double d)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a594a093bafb9091f843da3197e0638aa) 70 | - [json_object\* json_object_new_double_s(double d)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a594a093bafb9091f843da3197e0638aa) 71 | - [json_object\* json_object_new_int(int32_t i)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#ae92f0770fb4b3c884ce35de52d3d7de8) 72 | - [json_object\* json_object_new_int64(int64_t i)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a7847f74494645c2b076505c37cc4cb93) 73 | - [json_object\* json_object_new_object(void)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a68c383f54544fca19b5f2425be397600) 74 | - [json_object\* json_object_new_array(void)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a84f7f8c0774c4600d958561d7548d649) 75 | - [json_object\* json_object_new_string(const char \*s)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a7b7b5302b3903c9347eeb1f4a64d657b) 76 | - [json_object\* json_object_new_string_len(const char \*s, int len)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a778a1aa34a508d08daac3bdb83e24b52) 77 | - [json_object\* json_object_new_null(void)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a29e23b5be729c679960242b3b81bcde0) 78 | 79 | ## Adding elements to json arrays 80 | 81 | - [int json_object_array_add(json_object \* obj, json_object \* val)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a18cdd9a7455e09f36cdf6e5756b7f586) 82 | 83 | This function returns 0 on success and -1 on failure. 84 | 85 | ## json-new00.c 86 | 87 | As an example of using these functions along with a new function to write the JSON to your disk, consider the program, [_*json-new00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-new00.c), below. This program creates a new contact JSON file with the same JSON structure as our _*contact.json*_. It prints the JSON and saves it to the hard drive. 88 | 89 | ```C 90 | #include 91 | #include 92 | 93 | int 94 | main(void) 95 | { 96 | const char *filename = "contact2.json"; 97 | json_object *root = json_object_new_object(); 98 | if (!root) 99 | return 1; 100 | 101 | // basic data 102 | json_object_object_add(root, "firstName", json_object_new_string("Bart")); 103 | json_object_object_add(root, "lastName", json_object_new_string("Johnson")); 104 | json_object_object_add(root, "isAlive", json_object_new_boolean(TRUE)); 105 | json_object_object_add(root, "age", json_object_new_int(57)); 106 | // address json 107 | json_object *address = json_object_new_object(); 108 | json_object_object_add(address, "streetAddress", json_object_new_string("105 Murdock")); 109 | json_object_object_add(address, "city", json_object_new_string("Princeton")); 110 | json_object_object_add(address, "state", json_object_new_string("WV")); 111 | json_object_object_add(address, "postalCode", json_object_new_string("24740")); 112 | json_object_object_add(root, "address", address); 113 | // phone numbers array 114 | json_object *phone_numbers = json_object_new_array(); 115 | json_object_object_add(root, "phoneNumbers", phone_numbers); 116 | // home 117 | json_object *phone_home = json_object_new_object(); 118 | json_object_object_add(phone_home, "type", json_object_new_string("home")); 119 | json_object_object_add(phone_home, "number", json_object_new_string("304-888-5686")); 120 | json_object_array_add(phone_numbers, phone_home); 121 | // cell 122 | json_object *phone_cell = json_object_new_object(); 123 | json_object_object_add(phone_cell, "type", json_object_new_string("cell")); 124 | json_object_object_add(phone_cell, "number", json_object_new_string("304-888-3023")); 125 | json_object_array_add(phone_numbers, phone_cell); 126 | 127 | // children array 128 | json_object *children = json_object_new_array(); 129 | json_object_object_add(root, "children", children); 130 | // daughter 131 | json_object *justine = json_object_new_object(); 132 | json_object_object_add(justine, "name", json_object_new_string("Justine Johnson")); 133 | json_object_object_add(justine, "age", json_object_new_int(29)); 134 | json_object_array_add(children, justine); 135 | 136 | // spouse 137 | json_object_object_add(root, "spouse", json_object_new_string("Bobbi Johnson")); 138 | 139 | // print json 140 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 141 | // save json 142 | if (json_object_to_file(filename, root)) 143 | printf("Error: failed to save %s!!\n", filename); 144 | else 145 | printf("%s saved.\n", filename); 146 | 147 | // cleanup and exit 148 | json_object_put(root); 149 | return 0; 150 | } 151 | 152 | ``` 153 | 154 | Expected output: 155 | 156 | ``` 157 | $ ./json-new00 158 | The json representation: 159 | 160 | { 161 | "firstName":"Bart", 162 | "lastName":"Johnson", 163 | "isAlive":true, 164 | "age":57, 165 | "address":{ 166 | "streetAddress":"105 Murdock", 167 | "city":"Princeton", 168 | "state":"WV", 169 | "postalCode":"24740" 170 | }, 171 | "phoneNumbers":[ 172 | { 173 | "type":"home", 174 | "number":"304-888-5686" 175 | }, 176 | { 177 | "type":"cell", 178 | "number":"304-888-3023" 179 | } 180 | ], 181 | "children":[ 182 | { 183 | "name":"Justine Johnson", 184 | "age":29 185 | } 186 | ], 187 | "spouse":"Bobbi Johnson" 188 | } 189 | 190 | contact2.json saved. 191 | 192 | ``` 193 | 194 | By now you know what to do here ... 195 | 196 | ## Problems 197 | 198 | 1. What happens if _*json\_object \*address*_ is NULL in the above code, _*json-new00.c*_? Refactor the code above to prevent all such unlikely but serious cases of that happening. 199 | 2. Write a json-c program to create and save the following json: 200 | ```json 201 | { 202 | "items": 203 | { 204 | "properties": 205 | { 206 | "name": 207 | { 208 | "type": "unknown" 209 | } 210 | } 211 | }, 212 | "common": 213 | { 214 | "properties": null 215 | } 216 | } 217 | 218 | ``` 219 | 220 | -------------------------------------------------------------------------------- /tutorial/parsing2.md: -------------------------------------------------------------------------------- 1 | # Parsing a JSON object - part 2 complex parsing 2 | 3 | At this point in the tutorial, we have almost all the tools needed to completely parse the file _*contact.json*_. 4 | 5 | However, there is some ambiguity in the file _*contact.json*_ we need to address first. 6 | 7 | Consider the two attributes, "children" and "spouse": 8 | ```json 9 | "children": [], 10 | "spouse": null 11 | ``` 12 | For *children*, assume a value of null means _*No Children*_ whereas an empty array means _*Unknown*_. 13 | Where there are children, record the full name and age, for each child: 14 | 15 | ```json 16 | "children": [ 17 | { 18 | "name": "Tammy Smith", 19 | "age": 3 20 | }, 21 | { 22 | "name": "Judah Smith", 23 | "age": 7 24 | } 25 | ] 26 | ``` 27 | For Spouse, a value of null will mean _*No Spouse Known*_. 28 | Where a spouse is known, record the full name and age as in: 29 | 30 | ```json 31 | "spouse": { 32 | "name": "Amanda Smith", 33 | "age": 23 34 | } 35 | ``` 36 | 37 | ## Some needed Array functions 38 | 39 | With the ambiguity issue addressed, we proceed to read every value of every field in our contact.json file and print the results. To accomplish this we first need to determine the length of a json\_array in order to deal with the **Children** attribute. Json-c provides a function much like _*json_object_get_string_len*_ only for json_arrays: 40 | 41 | - [int json_object_array_length(json_object \*obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#ab9ea8f9c72d5adf83fdcbfe69f97fa44) 42 | 43 | The usage of this function is should be intuitively clear. It does what it says it does. 44 | 45 | Once we know the length of a json\_array, we have to be able to loop through every _*json_object*_ the array contains. That is we need some function to _index_ the json_array. Hence: 46 | 47 | - [json_object\* json_object_array_get_idx(json_object \*obj, int idx)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a676711a76545d4ec65cc75f100f5fd19) 48 | 49 | This function retrieves and returns the element at the specified index of the json_array or in the case of failure returns NULL. 50 | 51 | With these two functions now _under our belt_ the rest is just *grunt work*: 52 | 53 | ## json-parse04.c 54 | 55 | ```C 56 | #include 57 | #include 58 | 59 | int 60 | main(void) 61 | { 62 | int temp_n; 63 | json_object *root, *temp; 64 | 65 | root = json_object_from_file("contact.json"); 66 | if (!root) 67 | return 1; 68 | 69 | json_object *first_name = json_object_object_get(root, "firstName"); 70 | printf("First name: %s\n", json_object_get_string(first_name)); 71 | json_object *last_name = json_object_object_get(root, "lastName"); 72 | printf("Last name: %s\n", json_object_get_string(last_name)); 73 | json_object *is_alive = json_object_object_get(root, "isAlive"); 74 | printf("Is Alive: %s\n", json_object_get_boolean(is_alive)? "yes": "No"); 75 | json_object *age = json_object_object_get(root, "age"); 76 | printf("Age: %d\n", json_object_get_int(age)); 77 | 78 | printf("Address:\n"); 79 | json_object *address = json_object_object_get(root, "address"); 80 | json_object *st_address = json_object_object_get(address, "streetAddress"); 81 | printf("\tStreet Address: %s\n", json_object_get_string(st_address)); 82 | json_object *city = json_object_object_get(address, "city"); 83 | printf("\tCity: %s\n", json_object_get_string(city)); 84 | json_object *state = json_object_object_get(address, "state"); 85 | printf("\tState: %s\n", json_object_get_string(state)); 86 | json_object *zip = json_object_object_get(address, "postalCode"); 87 | printf("\tZip Code %s\n", json_object_get_string(zip)); 88 | 89 | printf("Phone Numbers:\n"); 90 | json_object *phone_numbers = json_object_object_get(root, "phoneNumbers"); 91 | temp_n = json_object_array_length(phone_numbers); 92 | for (int i = 0; i < temp_n; i++) 93 | { 94 | temp = json_object_array_get_idx(phone_numbers, i); 95 | json_object *type = json_object_object_get(temp, "type"); 96 | json_object *number = json_object_object_get(temp, "number"); 97 | printf("\tPhone number %d: %s: %s\n", i, json_object_get_string(type), json_object_get_string(number)); 98 | } 99 | 100 | printf("Children:\n"); 101 | json_object *children = json_object_object_get(root, "children"); 102 | if (json_object_get_type(children) == json_type_null) 103 | printf("\tNo children\n"); 104 | else 105 | { 106 | temp_n = json_object_array_length(children); 107 | if (temp_n) 108 | for (int i = 0; i < temp_n; i++) 109 | { 110 | temp = json_object_array_get_idx(children, i); 111 | json_object *name = json_object_object_get(temp, "name"); 112 | printf("\t Name: %s\n", json_object_get_string(name)); 113 | age = json_object_object_get(temp, "age"); 114 | printf("\t Age: %d\n\n", json_object_get_int(age)); 115 | } 116 | else 117 | printf("\tUnknown\n"); 118 | } 119 | 120 | printf("Spouse:\n"); 121 | json_object *spouse = json_object_object_get(root, "spouse"); 122 | if (json_object_get_type(spouse) == json_type_null) 123 | printf("\tNo Spouse Known\n"); 124 | else 125 | { 126 | json_object *name = json_object_object_get(spouse, "name"); 127 | printf("\t Name: %s\n", json_object_get_string(name)); 128 | age = json_object_object_get(spouse, "age"); 129 | printf("\t Age: %d\n\n", json_object_get_int(age)); 130 | } 131 | 132 | json_object_put(root); 133 | return 0; 134 | } 135 | 136 | ``` 137 | 138 | Compile and execute [_*json-parse04.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse04.c) above. 139 | 140 | Note: latter a simpler solution to this problem will be presented. 141 | 142 | Problems 143 | 144 | 1. Change the values if the children and/or spouse fields in _*contact.json*_ following the conventions introduced above to eliminate the ambiguity of our file. Rerun json-parse04 on the new JSON file. Does it properly handle all possible cases? 145 | 146 | - Refactor _*json-parse04.c*_ to store the json values in a C struct. 147 | 148 | - Write a classic C program that does the same thing as _*json-parse04.c*_ using only functions found in the C standard library. Simplicity is better than a complex solution. Depending upon your programming ability, this may be a difficult problem. 149 | 150 | - If you have completed the above problem, discuss the pros and cons of using your classic C solution verses a json-c implementation. 151 | -------------------------------------------------------------------------------- /tutorial/parsing3.md: -------------------------------------------------------------------------------- 1 | # Parsing a Json object - part 3: JSON strings 2 | 3 | At last, we have all the tools needed to parse a JSON file. Yet, the most common usage of json is to request the data from a website, download the data, and store it in a string. Parsing, processing, and displaying the data are the last things we do. For such usage, we wouldn't use the _*json\_object\_from\_file*_ function. Admittedly we could: download the file and store it somewhere and then load the file into a JSON object. All this is unnecessary, wasteful, and slow. Json-c has a function to create a _*json\_object*_ from a C string: 4 | 5 | - [json_object* json_tokener_parse(const char *str) ](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__tokener_8h.html#a236ef64d079822a4411d13eae7190c4d) 6 | 7 | The usage of this function is rather simple. 8 | 9 | Consider [_*json-str00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-str00.c): 10 | 11 | ```C 12 | #include 13 | #include 14 | 15 | int 16 | main(void) 17 | { 18 | char * str = "{\"firstName\" : \"John\", \"lastName\" : \"Smith\", \"email\":[{\"type\": \"personal\",\"url\": \"johnsmith0321@gmail.com\"},{\"type\": \"office\",\"url\": \"johnsmith@frankford.com\"} ] }"; 19 | json_object *root = json_tokener_parse(str); 20 | printf("The json string:\n\n%s\n\n", json_object_to_json_string(root)); 21 | 22 | printf("The json object to string:\n\n%s\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 23 | json_object_put(root); 24 | return 0; 25 | } 26 | 27 | ``` 28 | 29 | Once compiled and executed, the results: 30 | 31 | ``` 32 | $ ./json-str00 33 | The json string: 34 | 35 | { "firstName": "John", "lastName": "Smith", "email": [ { "type": "personal", "url": "johnsmith0321@gmail.com" }, { "type": "office", "url": "johnsmith@frankford.com" } ] } 36 | 37 | The json object to string: 38 | 39 | { 40 | "firstName":"John", 41 | "lastName":"Smith", 42 | "email":[ 43 | { 44 | "type":"personal", 45 | "url":"johnsmith0321@gmail.com" 46 | }, 47 | { 48 | "type":"office", 49 | "url":"johnsmith@frankford.com" 50 | } 51 | ] 52 | } 53 | 54 | ``` 55 | 56 | Not much to say here, other than it is a hassle to escape all the quote characters in a JSON representation for usage in a C program. However, this is not a problem for downloading and storing JSON from the internet. 57 | 58 | Problem: 59 | 60 | 1. Take _*json-parse04.c*_ previously discussed and add the macro below and use _*json\_tokener\_parse(SAMPLE_JSON)*_ instead of _*json\_object\_from_file*_. Save the file as _*json-parse05.c*_. 61 | 62 | Verify everything works as before: 63 | 64 | ```C 65 | #define SAMPLE_JSON \ 66 | "{" \ 67 | " \"firstName\": \"John\"," \ 68 | " \"lastName\": \"Smith\"," \ 69 | " \"isAlive\": true," \ 70 | " \"age\": 27," \ 71 | " \"address\": {" \ 72 | " \"streetAddress\": \"21 2nd Street\"," \ 73 | " \"city\": \"New York\"," \ 74 | " \"state\": \"NY\"," \ 75 | " \"postalCode\": \"10021-3100\"" \ 76 | " }," \ 77 | " \"phoneNumbers\": [" \ 78 | " {" \ 79 | " \"type\": \"home\"," \ 80 | " \"number\": \"212 555-1234\"" \ 81 | " }," \ 82 | " {" \ 83 | " \"type\": \"office\"," \ 84 | " \"number\": \"646 555-4567\"" \ 85 | " }" \ 86 | " ]," \ 87 | " \"children\": [" \ 88 | " {" \ 89 | " \"name\": \"Tammy Smith\"," \ 90 | " \"age\": 3" \ 91 | " }," \ 92 | " {" \ 93 | " \"name\": \"Judah Smith\"," \ 94 | " \"age\": 7" \ 95 | " }" \ 96 | " ]," \ 97 | " \"spouse\": {" \ 98 | " \"name\": \"Amanda Smith\"," \ 99 | " \"age\": 23" \ 100 | " }" \ 101 | "}" 102 | 103 | ``` 104 | 105 | -------------------------------------------------------------------------------- /tutorial/parsing4.md: -------------------------------------------------------------------------------- 1 | # Parsing a Json object - part 4: Iteration through a JSON obj 2 | 3 | Looking at the parsing code discussed so far, you might wonder if there is an easier way to parse the file rather than checking every attribute one at a time. Since we have been printing out the values for every attribute in the JSON file or string, shouldn't it be possible to simply iterate over the objects name/value pairs? Similar to a for loop only for json\_objects. 4 | 5 | The answer is, naturally, yes. 6 | 7 | In json-c, this is implemented as a macro: [_*json_object_object_foreach*_](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#acf5f514a9e0061c10fc08055762639ee). Typical usage is of the form: 8 | 9 | ```C 10 | json_object_object_foreach(obj, key, val) 11 | { 12 | // processing code goes here 13 | } 14 | ``` 15 | 16 | Where obj is the JSON object you want to parse; key and value correspond to key: value pairs. However, key and value are placeholders and not actual variables that you have to declare. They are declared by the macro itself, and you can use them inside the loop. Key is a char\* and val is a json_object\*. You can choose any _variable_ names to correspond to key and value if you wish. 17 | 18 | ## json_object_object_foreach: json-parse06.c 19 | 20 | The simple program below illustrates the usage of this macro. 21 | 22 | ```C 23 | #include 24 | #include 25 | 26 | int main(void) 27 | { 28 | json_object *root = json_object_from_file("contact.json"); 29 | json_object_object_foreach(root, key, val) 30 | printf("%s -> %s\n", key, json_object_get_string(val)); 31 | 32 | json_object_put(root); 33 | return 0; 34 | } 35 | 36 | ``` 37 | 38 | As usual compile and run [_*json-parse06.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse06.c). Expected output: 39 | 40 | ``` 41 | firstName -> John 42 | lastName -> Smith 43 | isAlive -> true 44 | age -> 27 45 | address -> { "streetAddress": "21 2nd Street", "city": "New York", "state": "NY", "postalCode": "10021-3100" } 46 | phoneNumbers -> [ { "type": "home", "number": "212 555-1234" }, { "type": "office", "number": "646 555-4567" } ] 47 | children -> [ ] 48 | spouse -> (null) 49 | ``` 50 | 51 | We have looped over every field in our _*contact.json*_ file. The code is simple and easy to understand. As you may have noticed, the brackets are not needed if only a single statement is executed in the loop, just as is the case with other C style loops. 52 | 53 | In cases where the value is another json\_object or a json\_array, the obj or array is not parsed. Simply printed as a string. Hence, the program is not generic in nature. However, we have all the tools to implement a recursive function to fully parse our _*contact.json*_ file, or in general any JSON. 54 | 55 | ## json_object_object_foreach: json-parse07.c 56 | 57 | So let's apply this idea to our previous example [_*json-parse04.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse04.c) and parse the entire file as before, printing out the name/value pairs: [_*json-parse07.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse07.c) 58 | 59 | ```C 60 | #include 61 | #include 62 | 63 | void doarray(json_object *obj); 64 | 65 | void 66 | doit(json_object *obj) 67 | { 68 | json_object_object_foreach(obj, key, val) 69 | { 70 | switch (json_object_get_type(val)) 71 | { 72 | case json_type_array: 73 | printf("\n%s \n\n", key); 74 | doarray(val); 75 | break; 76 | 77 | case json_type_object: 78 | printf("\n%s \n\n", key); 79 | doit(val); 80 | break; 81 | 82 | default: 83 | printf("%s: %s\n", key, json_object_get_string(val)); 84 | } 85 | } 86 | } 87 | 88 | void 89 | doarray(json_object *obj) 90 | { 91 | int temp_n = json_object_array_length(obj); 92 | for (int i = 0; i < temp_n; i++) 93 | doit(json_object_array_get_idx(obj, i)); 94 | } 95 | 96 | int 97 | main(void) 98 | { 99 | json_object *root = json_object_from_file("contact.json"); 100 | 101 | if (!root) 102 | return 1; 103 | doit(root); 104 | 105 | json_object_put(root); 106 | return 0; 107 | } 108 | 109 | ``` 110 | 111 | You know what to do here. The expected output: 112 | 113 | ``` 114 | $ ./json-parse07 115 | firstName: John 116 | lastName: Smith 117 | isAlive: true 118 | age: 27 119 | 120 | address 121 | 122 | streetAddress: 21 2nd Street 123 | city: New York 124 | state: NY 125 | postalCode: 10021-3100 126 | 127 | phoneNumbers 128 | 129 | type: home 130 | number: 212 555-1234 131 | type: office 132 | number: 646 555-4567 133 | 134 | children 135 | 136 | spouse: (null) 137 | 138 | ``` 139 | 140 | Ok, while this is not the *exact* output as our previous example _*json-parse04.c*_, it does illustrate the basic idea. And we have processed everything as before and printed the results. 141 | 142 | # Problems 143 | 144 | 1. Print types of JSON objects in _*contact.json*_ using json_object_object_foreach as _*json-type00.c*_ does. 145 | 146 | - Try to refactor _*json-parse07.c*_, so it produces _*exactly*_ the same output as _*json-parse04.c*_. 147 | 148 | - Refactor _*json-parse07.c*_ to store the JSON values in a C struct. 149 | 150 | - Why do you think I did not go over this first and forgo the more complex _*json-parse04.c*_? 151 | 152 | 153 | -------------------------------------------------------------------------------- /tutorial/parsing5.md: -------------------------------------------------------------------------------- 1 | # Parsing a Json object - part 5: Iterators 2 | 3 | We introduced the function _*json_object_object_foreach*_ previously. However, json-c offers another iteration API more in a C++ iterator type style. 4 | 5 | Consider our previous example: 6 | 7 | ```C 8 | #include 9 | #include 10 | 11 | int 12 | main(void) 13 | { 14 | json_object *root = json_object_from_file("contact.json"); 15 | json_object_object_foreach(root, key, val) 16 | printf("%s -> %s\n", key, json_object_get_string(val)); 17 | 18 | json_object_put(root); 19 | return 0; 20 | } 21 | 22 | ``` 23 | 24 | If we refactor the above by replacing essentially implementing the macro _*json_object_object_foreach*_, we have: 25 | 26 | ```C 27 | #include 28 | #include 29 | 30 | int 31 | main(void) 32 | { 33 | struct lh_entry *entry; // Struct needed here 34 | char *key; 35 | json_object *root = json_object_from_file("contact.json"); 36 | entry = json_object_get_object(root)->head; 37 | while( entry ) 38 | { 39 | key = (char *)entry->k; 40 | json_object* val = (json_object *) entry->v; 41 | printf("%s -> %s\n", key, json_object_get_string(val)); 42 | entry = entry->next; 43 | } 44 | json_object_put(root); 45 | return 0; 46 | } 47 | ``` 48 | 49 | Examining the above code, we are violating the Object-Oriented principle of [encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)) and exposing the json-c internal representation of the _*json_object*_. This is not as apparent when using the macro _*json_object_object_foreach*_, yet even then the programmer has access to the internal struct lh_entry: 50 | 51 | ```C 52 | #include 53 | #include 54 | 55 | int 56 | main(void) 57 | { 58 | json_object *root = json_object_from_file("contact.json"); 59 | json_object_object_foreach(root, key, val) 60 | printf("Entry %p\n",entrykey); 61 | 62 | json_object_put(root); 63 | return 0; 64 | } 65 | 66 | ``` 67 | 68 | The json-c libraries offers a way to avoid this "_*problem*_". To illustrate, consider [_*json-parse08.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse08.c): 69 | 70 | ```C 71 | #include 72 | #include 73 | 74 | int 75 | main(void) 76 | { 77 | struct json_object_iterator it; 78 | struct json_object_iterator itEnd; 79 | 80 | json_object *root = json_object_from_file("contact.json"); 81 | it = json_object_iter_init_default(); 82 | it = json_object_iter_begin(root); 83 | itEnd = json_object_iter_end(root); 84 | 85 | while (!json_object_iter_equal(&it, &itEnd)) 86 | { 87 | const char* key = json_object_iter_peek_name(&it); 88 | json_object* val = json_object_iter_peek_value(&it); 89 | printf("%s -> %s\n", key, json_object_get_string(val)); 90 | json_object_iter_next(&it); 91 | } 92 | json_object_put(root); 93 | return 0; 94 | } 95 | ``` 96 | 97 | The code should explain itself, but consult the [documentation](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object__iterator_8h.html) for more details if needed. 98 | 99 | **Note:** The usage of _*struct*_ in the declarations of _*it*_ and _*itEnd*_ are necessary for the data 'type' _*json_object_iterator*_. 100 | -------------------------------------------------------------------------------- /tutorial/parsing6.md: -------------------------------------------------------------------------------- 1 | # Parsing a Json object - part 6: Iteration yet again 2 | 3 | We have previously discussed two methods for iterating over _*json_type_object*_ objects, here we yet another one inspired from [graph theory](https://en.wikipedia.org/wiki/Graph_theory). We shall illustrate its usage with a very simple example. Recall program [_*json-array02.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array02.c) demonstrating looping over all values in a JSON array. Now consider the program below, [_*json-array04*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array04.c), which iterates through all the values in the JSON array _*names.json*_, printing each value and the index of the value in the array: 4 | 5 | ## json-array04.c 6 | 7 | ```C 8 | #include 9 | #include 10 | #include 11 | 12 | static int 13 | print_str(json_object *obj, int flags, json_object *parent, const char *key, 14 | size_t *index, void *data) 15 | { 16 | if (index) 17 | printf("The value at %ld position is: %s\n", (long)* index, json_object_get_string(obj)); 18 | return JSON_C_VISIT_RETURN_CONTINUE; 19 | } 20 | ``` 21 | 22 | The function that does all the work here is _*json_c_visit*_. The first thing to note is that we must include the _*json_visit.h*_ header file to use this function. Now for the specifics: 23 | 24 | - [int json_c_visit(json_object *jso, int future_flags, json_c_visit_userfunc *userfunc, void *userarg)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__visit_8h.html) 25 | 26 | From the documentation: 27 | 28 | > Visit each object in the JSON hierarchy starting at jso. For each object, userfunc is called, passing the object and userarg. If the object has a parent (i.e. anything other than jso itself) its parent will be passed as parent_jso, and either jso_key or jso_index will be set, depending on whether the parent is an object or an array. 29 | > 30 | > Nodes will be visited depth first, but containers (arrays and objects) will be visited twice, the second time with JSON_C_VISIT_SECOND set in flags. 31 | > 32 | > userfunc must return one of the defined return values, to indicate whether and how to continue visiting nodes, or one of various ways to stop. 33 | > 34 | > Returns 0 if nodes were visited successfully, even if some were intentionally skipped due to what userfunc returned. Returns <0 if an error occurred during iteration, including if userfunc returned JSON_C_VISIT_RETURN_ERROR. 35 | 36 | For our example, [_*json-array04*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array04.c), we call _*json_c_visit*_ on our JSON array, _*root*_ with a userfunc, _*print_str*_ which merely prints the array index and array value at that index. Note that the _*userfunc*_ is declared to be type _*json_c_visit_userfunc*_. This a typedef in the _*json_visit.h*_ header file: 37 | 38 | ```C 39 | typedef int(json_c_visit_userfunc)(json_object *jso, int flags, json_object *parent_jso, const char *jso_key, size_t *jso_index, void *userarg) 40 | ``` 41 | 42 | The _*userfunc*_ must return one of the below defined return values: 43 | 44 | - JSON_C_VISIT_RETURN_CONTINUE 45 | - JSON_C_VISIT_RETURN_ERROR 46 | - JSON_C_VISIT_RETURN_POP 47 | - JSON_C_VISIT_RETURN_SKIP 48 | - JSON_C_VISIT_RETURN_STOP 49 | 50 | These return values determine how the path through the JSON continues. Notice our function _*print_str*_ returns _*JSON_C_VISIT_RETURN_CONTINUE*_ for all values visited. We wish to loop over the entire array. 51 | 52 | Also note: the very first time _*print_str*_ is called it is called with the entire JSON array itself, and hence the argument _*jso_index*_ is NULL. We are not interested in printing this value or the JSON array itself so our _*print_str*_ function tests for this condition: 53 | 54 | ```C 55 | if (index) 56 | printf("The value at %ld position is: %s\n", (long)* index, json_object_get_string(obj)); 57 | ``` 58 | 59 | Using _*json_c_visit*_ to loop over a JSON array as above is perhaps overkill. For production code, I would recommend using a simple loop as previously discussed. The _*json_c_visit*_ solution is provided merely for completeness sake and to introduce the subject with a rather easy to understand example. 60 | 61 | ## Depth-first search 62 | 63 | The function _*json_c_visit*_ is best illustrated by considering an actual example involving a nonlinear graph. The array example above fails to illustrate the path _*json_c_visit*_ takes through a JSON document. Recall from the documentation: 64 | 65 | > Visit each object in the JSON hierarchy starting at jso. 66 | > Nodes will be visited depth first, but containers (arrays and objects) will be visited twice, the second time with JSON_C_VISIT_SECOND set in flags. 67 | 68 | A more general example of a Depth-first search would take a more complex data structure. 69 | 70 | I am going to take the [Animated example of a depth-first search](https://en.wikipedia.org/wiki/Depth-first_search#/media/File:Depth-First-Search.gif) from [wikipedia](https://en.wikipedia.org/wiki/Depth-first_search). Illustrated below along with a JSON document with a similar structure: 71 | 72 | 73 | 74 | 75 | 76 | 77 | 100 | 101 | 102 |
Json Graph
78 | 79 | ```json 80 | { 81 | "1": { 82 | "2": { 83 | "3": { 84 | "4": 4 85 | } 86 | }, 87 | "5": { 88 | "6": { 89 | "7": 7 90 | }, 91 | "8": 8 92 | }, 93 | "9": { 94 | "10": 10 95 | } 96 | } 97 | } 98 | ``` 99 |
103 | 104 | Now, the defintion of a JSON also from wikipedia: 105 | 106 | > Depth-first search (DFS) is an algorithm for traversing or searching tree or graph data structures. The algorithm starts at the root node (selecting some arbitrary node as the root node in the case of a graph) and explores as far as possible along each branch before backtracking. 107 | 108 | To properly illustrate a depth-first search, we note the function _*json_c_visit*_ visists container nodes twice. So in our _*json_c_visit_userfunc*_ we need to test for that and simply return as in: 109 | 110 | ```C 111 | if (!parent || flags==JSON_C_VISIT_SECOND) return JSON_C_VISIT_RETURN_CONTINUE; 112 | ``` 113 | Note: we need to ignore the case where no parent JSON exists also. The case corresponds to the entire JSON document itself. It will be visisted both first and last as it also is a '_*container node*_'. 114 | 115 | Putting it all together [_*json-parse10.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse10.c) reads [_*depth.json*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/depth.json) and prints the key and value of each node in the a depth-first search: 116 | 117 | ## json-parse10.c 118 | 119 | ```C 120 | #include 121 | #include 122 | #include 123 | 124 | static int 125 | doit(json_object *obj, int flags, json_object *parent, const char *key, 126 | size_t *index, void *data) 127 | { 128 | if (!parent || flags==JSON_C_VISIT_SECOND) return JSON_C_VISIT_RETURN_CONTINUE; 129 | printf("key: %s, value: %s\n", key, json_object_to_json_string(obj)); 130 | return JSON_C_VISIT_RETURN_CONTINUE; 131 | } 132 | 133 | int 134 | main(void) 135 | { 136 | json_object *root = json_object_from_file("depth.json"); 137 | json_c_visit(root, 0, doit, NULL); 138 | 139 | json_object_put(root); 140 | return 0; 141 | } 142 | 143 | ``` 144 | 145 | Expected Output: 146 | 147 | ``` 148 | key: 1, value: { "2": { "3": { "4": 4 } }, "5": { "6": { "7": 7 }, "8": 8 }, "9": { "10": 10 } } 149 | key: 2, value: { "3": { "4": 4 } } 150 | key: 3, value: { "4": 4 } 151 | key: 4, value: 4 152 | key: 5, value: { "6": { "7": 7 }, "8": 8 } 153 | key: 6, value: { "7": 7 } 154 | key: 7, value: 7 155 | key: 8, value: 8 156 | key: 9, value: { "10": 10 } 157 | key: 10, value: 10 158 | ``` 159 | ## Serching a JSON 160 | 161 | We have already discussed _*json_object_array_bsearch*_ which can be used to search a **sorted** JSON array, but what if we wish to search a JSON object array or otherwise for a particular key or value? And terminate the search once the key or value is found. 162 | 163 | In [_*json-parse11.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse11.c) we wish to find the name, first and last, of the user with a particular email address, _*ptunkiny@angelfire.com*_ in the JSON document,[_*sample00.json*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/sample00.json). 164 | 165 | This JSON consists of an array containing many records of the form: 166 | 167 | ```json 168 | { 169 | "id": 1, 170 | "first_name": "Catie", 171 | "last_name": "Gregorin", 172 | "email": "cgregorin0@elegantthemes.com", 173 | "gender": "Female", 174 | "ip_address": "172.219.194.172" 175 | } 176 | ``` 177 | 178 | As this JSON document is an array, one could use _*json_object_array_bsearch*_ to search the array with the right _*sort_fn*_. However, this has the disadvantage that the array must be sorted first. So consider [_*json-parse11.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-parse11.c) below: 179 | 180 | 181 | ## json-parse11.c 182 | 183 | ```C 184 | #include 185 | #include 186 | #include 187 | #include 188 | 189 | #define EMAIL "ptunkiny@angelfire.com" 190 | #define JSON_OBJECT_STR(obj, key) json_object_get_string(json_object_object_get(obj, key)) 191 | 192 | static int 193 | doit(json_object *obj, int flags, json_object *parent, const char *key, 194 | size_t *index, void *data) 195 | { 196 | if (!parent || flags==JSON_C_VISIT_SECOND || 197 | json_object_get_type(obj) == json_type_object || 198 | json_object_get_type(obj) == json_type_array) 199 | return JSON_C_VISIT_RETURN_CONTINUE; 200 | 201 | if (strcmp(json_object_get_string(obj), EMAIL) == 0) 202 | { 203 | printf("Found: %s %s %s\n", JSON_OBJECT_STR(parent, "first_name"), 204 | JSON_OBJECT_STR(parent, "last_name"), json_object_to_json_string(obj)); 205 | return JSON_C_VISIT_RETURN_STOP; 206 | } 207 | return JSON_C_VISIT_RETURN_CONTINUE; 208 | } 209 | 210 | int 211 | main(void) 212 | { 213 | json_object *root = json_object_from_file("sample00.json"); 214 | printf("Search for %s\n\n", EMAIL); 215 | json_c_visit(root, 0, doit, NULL); 216 | 217 | json_object_put(root); 218 | return 0; 219 | } 220 | 221 | ``` 222 | 223 | The code is fairly straightforward, note the usage of _*JSON_C_VISIT_RETURN_STOP*_ to stop _*json_c_visit*_ from visiting any further nodes in the JSON document. 224 | 225 | From the [documentation](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__visit_8h.html#a5956f41bed48f90a127f9b37fad7ea97): 226 | > This json_c_visit_userfunc return value indicates that iteration should stop immediately, and cause json_c_visit to return success. 227 | 228 | This is precisely what we wish to do at this step, terminate the search once we have found the required record. 229 | 230 | ## Problems 231 | 232 | 1. Rewrite _*json-parse11.c*_ to use _*json_object_array_bsearch*_. 233 | 2. Review _* JSON_C_VISIT_RETURN_POP*_ and _*JSON_C_VISIT_RETURN_SKIP*_ in the [docs](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__visit_8h.html), can you think of any user case for these? 234 | -------------------------------------------------------------------------------- /tutorial/sort.md: -------------------------------------------------------------------------------- 1 | # JSON Arrays: sorting and searching 2 | 3 | 4 | Now that we have reviewed JSON arrays, let's examine the json-c libraries functions to sort and search arrays. 5 | 6 | First to sort a JSON array use: 7 | - [_*void json_object_array_sort(json_object \*jso, int(\*)(const void \*, const void \*) sort_fn)*_](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a5584e2f2051cd1faa7fafd07ba888fd1) 8 | 9 | This function is very much like the C library function - [_*qsort*_](https://linux.die.net/man/3/qsort): it relies upon the application code providing a comparison function, _*sort_fn*_. The comparison function behaves like the C function [_*strcmp*_](https://linux.die.net/man/3/strcmp). 10 | 11 | From the documentation: 12 | > Sorts the elements of jso of type json_type_array 13 | > 14 | > Pointers to the json_object pointers will be passed as the two arguments to sort_fn 15 | 16 | An example of a _*sort_fn*_ for use with an array containing only intergers is found in the json-c program, [_*test1.c*_](https://github.com/json-c/json-c/blob/master/tests/test1.c): 17 | 18 | ```C 19 | static int sort_fn(const void *j1, const void *j2) 20 | { 21 | json_object *const *jso1, *const *jso2; 22 | int i1, i2; 23 | 24 | jso1 = (json_object *const *)j1; 25 | jso2 = (json_object *const *)j2; 26 | if (!*jso1 && !*jso2) 27 | return 0; 28 | if (!*jso1) 29 | return -1; 30 | if (!*jso2) 31 | return 1; 32 | 33 | i1 = json_object_get_int(*jso1); 34 | i2 = json_object_get_int(*jso2); 35 | 36 | return i1 - i2; 37 | } 38 | 39 | ``` 40 | 41 | This is the general form all _*sort_fns*_ are going to take: 42 | 43 | - Declare and initialize our variables. 44 | - Test for NULL values. 45 | - Get the values we need for our comparison from the two JSON objects. 46 | - perform the needed comparison and return the result. 47 | 48 | ## json-array03.c 49 | 50 | Consider a JSON array whose values are first names. [_*names.json*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/names.json). Our JSON has the form: 51 | 52 | ``` 53 | ["Torin", "Stefin", "Emerson", "Lisandro", "Caidan", ...] 54 | ``` 55 | 56 | This array is clearly unsorted. In json-c, sorting this array is as easy as: 57 | 58 | ```C 59 | json_object *root = json_object_from_file("names.json"); 60 | json_object_array_sort(root, sort_fn); 61 | ``` 62 | 63 | provided one has implemented a _*sort_fn*_ that handles strings. A naive _*sort_fn*_ for such a case can be found in _*json-array03.c*_ below. 64 | 65 | - [json_object* json_object_array_bsearch( const struct json_object *key, const struct json_object *jso, int(*)(const void *, const void *) sort_fn)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#aed353084ed3ad84e7b7575afbe7e719d) 66 | 67 | From the documentation: 68 | 69 | > Binary search a sorted array for a specified key object. 70 | > 71 | > It depends on your compare function what's sufficient as a key. Usually you create some dummy object with the parameter compared in it, to identify the right item you're actually looking for. 72 | 73 | Wrapping it all up here is a program to sort the JSON array _*names.json*_ and search for two keys, one key present and one key not present: [_*json-array03.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-array03.c) 74 | 75 | ```C 76 | #include 77 | #include 78 | #include 79 | 80 | #define NUM_KEYS 2 81 | 82 | static int 83 | sort_fn(const void *j1, const void *j2) 84 | { 85 | json_object *const *jso1, *const *jso2; 86 | const char *str1, *str2; 87 | 88 | jso1 = (json_object *const *) j1; 89 | jso2 = (json_object *const *) j2; 90 | 91 | if (!*jso1 && !*jso2) 92 | return 0; 93 | if (!*jso1) 94 | return -1; 95 | if (!*jso2) 96 | return 1; 97 | 98 | str1 = json_object_get_string(*jso1); 99 | str2 = json_object_get_string(*jso2); 100 | 101 | return strcmp(str1, str2); 102 | } 103 | 104 | int 105 | main(void) 106 | { 107 | json_object *str, *temp; 108 | char *keys[NUM_KEYS] = {"Vladimir", "Nathaniel"}; 109 | 110 | json_object *root = json_object_from_file("names.json"); 111 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 112 | 113 | json_object_array_sort(root, sort_fn); 114 | printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY)); 115 | 116 | for(int i=0; i *. They were introduced into the C language by the [C99 standard](https://en.wikipedia.org/wiki/C99). These are exact-width integer types that are guaranteed to have the same number of bits across all implementations. So *int32\_t* is a 32 bit integer while *int64\_t* is 64 bits. In general, it is safest to always use the int64 functions in the json-c library. 28 | 29 | We have two functions in the json-c library to help us determine the type of a _*json_object*_: 30 | 31 | - [int json_object_is_type(json_object \*obj, json_type type)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a8ab506a3d8f4ba5eb6a12ce0a6bbd37b) 32 | - [json_type json_type json_object_get_type(json_object \*obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#af256a3a7910e271a2b9735e5044c3827) 33 | 34 | We have seen the usage of the function _*json_object_get_string*_, json-c naturally also provides the functions: 35 | 36 | - [json_bool json_object_get_boolean(json_object *obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#ac003fb99db7ecd674bb16d983d2f92ee) 37 | - [double json_object_get_double(json_object *obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a94a70cff6a14398b581b7b10b0792c5b) 38 | - [int32_t json_object_get_int(json_object *obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a8c56dc58a02f92cd6789ba5dcb9fe7b1) 39 | - [int64_t json_object_get_int64(json_object *obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a1a14750b3af4df18ec8dc93b090a8e8a) 40 | - [lh_table* json_object_get_object(json_object *obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a2caa52ae1863bd073444f3737138a4db) 41 | - [array_list * json_object_get_array(json_object *obj)](https://json-c.github.io/json-c/json-c-0.15/doc/html/json__object_8h.html#a23d20e3f886c1638a7116be66b7b5ec2) 42 | 43 | One can also see we have two new types: 44 | 45 | - [lh_table](https://json-c.github.io/json-c/json-c-0.15/doc/html/structlh__table.html) 46 | - [array_list](https://json-c.github.io/json-c/json-c-0.15/doc/html/structarray__list.html) 47 | 48 | Both of course *structs* defined in the json-c header files. For now, we can safely ignore these types as the details are not important here. Curious users can read the docs or look up the definitions in the header files. More details on these functions can be found in the json-c documentation. 49 | 50 | Now, let's demonstrate some of these function's usage with our _*contact.json*_ file. Example [_*json-type00.c*_](https://github.com/rbtylee/tutorial-jsonc/blob/master/src/json-type00.c) below: 51 | 52 | ```C 53 | #include 54 | #include 55 | 56 | void json_object_print_type(json_object *obj, const char *key); 57 | 58 | int 59 | main(void) 60 | { 61 | json_object *root = json_object_from_file("contact.json"); 62 | if (!root) 63 | return 1; 64 | 65 | json_object *first_name = json_object_object_get(root, "firstName"); 66 | json_object_print_type(first_name, "firstName"); 67 | json_object *last_name = json_object_object_get(root, "lastName"); 68 | json_object_print_type(last_name, "lastName"); 69 | json_object *is_alive = json_object_object_get(root, "isAlive"); 70 | json_object_print_type(is_alive, "isAlive"); 71 | json_object *age = json_object_object_get(root, "age"); 72 | json_object_print_type(age, "age"); 73 | json_object *address = json_object_object_get(root, "address"); 74 | json_object_print_type(address, "address"); 75 | json_object *phone_numbers = json_object_object_get(root, "phoneNumbers"); 76 | json_object_print_type(phone_numbers, "phoneNumbers"); 77 | json_object *children = json_object_object_get(root, "children"); 78 | json_object_print_type(children, "children"); 79 | json_object *spouse = json_object_object_get(root, "spouse"); 80 | json_object_print_type(spouse, "spouse"); 81 | 82 | json_object_put(root); 83 | return 0; 84 | } 85 | 86 | void 87 | json_object_print_type(json_object *obj, const char *key) 88 | { 89 | json_type type; 90 | 91 | type = json_object_get_type(obj); /*Getting the type of the json object*/ 92 | switch (type) 93 | { 94 | case json_type_null: 95 | printf("%s is json_type_null\n", key); 96 | printf(" value: %s\n", json_object_get_string(obj)); 97 | break; 98 | 99 | case json_type_boolean: 100 | printf("%s is json_type_boolean\n", key); 101 | printf(" value: %s\n", json_object_get_boolean(obj)? "true": "false"); 102 | break; 103 | 104 | case json_type_double: 105 | printf("%s is json_type_double\n", key); 106 | printf(" value: %lf\n", json_object_get_double(obj)); 107 | break; 108 | 109 | case json_type_int: 110 | printf("%s is json_type_int\n", key); 111 | printf(" value: %d\n", json_object_get_int(obj)); 112 | break; 113 | 114 | case json_type_object: 115 | printf("%s is json_type_object\n", key); 116 | printf(" value: %s\n", json_object_get_string(obj)); 117 | break; 118 | 119 | case json_type_array: 120 | printf("%s is json_type_array\n", key); 121 | printf(" value: %s\n", json_object_get_string(obj)); 122 | break; 123 | 124 | case json_type_string: 125 | printf("%s is json_type_string\n", key); 126 | printf(" value: %s\n", json_object_get_string(obj)); 127 | break; 128 | 129 | default: 130 | printf("%s: WTF, unhandled case, type %d\n", key, type); 131 | printf(" value: %s\n", json_object_get_string(obj)); 132 | } 133 | } 134 | 135 | ``` 136 | 137 | Compile, and execute. Compare your results with the original _*contact.json*_ file to ensure the results make sense. 138 | 139 | ## Problems 140 | 141 | 1. In any language, write an implementation of a state machine to determine whether a JSON value is valid. Consult the state diagram for a JSON value above. You are free to use a state machine library. However, for such a simple example it is hardly necessary. 142 | 143 | - If you choose a language other than C for Problem 1, explain why? Explain how difficult would it be to implement your non-C solution or something akin to it in C? If it is possible for you to do so in a reasonable amount of time, implement your non-C solution in C. 144 | 145 | - If you solved problem 1. in C, try it again in a non-C language. Preferably a 'popular' well-known one. 146 | -------------------------------------------------------------------------------- /tutorial/url.txt: -------------------------------------------------------------------------------- 1 | chapters to write: so far SEVEN to write 2 | 3 | -------------------------------------------------------------------------------- 4 | url examples 5 | 6 | copying 7 | printing ... display, serializers 8 | handling errors 9 | threads 10 | debugging 11 | autmake and meson 12 | Documentation 13 | -------------------------------------------------------------------------------- 14 | iteration part two mostly finished 15 | 16 | Pointer https://www.baeldung.com/json-pointer 17 | 18 | iteration. 19 | on write up mention visit is more powerful 20 | compare for each and visit on getting all top level keys, values. 21 | write my function to return keys like python json.keys[i] dictionary 22 | write my function to return keys like python json.keys as eina hash 23 | problems. 24 | read an array json, json-array02.c json-array04.c be sure works for general case 25 | graph dot like python tree.py 26 | generalize graph dot to work on contacts and general json 27 | 28 | 29 | Eric Hawicz 30 | 31 | https://groups.google.com/forum/#!topic/json-c/gD_p68OA-L8 32 | hashlink https://groups.google.com/forum/?nomobile=true#!topic/json-c/jt0pxWL9GP8 33 | curl -XPOST 'https://hastebin.com/documents' -d'hello world' 34 | 35 | shit iteration part 2 36 | https://json-c.github.io/json-c/json-c-0.13/doc/html/json__visit_8h.html 37 | todo JSON_C_TO_STRING_PRETTY | other values what does this do? I saw it in a sample program online. explore this 38 | 39 | read weather json (weather.json) create a json with some of the data (forecasts.hson like our forecast module) and display it 40 | 41 | 42 | --------------------------------------------------------------------------------