UNPKG

diffusion

Version:

Diffusion JavaScript client

176 lines (144 loc) 4.71 kB
/* * A module for converting between JSON and XML representations for * the primary purpose of topic metadata. */ var ATTR = require('../schema/consts').ATTR; // Parse a string of key/value pairs and produce a js object. // NB: Does not handle embedded = or " function attrs_str2js(str) { var js = {}; var pairs = str.split(' '); for (var i = 0; i < pairs.length; i++) { var pair = pairs[i].split('='); js[pair[0]] = pair[1].match(/"(.*)"/)[1]; } return js; } function escapeEntities(str) { return String(str).replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/"/g, '&quot;') .replace(/'/g, '&#x27;'); } function attrs_obj2arr(obj) { var attrs = []; if (typeof obj === 'object') { for (var key in obj) { attrs.push('' + key + '="' + escapeEntities(obj[key]) + '"'); } } return attrs; } // This is a simple XML parser that can handle topic metadata received // from Diffusion. It's not a fully-fledged XML parser, but it's a lot // more lightweight. function xml2json(xml, pos) { var js = {}; if (pos === undefined) { // First call of this function. pos = { idx : 0, isRoot : true }; // Strip off preamble. Because it's the first thing to be // found in the XML, we can limit searching for it to the // initial call to this function. var preamble = xml.match(/<\?.*?\?>/); if (preamble) { xml = xml.substr(preamble[0].length); } } var elem_match = null; for (;;) { elem_match = xml.substr(pos.idx).match(/<.*?>/); if (!elem_match) { break; } pos.idx += elem_match[0].length; var elem = elem_match[0].trim(); if (elem.substr(0,2) === '</') { // Closing element, back to parent. return js; } var name = elem.match(/\b(.+?)\b/)[0]; var attrs_match = elem.match(/<.+?\b(.*)\/?>/); var attrs_str = ''; if (attrs_match) { attrs_str = attrs_match[1].trim(); } var attrs = attrs_str2js(attrs_str); var child_count; if (elem.substr(-2) === '/>') { // Self-closing element, no children. // Root element, never repeated. if (pos.isRoot) { pos.isRoot = false; js[name] = xml2json(xml, pos); js[name][ATTR] = attrs; } else { if (!js[name]) { js[name] = []; } child_count = js[name].push({}); js[name][child_count - 1][ATTR] = attrs; } } else { // Opening a new element, which may have children. // Root element is never repeated. if (pos.isRoot) { pos.isRoot = false; js[name] = xml2json(xml, pos); js[name][ATTR] = attrs; } else { if (!js[name]) { js[name] = []; } child_count = js[name].push(xml2json(xml, pos)); js[name][child_count - 1][ATTR] = attrs; } } } return js; } // Convert a JSON object (primarily, topic metadata) to a stringified // XML representation. It is not intended to be a complete JSON->XML // converter, but it is small, light, and does enough for our needs. function json2xml(obj, recur) { var str = ''; if (!recur) { str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'; } for (var key in obj) { if (key === ATTR) { continue; } var val = obj[key]; if (!(val instanceof Array)) { val = Array(val); } for (var i = 0; i < val.length; i++) { var attrs = attrs_obj2arr(val[i][ATTR]); str += '<' + key; if (attrs && attrs.length > 0) { str += ' '; str += attrs.join(' '); } // Check for non-attribute children of this element var child_str = json2xml(val[i], true); if (child_str && child_str.length > 0) { str += '>'; str += child_str; str += '</' + key + '>'; } else { // No children, close tag here. str += '/>'; } } } return str; } module.exports = { xml2json : xml2json, json2xml : json2xml };