├── .gitignore ├── example ├── convert.js ├── output.xml └── input.json ├── package.json ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | test* -------------------------------------------------------------------------------- /example/convert.js: -------------------------------------------------------------------------------- 1 | var jax = require("../index"), 2 | inputJSON = require("fs").readFileSync(__dirname+"/input.json", "utf-8"); 3 | 4 | console.log(jax(inputJSON)); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jax", 3 | "version": "0.1.0", 4 | "description": "Convert JSON from GData API's back to XML", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": "", 10 | "author": "Andris Reinman", 11 | "license": "MIT" 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jax 2 | 3 | Convert JSON to XML. Useful for converting Google API JSON structures back to XML. 4 | 5 | ## Installation 6 | 7 | npm install jax 8 | 9 | ## Usage 10 | 11 | var jax = require("jax"); 12 | 13 | inputJSON = fs.readFileSync("data.json", "utf-8"); 14 | outputXML = jax(input); 15 | 16 | See example/input.json and example/output.xml for sample data format 17 | 18 | ## License 19 | 20 | MIT -------------------------------------------------------------------------------- /example/output.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | http://www.google.com/m8/feeds/contacts/andris.reinman%40gmail.com/base/4acc2efb88cc1547 4 | 2012-10-12T06:49:19.203Z 5 | 2012-10-12T06:49:19.203Z 6 | 7 | Koogel Moogel 8 | Some notes about this contact 9 | 10 | 11 | 12 | Koogel Moogel 13 | Koogel 14 | Moogel 15 | 16 | +3721234567 17 | -------------------------------------------------------------------------------- /example/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "encoding": "UTF-8", 4 | "entry": { 5 | "xmlns": "http://www.w3.org/2005/Atom", 6 | "xmlns$gContact": "http://schemas.google.com/contact/2008", 7 | "xmlns$batch": "http://schemas.google.com/gdata/batch", 8 | "xmlns$gd": "http://schemas.google.com/g/2005", 9 | "gd$etag": "\"SHw7ezVSLyt7I2A9WhNTEE8OQgE.\"", 10 | "id": { 11 | "$t": "http://www.google.com/m8/feeds/contacts/andris.reinman%40gmail.com/base/4acc2efb88cc1547" 12 | }, 13 | "updated": { 14 | "$t": "2012-10-12T06:49:19.203Z" 15 | }, 16 | "app$edited": { 17 | "xmlns$app": "http://www.w3.org/2007/app", 18 | "$t": "2012-10-12T06:49:19.203Z" 19 | }, 20 | "category": [{ 21 | "scheme": "http://schemas.google.com/g/2005#kind", 22 | "term": "http://schemas.google.com/contact/2008#contact" 23 | }], 24 | "title": { 25 | "$t": "Koogel Moogel" 26 | }, 27 | "content": { 28 | "$t": "Some notes about this contact" 29 | }, 30 | "link": [{ 31 | "rel": "self", 32 | "type": "application/atom+xml", 33 | "href": "https://www.google.com/m8/feeds/contacts/andris.reinman%40gmail.com/base/4acc2efb88cc1547" 34 | }, { 35 | "rel": "edit", 36 | "type": "application/atom+xml", 37 | "href": "https://www.google.com/m8/feeds/contacts/andris.reinman%40gmail.com/base/4acc2efb88cc1547" 38 | }], 39 | "gd$name": { 40 | "gd$fullName": { 41 | "$t": "Koogel Moogel" 42 | }, 43 | "gd$givenName": { 44 | "$t": "Koogel" 45 | }, 46 | "gd$familyName": { 47 | "$t": "Moogel" 48 | } 49 | }, 50 | "gd$phoneNumber": [{ 51 | "rel": "http://schemas.google.com/g/2005#other", 52 | "uri": "tel:+372-123-4567", 53 | "$t": "+3721234567" 54 | }] 55 | } 56 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | 3 | module.exports = jax; 4 | 5 | /** 6 | * Converts JSON to XML. Expects $t for text tags. First root object 7 | * is used as the XML root, other objects are discarded. 8 | * 9 | * @param {Object|String} JSON string or an object to be converted to XML 10 | * @return {String} XML output 11 | */ 12 | function jax(object){ 13 | var rootElement, 14 | headParams = [], 15 | xml = ""; 16 | 17 | if(typeof object == "string"){ 18 | object = JSON.parse(object); 19 | } 20 | 21 | Object.keys(object).forEach(function(key){ 22 | if(typeof object[key] != "object"){ 23 | headParams.push(key.replace(/[\$]/g, ":")+'="'+escapeValue(object[key])+'"'); 24 | }else{ 25 | rootElement = {name: key, content: object[key]}; 26 | } 27 | }); 28 | 29 | xml += ""; 30 | if(rootElement){ 31 | xml += drawBranch(rootElement.name, rootElement.content); 32 | } 33 | 34 | return xml; 35 | } 36 | 37 | /** 38 | * Draws XML for a branch object, recursive function 39 | * 40 | * @param {Object|String} Object to be converted to XML 41 | * @return {String} XML output 42 | */ 43 | function drawBranch(name, object, level){ 44 | name = (name || "").replace(/[\$]/g, ":"); 45 | level = level || 0; 46 | var branches = [], params = [], start, end; 47 | Object.keys(object).forEach(function(key){ 48 | if(Array.isArray(object[key])){ 49 | object[key].forEach(function(elm){ 50 | branches.push(drawBranch(key, elm, level + 1)); 51 | }); 52 | }else if(typeof object[key] == "object"){ 53 | branches.push(drawBranch(key, object[key], level + 1)); 54 | }else if(key != "$t"){ 55 | params.push(key.replace(/[\$]/g, ":")+'="'+escapeValue(object[key])+'"') 56 | } 57 | }); 58 | 59 | if(object.$t){ 60 | branches.unshift(escapeText(object.$t)); 61 | } 62 | 63 | if(branches.length){ 64 | start = "<" + name + (params.length?" "+params.join(" "):"") + ">"; 65 | end = ""; 66 | }else{ 67 | start = "<" + name + (params.length?" "+params.join(" "):"") + "/>"; 68 | end = ""; 69 | } 70 | return start + branches.join("") + end; 71 | 72 | } 73 | 74 | /** 75 | * Escapes text values ($t) 76 | * 77 | * @param {String} str String value to be escaped 78 | */ 79 | function escapeText(str){ 80 | str = (str || "").toString().trim(). 81 | replace(/&/g,"&"). 82 | replace(//g,">"); 84 | 85 | return str; 86 | } 87 | 88 | /** 89 | * Escapes attribute values 90 | * 91 | * @param {String} str String value to be escaped 92 | */ 93 | function escapeValue(str){ 94 | str = (str || "").toString().trim(). 95 | replace(/&/g,"&"). 96 | replace(/"/g,"""). 97 | replace(//g,">"); 99 | 100 | return str; 101 | } 102 | 103 | --------------------------------------------------------------------------------