Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

xml-js

Package Overview
Dependencies
Maintainers
1
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

xml-js - npm Package Compare versions

Comparing version 1.5.2 to 1.6.0

.eslintrc.json

3

.vscode/launch.json

@@ -7,3 +7,2 @@ {

"configurations": [
{

@@ -13,3 +12,3 @@ "type": "node",

"name": "Launch Program",
"program": "${workspaceRoot}\\test\\index.js",
"program": "${workspaceRoot}/test/index",
"outFiles": [

@@ -16,0 +15,0 @@ "${workspaceRoot}/out/**/*.js"

#!/usr/bin/env node
/*jslint node:true*/
var fs = require('fs');
var helper = require('./cli-helper');
var project = require('../package.json');
var common = require('../lib/common');
var xml2json = require('../lib/xml2json');

@@ -14,35 +13,35 @@ var json2xml = require('../lib/json2xml');

var requiredArgs = [
{arg: 'src', type: 'file', option: 'src', desc: 'Input file that need to be converted.'}
{ arg: 'src', type: 'file', option: 'src', desc: 'Input file that need to be converted.'}
];
var optionalArgs = [
{arg: 'help', alias: 'h', type: 'flag', option: 'help', desc: 'Display this help content.'},
{arg: 'version', alias: 'v', type: 'flag', option: 'version', desc: 'Display version number of this module.'},
{arg: 'out', type: 'file', option: 'out', desc: 'Output file where the converted result should be written.'},
{arg: 'to-json', type: 'flag', option:'toJason', desc: 'Convert.'},
{arg: 'compact', type: 'flag', option:'compact', desc: 'Compact JSON form (see explanation in www.npmjs.com/package/xml-js).'},
{arg: 'spaces', type: 'number', option:'spaces', desc: 'Specifies amount of space indentation in the output.'},
{arg: 'trim', type: 'flag', option:'trim', desc: 'Any whitespaces surrounding texts will be trimmed.'},
// {arg: 'sanitize', type: 'flag', option:'sanitize', desc: 'Special xml characters will be replaced with entity codes.'},
{arg: 'native-type', type: 'flag', option:'nativeType', desc: 'Numbers and boolean will be converted (coerced) to native type instead of text.'},
{arg: 'always-array', type: 'flag', option:'alwaysArray', desc: 'Every element will always be an array type (applicable if --compact is set).'},
{arg: 'always-children', type: 'flag', option:'alwaysChildren', desc: 'Every element will always contain sub-elements (applicable if --compact is not set).'},
{arg: 'instruction-attr', type: 'flag', option:'instructionHasAttributes', desc: 'Whether to parse contents of processing instruction as attributes.'},
{arg: 'full-tag', type: 'flag', option:'fullTagEmptyElement', desc: 'XML elements will always be in <a></a> form.'},
{arg: 'no-decl', type: 'flag', option:'ignoreDeclaration', desc: 'Declaration instruction <?xml?> will be ignored.'},
{arg: 'no-decl', type: 'flag', option:'ignoreInstruction', desc: 'Processing instruction <?...?> will be ignored.'},
{arg: 'no-attr', type: 'flag', option:'ignoreAttributes', desc: 'Attributes of elements will be ignored.'},
{arg: 'no-text', type: 'flag', option:'ignoreText', desc: 'Texts of elements will be ignored.'},
{arg: 'no-cdata', type: 'flag', option:'ignoreCdata', desc: 'CData of elements will be ignored.'},
{arg: 'no-doctype', type: 'flag', option:'ignoreDoctype', desc: 'DOCTYPE of elements will be ignored.'},
{arg: 'no-comment', type: 'flag', option:'ignoreComment', desc: 'Comments of elements will be ignored.'},
{arg: 'text-key', type: 'string', option:'textKey', desc: 'To change the default \'text\' key.'},
{arg: 'cdata-key', type: 'string', option:'cdataKey', desc: 'To change the default \'cdata\' key.'},
{arg: 'doctype-key', type: 'string', option:'doctypeKey', desc: 'To change the default \'doctype\' key.'},
{arg: 'comment-key', type: 'string', option:'commentKey', desc: 'To change the default \'comment\' key.'},
{arg: 'attributes-key', type: 'string', option:'attributesKey', desc: 'To change the default \'attributes\' key.'},
{arg: 'declaration-key', type: 'string', option:'declarationKey', desc: 'To change the default \'declaration\' key <?xml?>.'},
{arg: 'instruction-key', type: 'string', option:'instructionKey', desc: 'To change the default \'processing instruction\' key <?...?>.'},
{arg: 'type-key', type: 'string', option:'typeKey', desc: 'To change the default \'type\' key (applicable if --compact is not set).'},
{arg: 'name-key', type: 'string', option:'nameKey', desc: 'To change the default \'name\' key (applicable if --compact is not set).'},
{arg: 'elements-key', type: 'string', option:'elementsKey', desc: 'To change the default \'elements\' key (applicable if --compact is not set).'}
{ arg: 'help', alias: 'h', type: 'flag', option: 'help', desc: 'Display this help content.' },
{ arg: 'version', alias: 'v', type: 'flag', option: 'version', desc: 'Display version number of this module.' },
{ arg: 'out', type: 'file', option: 'out', desc: 'Output file where the converted result should be written.' },
{ arg: 'to-json', type: 'flag', option:'toJason', desc: 'Convert.' },
{ arg: 'compact', type: 'flag', option:'compact', desc: 'Compact JSON form (see explanation in www.npmjs.com/package/xml-js).' },
{ arg: 'spaces', type: 'number', option:'spaces', desc: 'Specifies amount of space indentation in the output.' },
{ arg: 'trim', type: 'flag', option:'trim', desc: 'Any whitespaces surrounding texts will be trimmed.' },
// { arg: 'sanitize', type: 'flag', option:'sanitize', desc: 'Special xml characters will be replaced with entity codes.' },
{ arg: 'native-type', type: 'flag', option:'nativeType', desc: 'Numbers and boolean will be converted (coerced) to native type instead of text.' },
{ arg: 'always-array', type: 'flag', option:'alwaysArray', desc: 'Every element will always be an array type (applicable if --compact is set).' },
{ arg: 'always-children', type: 'flag', option:'alwaysChildren', desc: 'Every element will always contain sub-elements (applicable if --compact is not set).' },
{ arg: 'instruction-attr', type: 'flag', option:'instructionHasAttributes', desc: 'Whether to parse contents of processing instruction as attributes.' },
{ arg: 'full-tag', type: 'flag', option:'fullTagEmptyElement', desc: 'XML elements will always be in <a></a> form.' },
{ arg: 'no-decl', type: 'flag', option:'ignoreDeclaration', desc: 'Declaration instruction <?xml?> will be ignored.' },
{ arg: 'no-decl', type: 'flag', option:'ignoreInstruction', desc: 'Processing instruction <?...?> will be ignored.' },
{ arg: 'no-attr', type: 'flag', option:'ignoreAttributes', desc: 'Attributes of elements will be ignored.' },
{ arg: 'no-text', type: 'flag', option:'ignoreText', desc: 'Texts of elements will be ignored.' },
{ arg: 'no-cdata', type: 'flag', option:'ignoreCdata', desc: 'CData of elements will be ignored.' },
{ arg: 'no-doctype', type: 'flag', option:'ignoreDoctype', desc: 'DOCTYPE of elements will be ignored.' },
{ arg: 'no-comment', type: 'flag', option:'ignoreComment', desc: 'Comments of elements will be ignored.' },
{ arg: 'text-key', type: 'string', option:'textKey', desc: 'To change the default \'text\' key.' },
{ arg: 'cdata-key', type: 'string', option:'cdataKey', desc: 'To change the default \'cdata\' key.' },
{ arg: 'doctype-key', type: 'string', option:'doctypeKey', desc: 'To change the default \'doctype\' key.' },
{ arg: 'comment-key', type: 'string', option:'commentKey', desc: 'To change the default \'comment\' key.' },
{ arg: 'attributes-key', type: 'string', option:'attributesKey', desc: 'To change the default \'attributes\' key.' },
{ arg: 'declaration-key', type: 'string', option:'declarationKey', desc: 'To change the default \'declaration\' key <?xml?>.' },
{ arg: 'instruction-key', type: 'string', option:'instructionKey', desc: 'To change the default \'processing instruction\' key <?...?>.' },
{ arg: 'type-key', type: 'string', option:'typeKey', desc: 'To change the default \'type\' key (applicable if --compact is not set).' },
{ arg: 'name-key', type: 'string', option:'nameKey', desc: 'To change the default \'name\' key (applicable if --compact is not set).' },
{ arg: 'elements-key', type: 'string', option:'elementsKey', desc: 'To change the default \'elements\' key (applicable if --compact is not set).' }
];

@@ -52,36 +51,35 @@

process.stdin.on('readable', function () {
var chunk = process.stdin.read();
if (chunk !== null) {
stream += chunk;
}
var chunk = process.stdin.read();
if (chunk !== null) {
stream += chunk;
}
});
process.stdin.on('end', function () {
process.stdout.write(xml2json(stream, {}) + '\n');
process.stdout.write(xml2json(stream, {}) + '\n');
});
options = common.mapCommandLineArgs(requiredArgs, optionalArgs);
options = helper.mapCommandLineArgs(requiredArgs, optionalArgs);
if (options.version) {
console.log(project.version);
process.exit(0);
console.log(project.version);
process.exit(0);
} else if (options.help || process.argv.length <= 2 + requiredArgs.length - 1) {
console.log(common.getCommandLineHelp('xml-js', requiredArgs, optionalArgs));
process.exit(process.argv.length <= 2 ? 1 : 0);
console.log(helper.getCommandLineHelp('xml-js', requiredArgs, optionalArgs));
process.exit(process.argv.length <= 2 ? 1 : 0);
} else if ('src' in options) {
if (fs.statSync(options.src).isFile()) {
if (options.src.split('.').pop() === 'xml') {
output = xml2json(fs.readFileSync(options.src, 'utf8'), options);
} else if (options.src.split('.').pop() === 'json') {
output = json2xml(fs.readFileSync(options.src, 'utf8'), options);
}
if (options.out) {
fs.writeFileSync(options.out, output, 'utf8');
} else {
console.log(output);
}
process.exit(0);
if (fs.statSync(options.src).isFile()) {
if (options.src.split('.').pop() === 'xml') {
output = xml2json(fs.readFileSync(options.src, 'utf8'), options);
} else if (options.src.split('.').pop() === 'json') {
output = json2xml(fs.readFileSync(options.src, 'utf8'), options);
}
if (options.out) {
fs.writeFileSync(options.out, output, 'utf8');
} else {
console.log(output);
}
process.exit(0);
}
} else {
process.exit(1);
process.exit(1);
}

@@ -9,6 +9,6 @@ /*jslint node:true */

module.exports = {
xml2js: xml2js,
xml2json: xml2json,
js2xml: js2xml,
json2xml: json2xml
};
xml2js: xml2js,
xml2json: xml2json,
js2xml: js2xml,
json2xml: json2xml
};

@@ -1,266 +0,302 @@

var common = require('./common');
var helper = require('./options-helper');
var currentElement, currentElementName;
function validateOptions(userOptions) {
var options = common.copyOptions(userOptions);
common.ensureFlagExists('ignoreDeclaration', options);
common.ensureFlagExists('ignoreInstruction', options);
common.ensureFlagExists('ignoreAttributes', options);
common.ensureFlagExists('ignoreText', options);
common.ensureFlagExists('ignoreComment', options);
common.ensureFlagExists('ignoreCdata', options);
common.ensureFlagExists('ignoreDoctype', options);
common.ensureFlagExists('compact', options);
common.ensureFlagExists('indentText', options);
common.ensureFlagExists('indentCdata', options);
common.ensureFlagExists('indentAttributes', options);
common.ensureFlagExists('indentInstruction', options);
common.ensureFlagExists('fullTagEmptyElement', options);
common.ensureFlagExists('noQuotesForNativeAttributes', options);
common.ensureSpacesExists(options);
if (typeof options.spaces === 'number') {
options.spaces = Array(options.spaces + 1).join(' ');
}
common.ensureKeyExists('declaration', options);
common.ensureKeyExists('instruction', options);
common.ensureKeyExists('attributes', options);
common.ensureKeyExists('text', options);
common.ensureKeyExists('comment', options);
common.ensureKeyExists('cdata', options);
common.ensureKeyExists('doctype', options);
common.ensureKeyExists('type', options);
common.ensureKeyExists('name', options);
common.ensureKeyExists('elements', options);
return options;
var options = helper.copyOptions(userOptions);
helper.ensureFlagExists('ignoreDeclaration', options);
helper.ensureFlagExists('ignoreInstruction', options);
helper.ensureFlagExists('ignoreAttributes', options);
helper.ensureFlagExists('ignoreText', options);
helper.ensureFlagExists('ignoreComment', options);
helper.ensureFlagExists('ignoreCdata', options);
helper.ensureFlagExists('ignoreDoctype', options);
helper.ensureFlagExists('compact', options);
helper.ensureFlagExists('indentText', options);
helper.ensureFlagExists('indentCdata', options);
helper.ensureFlagExists('indentAttributes', options);
helper.ensureFlagExists('indentInstruction', options);
helper.ensureFlagExists('fullTagEmptyElement', options);
helper.ensureFlagExists('noQuotesForNativeAttributes', options);
helper.ensureSpacesExists(options);
if (typeof options.spaces === 'number') {
options.spaces = Array(options.spaces + 1).join(' ');
}
helper.ensureKeyExists('declaration', options);
helper.ensureKeyExists('instruction', options);
helper.ensureKeyExists('attributes', options);
helper.ensureKeyExists('text', options);
helper.ensureKeyExists('comment', options);
helper.ensureKeyExists('cdata', options);
helper.ensureKeyExists('doctype', options);
helper.ensureKeyExists('type', options);
helper.ensureKeyExists('name', options);
helper.ensureKeyExists('elements', options);
helper.checkFnExists('doctype', options);
helper.checkFnExists('instruction', options);
helper.checkFnExists('cdata', options);
helper.checkFnExists('comment', options);
helper.checkFnExists('text', options);
helper.checkFnExists('instructionName', options);
helper.checkFnExists('elementName', options);
helper.checkFnExists('attributeName', options);
helper.checkFnExists('attributeValue', options);
helper.checkFnExists('attributes', options);
return options;
}
function writeIndentation(options, depth, firstLine) {
return (!firstLine && options.spaces ? '\n' : '') + Array(depth + 1).join(options.spaces);
return (!firstLine && options.spaces ? '\n' : '') + Array(depth + 1).join(options.spaces);
}
function writeAttributes(attributes, options, depth) {
if (options.ignoreAttributes) {
return '';
if (options.ignoreAttributes) {
return '';
}
if ('attributesFn' in options) {
attributes = options.attributesFn(attributes, currentElementName, currentElement);
}
var key, attr, attrName, quote, result = '';
for (key in attributes) {
if (attributes.hasOwnProperty(key)) {
quote = options.noQuotesForNativeAttributes && typeof attributes[key] !== 'string' ? '' : '"';
attr = '' + attributes[key]; // ensure number and boolean are converted to String
attr = attr.replace(/"/g, '&quot;');
attrName = 'attributeNameFn' in options ? options.attributeNameFn(key, attr, currentElementName, currentElement) : key;
result += (options.spaces && options.indentAttributes? writeIndentation(options, depth+1, false) : ' ');
result += attrName + '=' + quote + ('attributeValueFn' in options ? options.attributeValueFn(attr, key, currentElementName, currentElement) : attr) + quote;
}
var key, attr, quote, result = '';
for (key in attributes) {
if (attributes.hasOwnProperty(key)) {
quote = options.noQuotesForNativeAttributes && typeof attributes[key] !== 'string' ? '' : '"';
attr = '' + attributes[key]; // ensure Number and Boolean are converted to String
result += (options.spaces && options.indentAttributes? writeIndentation(options, depth+1, false) : ' ');
result += key + '=' + quote + attr.replace(/"/g, '&quot;') + quote;
}
}
if (attributes && Object.keys(attributes).length && options.spaces && options.indentAttributes) {
result += writeIndentation(options, depth, false);
}
return result;
}
if (attributes && Object.keys(attributes).length && options.spaces && options.indentAttributes) {
result += writeIndentation(options, depth, false);
}
return result;
}
function writeDeclaration(declaration, options, depth) {
return options.ignoreDeclaration ? '' : '<?xml' + writeAttributes(declaration[options.attributesKey], options, depth) + '?>';
currentElement = declaration;
currentElementName = 'xml';
return options.ignoreDeclaration ? '' : '<?' + 'xml' + writeAttributes(declaration[options.attributesKey], options, depth) + '?>';
}
function writeInstruction(instruction, options, depth) {
if (options.ignoreInstruction) {
return '';
if (options.ignoreInstruction) {
return '';
}
var key;
for (key in instruction) {
if (instruction.hasOwnProperty(key)) {
break;
}
var key;
for (key in instruction) {
if (instruction.hasOwnProperty(key)) {
break;
}
}
if (typeof instruction[key] === 'object') {
return '<?' + key + writeAttributes(instruction[key][options.attributesKey], options, depth) + '?>';
} else {
return '<?' + key + (instruction[key] ? ' ' + instruction[key] : '') + '?>';
}
}
var instructionName = 'instructionNameFn' in options ? options.instructionNameFn(key, instruction[key], currentElementName, currentElement) : key;
if (typeof instruction[key] === 'object') {
currentElement = instruction;
currentElementName = instructionName;
return '<?' + instructionName + writeAttributes(instruction[key][options.attributesKey], options, depth) + '?>';
} else {
var instructionValue = instruction[key] ? instruction[key] : '';
if ('instructionFn' in options) instructionValue = options.instructionFn(instructionValue, key, currentElementName, currentElement);
return '<?' + instructionName + (instructionValue ? ' ' + instructionValue : '') + '?>';
}
}
function writeComment(comment, options) {
return options.ignoreComment ? '' : '<!--' + comment + '-->';
return options.ignoreComment ? '' : '<!--' + ('commentFn' in options ? options.commentFn(comment, currentElementName, currentElement) : comment) + '-->';
}
function writeCdata(cdata, options) {
return options.ignoreCdata ? '' : '<![CDATA[' + cdata + ']]>';
return options.ignoreCdata ? '' : '<![CDATA[' + ('cdataFn' in options ? options.cdataFn(cdata, currentElementName, currentElement) : cdata) + ']]>';
}
function writeDoctype(doctype, options) {
return options.ignoreDoctype ? '' : '<!DOCTYPE ' + doctype + '>';
return options.ignoreDoctype ? '' : '<!DOCTYPE ' + ('doctypeFn' in options ? options.doctypeFn(doctype, currentElementName, currentElement) : doctype) + '>';
}
function writeText(text, options) {
text = '' + text; // ensure Number and Boolean are converted to String
text = text.replace(/&amp;/g, '&'); // desanitize to avoid double sanitization
return options.ignoreText ? '' : text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
if (options.ignoreText) return '';
text = '' + text; // ensure Number and Boolean are converted to String
text = text.replace(/&amp;/g, '&'); // desanitize to avoid double sanitization
text = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
return 'textFn' in options ? options.textFn(text, currentElementName, currentElement) : text;
}
function hasContent(element, options) {
var i;
if (element.elements && element.elements.length) {
for (i = 0; i < element.elements.length; ++i) {
switch (element.elements[i][options.typeKey]) {
case 'text':
if (options.indentText) {
return true;
}
break; // skip to next key
case 'cdata':
if (options.indentCdata) {
return true;
}
break; // skip to next key
case 'instruction':
if (options.indentInstruction) {
return true;
}
break; // skip to next key
case 'doctype':
case 'comment':
case 'element':
return true;
default:
return true;
}
var i;
if (element.elements && element.elements.length) {
for (i = 0; i < element.elements.length; ++i) {
switch (element.elements[i][options.typeKey]) {
case 'text':
if (options.indentText) {
return true;
}
break; // skip to next key
case 'cdata':
if (options.indentCdata) {
return true;
}
break; // skip to next key
case 'instruction':
if (options.indentInstruction) {
return true;
}
break; // skip to next key
case 'doctype':
case 'comment':
case 'element':
return true;
default:
return true;
}
}
return false;
}
return false;
}
function writeElement(element, options, depth) {
var xml = '';
xml += '<' + element.name;
if (element[options.attributesKey]) {
xml += writeAttributes(element[options.attributesKey], options, depth);
currentElement = element;
currentElementName = element.name;
var xml = '', elementName = 'elementNameFn' in options ? options.elementNameFn(element.name, element) : element.name;
xml += '<' + elementName;
if (element[options.attributesKey]) {
xml += writeAttributes(element[options.attributesKey], options, depth);
}
if (options.fullTagEmptyElement || (element[options.elementsKey] && element[options.elementsKey].length) || (element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve')) {
xml += '>';
if (element[options.elementsKey] && element[options.elementsKey].length) {
xml += writeElements(element[options.elementsKey], options, depth + 1);
currentElement = element;
currentElementName = element.name;
}
if (options.fullTagEmptyElement || (element[options.elementsKey] && element[options.elementsKey].length) || (element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve')) {
xml += '>';
if (element[options.elementsKey] && element[options.elementsKey].length) {
xml += writeElements(element[options.elementsKey], options, depth + 1);
}
xml += options.spaces && hasContent(element, options) ? '\n' + Array(depth + 1).join(options.spaces) : '';
xml += '</' + element.name + '>';
} else {
xml += '/>';
}
return xml;
xml += options.spaces && hasContent(element, options) ? '\n' + Array(depth + 1).join(options.spaces) : '';
xml += '</' + elementName + '>';
} else {
xml += '/>';
}
return xml;
}
function writeElements(elements, options, depth, firstLine) {
return elements.reduce(function (xml, element) {
var indent = writeIndentation(options, depth, firstLine && !xml);
switch (element.type) {
case 'element': return xml + indent + writeElement(element, options, depth);
case 'comment': return xml + indent + writeComment(element[options.commentKey], options);
case 'doctype': return xml + indent + writeDoctype(element[options.doctypeKey], options);
case 'cdata': return xml + (options.indentCdata ? indent : '') + writeCdata(element[options.cdataKey], options);
case 'text': return xml + (options.indentText ? indent : '') + writeText(element[options.textKey], options);
case 'instruction':
var instruction = {};
instruction[element[options.nameKey]] = element[options.attributesKey] ? element : element[options.instructionKey];
return xml + (options.indentInstruction ? indent : '') + writeInstruction(instruction, options, depth);
}
}, '');
return elements.reduce(function (xml, element) {
var indent = writeIndentation(options, depth, firstLine && !xml);
switch (element.type) {
case 'element': return xml + indent + writeElement(element, options, depth);
case 'comment': return xml + indent + writeComment(element[options.commentKey], options);
case 'doctype': return xml + indent + writeDoctype(element[options.doctypeKey], options);
case 'cdata': return xml + (options.indentCdata ? indent : '') + writeCdata(element[options.cdataKey], options);
case 'text': return xml + (options.indentText ? indent : '') + writeText(element[options.textKey], options);
case 'instruction':
var instruction = {};
instruction[element[options.nameKey]] = element[options.attributesKey] ? element : element[options.instructionKey];
return xml + (options.indentInstruction ? indent : '') + writeInstruction(instruction, options, depth);
}
}, '');
}
function hasContentCompact(element, options, anyContent) {
var key;
for (key in element) {
if (element.hasOwnProperty(key)) {
switch (key) {
case options.parentKey:
case options.attributesKey:
break; // skip to next key
case options.textKey:
if (options.indentText || anyContent) {
return true;
}
break; // skip to next key
case options.cdataKey:
if (options.indentCdata || anyContent) {
return true;
}
break; // skip to next key
case options.instructionKey:
if (options.indentInstruction || anyContent) {
return true;
}
break; // skip to next key
case options.doctypeKey:
case options.commentKey:
return true;
default:
return true;
}
var key;
for (key in element) {
if (element.hasOwnProperty(key)) {
switch (key) {
case options.parentKey:
case options.attributesKey:
break; // skip to next key
case options.textKey:
if (options.indentText || anyContent) {
return true;
}
break; // skip to next key
case options.cdataKey:
if (options.indentCdata || anyContent) {
return true;
}
break; // skip to next key
case options.instructionKey:
if (options.indentInstruction || anyContent) {
return true;
}
break; // skip to next key
case options.doctypeKey:
case options.commentKey:
return true;
default:
return true;
}
}
return false;
}
return false;
}
function writeElementCompact(element, name, options, depth, indent) {
if (typeof element === 'undefined' || element === null) {
return options.fullTagEmptyElement ? '<' + name + '></' + name + '>' : '<' + name + '/>';
currentElement = element;
currentElementName = name;
var elementName = 'elementNameFn' in options ? options.elementNameFn(name, element) : name;
if (typeof element === 'undefined' || element === null) {
return options.fullTagEmptyElement ? '<' + elementName + '></' + elementName + '>' : '<' + elementName + '/>';
}
var xml = '';
if (name) {
xml += '<' + elementName;
if (typeof element !== 'object') {
xml += '>' + writeText(element,options) + '</' + elementName + '>';
return xml;
}
var xml = '';
if (name) {
xml += '<' + name;
if (typeof element !== 'object') {
xml += '>' + writeText(element,options) + '</' + name + '>';
return xml;
}
if (element[options.attributesKey]) {
xml += writeAttributes(element[options.attributesKey], options, depth);
}
if (options.fullTagEmptyElement || hasContentCompact(element, options, true) || element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve') {
xml += '>';
} else {
xml += '/>';
return xml;
}
if (element[options.attributesKey]) {
xml += writeAttributes(element[options.attributesKey], options, depth);
}
xml += writeElementsCompact(element, options, depth + 1, false);
if (name) {
xml += (indent ? writeIndentation(options, depth, false) : '') + '</' + name + '>';
if (options.fullTagEmptyElement || hasContentCompact(element, options, true) || element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve') {
xml += '>';
} else {
xml += '/>';
return xml;
}
return xml;
}
xml += writeElementsCompact(element, options, depth + 1, false);
currentElement = element;
currentElementName = name;
if (name) {
xml += (indent ? writeIndentation(options, depth, false) : '') + '</' + elementName + '>';
}
return xml;
}
function writeElementsCompact(element, options, depth, firstLine) {
var i, key, nodes, xml = '';
for (key in element) {
if (element.hasOwnProperty(key)) {
nodes = element[key] instanceof Array ? element[key] : [element[key]];
for (i = 0; i < nodes.length; ++i) {
switch (key) {
case options.declarationKey: xml += writeDeclaration(nodes[i], options, depth); break;
case options.instructionKey: xml += (options.indentInstruction ? writeIndentation(options, depth, firstLine) : '') + writeInstruction(nodes[i], options, depth); break;
case options.attributesKey: case options.parentKey: break; // skip
case options.textKey: xml += (options.indentText ? writeIndentation(options, depth, firstLine) : '') + writeText(nodes[i], options); break;
case options.cdataKey: xml += (options.indentCdata ? writeIndentation(options, depth, firstLine) : '') + writeCdata(nodes[i], options); break;
case options.doctypeKey: xml += writeIndentation(options, depth, firstLine) + writeDoctype(nodes[i], options); break;
case options.commentKey: xml += writeIndentation(options, depth, firstLine) + writeComment(nodes[i], options); break;
default: xml += writeIndentation(options, depth, firstLine) + writeElementCompact(nodes[i], key, options, depth, hasContentCompact(nodes[i], options));
}
firstLine = firstLine && !xml;
}
var i, key, nodes, xml = '';
for (key in element) {
if (element.hasOwnProperty(key)) {
nodes = element[key] instanceof Array ? element[key] : [element[key]];
for (i = 0; i < nodes.length; ++i) {
switch (key) {
case options.declarationKey: xml += writeDeclaration(nodes[i], options, depth); break;
case options.instructionKey: xml += (options.indentInstruction ? writeIndentation(options, depth, firstLine) : '') + writeInstruction(nodes[i], options, depth); break;
case options.attributesKey: case options.parentKey: break; // skip
case options.textKey: xml += (options.indentText ? writeIndentation(options, depth, firstLine) : '') + writeText(nodes[i], options); break;
case options.cdataKey: xml += (options.indentCdata ? writeIndentation(options, depth, firstLine) : '') + writeCdata(nodes[i], options); break;
case options.doctypeKey: xml += writeIndentation(options, depth, firstLine) + writeDoctype(nodes[i], options); break;
case options.commentKey: xml += writeIndentation(options, depth, firstLine) + writeComment(nodes[i], options); break;
default: xml += writeIndentation(options, depth, firstLine) + writeElementCompact(nodes[i], key, options, depth, hasContentCompact(nodes[i], options));
}
firstLine = firstLine && !xml;
}
}
return xml;
}
return xml;
}
module.exports = function (js, options) {
'use strict';
options = validateOptions(options);
var xml = '';
if (options.compact) {
xml = writeElementsCompact(js, options, 0, true);
} else {
if (js[options.declarationKey]) {
xml += writeDeclaration(js[options.declarationKey], options, 0);
}
if (js[options.elementsKey] && js[options.elementsKey].length) {
xml += writeElements(js[options.elementsKey], options, 0, !xml);
}
options = validateOptions(options);
var xml = '';
currentElement = js;
currentElementName = '_root_';
if (options.compact) {
xml = writeElementsCompact(js, options, 0, true);
} else {
if (js[options.declarationKey]) {
xml += writeDeclaration(js[options.declarationKey], options, 0);
}
return xml;
if (js[options.elementsKey] && js[options.elementsKey].length) {
xml += writeElements(js[options.elementsKey], options, 0, !xml);
}
}
return xml;
};
var js2xml = require('./js2xml.js');
module.exports = function (json, options) {
'use strict';
if (json instanceof Buffer) {
json = json.toString();
if (json instanceof Buffer) {
json = json.toString();
}
var js = null;
if (typeof (json) === 'string') {
try {
js = JSON.parse(json);
} catch (e) {
throw new Error('The JSON structure is invalid');
}
var js = null;
if (typeof (json) === 'string') {
try {
js = JSON.parse(json);
} catch (e) {
throw new Error("The JSON structure is invalid");
}
} else {
js = json;
}
return js2xml(js, options);
};
} else {
js = json;
}
return js2xml(js, options);
};
var sax = require('sax');
var expat /*= require('node-expat');*/ = { on: function () { }, parse: function () { } };
var common = require('./common');
var helper = require('./options-helper');

@@ -10,241 +10,297 @@ var options;

function validateOptions(userOptions) {
options = common.copyOptions(userOptions);
common.ensureFlagExists('ignoreDeclaration', options);
common.ensureFlagExists('ignoreInstruction', options);
common.ensureFlagExists('ignoreAttributes', options);
common.ensureFlagExists('ignoreText', options);
common.ensureFlagExists('ignoreComment', options);
common.ensureFlagExists('ignoreCdata', options);
common.ensureFlagExists('ignoreDoctype', options);
common.ensureFlagExists('compact', options);
common.ensureFlagExists('alwaysArray', options);
common.ensureFlagExists('alwaysChildren', options);
common.ensureFlagExists('addParent', options);
common.ensureFlagExists('trim', options);
common.ensureFlagExists('nativeType', options);
common.ensureFlagExists('sanitize', options);
common.ensureFlagExists('instructionHasAttributes', options);
common.ensureFlagExists('captureSpacesBetweenElements', options);
common.ensureKeyExists('declaration', options);
common.ensureKeyExists('instruction', options);
common.ensureKeyExists('attributes', options);
common.ensureKeyExists('text', options);
common.ensureKeyExists('comment', options);
common.ensureKeyExists('cdata', options);
common.ensureKeyExists('doctype', options);
common.ensureKeyExists('type', options);
common.ensureKeyExists('name', options);
common.ensureKeyExists('elements', options);
common.ensureKeyExists('parent', options);
return options;
options = helper.copyOptions(userOptions);
helper.ensureFlagExists('ignoreDeclaration', options);
helper.ensureFlagExists('ignoreInstruction', options);
helper.ensureFlagExists('ignoreAttributes', options);
helper.ensureFlagExists('ignoreText', options);
helper.ensureFlagExists('ignoreComment', options);
helper.ensureFlagExists('ignoreCdata', options);
helper.ensureFlagExists('ignoreDoctype', options);
helper.ensureFlagExists('compact', options);
helper.ensureFlagExists('alwaysArray', options);
helper.ensureFlagExists('alwaysChildren', options);
helper.ensureFlagExists('addParent', options);
helper.ensureFlagExists('trim', options);
helper.ensureFlagExists('nativeType', options);
helper.ensureFlagExists('sanitize', options);
helper.ensureFlagExists('instructionHasAttributes', options);
helper.ensureFlagExists('captureSpacesBetweenElements', options);
helper.ensureKeyExists('declaration', options);
helper.ensureKeyExists('instruction', options);
helper.ensureKeyExists('attributes', options);
helper.ensureKeyExists('text', options);
helper.ensureKeyExists('comment', options);
helper.ensureKeyExists('cdata', options);
helper.ensureKeyExists('doctype', options);
helper.ensureKeyExists('type', options);
helper.ensureKeyExists('name', options);
helper.ensureKeyExists('elements', options);
helper.ensureKeyExists('parent', options);
helper.checkFnExists('doctype', options);
helper.checkFnExists('instruction', options);
helper.checkFnExists('cdata', options);
helper.checkFnExists('comment', options);
helper.checkFnExists('text', options);
helper.checkFnExists('instructionName', options);
helper.checkFnExists('elementName', options);
helper.checkFnExists('attributeName', options);
helper.checkFnExists('attributeValue', options);
helper.checkFnExists('attributes', options);
return options;
}
function nativeType(value) {
var nValue = Number(value);
if (!isNaN(nValue)) {
return nValue;
var nValue = Number(value);
if (!isNaN(nValue)) {
return nValue;
}
var bValue = value.toLowerCase();
if (bValue === 'true') {
return true;
} else if (bValue === 'false') {
return false;
}
return value;
}
function addField(type, value) {
var key;
if (options.compact) {
if (!currentElement[options[type + 'Key']] && options.alwaysArray) {
currentElement[options[type + 'Key']] = [];
}
var bValue = value.toLowerCase();
if (bValue === 'true') {
return true;
} else if (bValue === 'false') {
return false;
if (currentElement[options[type + 'Key']] && !(currentElement[options[type + 'Key']] instanceof Array)) {
currentElement[options[type + 'Key']] = [currentElement[options[type + 'Key']]];
}
return value;
}
function addField(type, value, options) {
if (options.compact) {
if (!currentElement[options[type + 'Key']] && options.alwaysArray) {
currentElement[options[type + 'Key']] = [];
if (type + 'Fn' in options && typeof value === 'string') {
value = options[type + 'Fn'](value, currentElement);
}
if (type === 'instruction' && ('instructionFn' in options || 'instructionNameFn' in options)) {
for (key in value) {
if (value.hasOwnProperty(key)) {
if ('instructionFn' in options) {
value[key] = options.instructionFn(value[key], key, currentElement);
} else {
var temp = value[key];
delete value[key];
value[options.instructionNameFn(key, temp, currentElement)] = temp;
}
}
if (currentElement[options[type + 'Key']] && !(currentElement[options[type + 'Key']] instanceof Array)) {
currentElement[options[type + 'Key']] = [currentElement[options[type + 'Key']]];
}
if (currentElement[options[type + 'Key']] instanceof Array) {
currentElement[options[type + 'Key']].push(value);
} else {
currentElement[options[type + 'Key']] = value;
}
}
}
if (currentElement[options[type + 'Key']] instanceof Array) {
currentElement[options[type + 'Key']].push(value);
} else {
if (!currentElement[options.elementsKey]) {
currentElement[options.elementsKey] = [];
currentElement[options[type + 'Key']] = value;
}
} else {
if (!currentElement[options.elementsKey]) {
currentElement[options.elementsKey] = [];
}
var element = {};
element[options.typeKey] = type;
if (type === 'instruction') {
for (key in value) {
if (value.hasOwnProperty(key)) {
break;
}
var key, element = {};
element[options.typeKey] = type;
if (type === 'instruction' && typeof value === 'object') {
for (key in value) {
if (value.hasOwnProperty(key)) {
break;
}
}
element[options.nameKey] = key;
if (options.instructionHasAttributes) {
element[options.attributesKey] = value[key][options.attributesKey];
} else {
element[options[type + 'Key']] = value[key];
}
} else {
element[options[type + 'Key']] = value;
}
element[options.nameKey] = 'instructionNameFn' in options ? options.instructionNameFn(key, value, currentElement) : key;
if (options.instructionHasAttributes) {
element[options.attributesKey] = value[key][options.attributesKey];
if ('instructionFn' in options) {
element[options.attributesKey] = options.instructionFn(element[options.attributesKey], key, currentElement);
}
if (options.addParent) {
element[options.parentKey] = currentElement;
} else {
if ('instructionFn' in options) {
value[key] = options.instructionFn(value[key], key, currentElement);
}
currentElement[options.elementsKey].push(element);
element[options.instructionKey] = value[key];
}
} else {
if (type + 'Fn' in options) {
value = options[type + 'Fn'](value, currentElement);
}
element[options[type + 'Key']] = value;
}
if (options.addParent) {
element[options.parentKey] = currentElement;
}
currentElement[options.elementsKey].push(element);
}
}
function onInstruction(instruction) {
var attributes = {};
if (instruction.body && (instruction.name.toLowerCase() === 'xml' || options.instructionHasAttributes)) {
var attrsRegExp = /([\w:-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|(\w+))\s*/g;
var match;
while ((match = attrsRegExp.exec(instruction.body)) !== null) {
attributes[match[1]] = match[2] || match[3] || match[4];
function manipulateAttributes(attributes) {
if ('attributesFn' in options && attributes) {
attributes = options.attributesFn(attributes, currentElement);
}
if ((options.trim || 'attributeValueFn' in options || 'attributeNameFn' in options) && attributes) {
var key;
for (key in attributes) {
if (attributes.hasOwnProperty(key)) {
if (options.trim) attributes[key] = attributes[key].trim();
if ('attributeValueFn' in options) attributes[key] = options.attributeValueFn(attributes[key], key, currentElement);
if ('attributeNameFn' in options) {
var temp = attributes[key];
delete attributes[key];
attributes[options.attributeNameFn(key, attributes[key], currentElement)] = temp;
}
}
}
if (instruction.name.toLowerCase() === 'xml') {
if (options.ignoreDeclaration) {
return;
}
currentElement[options.declarationKey] = {};
if (Object.keys(attributes).length) {
currentElement[options.declarationKey][options.attributesKey] = attributes;
}
if (options.addParent) {
currentElement[options.declarationKey][options.parentKey] = currentElement;
}
} else {
if (options.ignoreInstruction) {
return;
}
if (options.trim) {
instruction.body = instruction.body.trim();
}
var value = {};
if (options.instructionHasAttributes && Object.keys(attributes).length) {
value[instruction.name] = {};
value[instruction.name][options.attributesKey] = attributes;
} else {
value[instruction.name] = instruction.body;
}
addField('instruction', value, options);
}
}
return attributes;
}
function onStartElement(name, attributes) {
var key, element;
if (typeof name === 'object') {
attributes = name.attributes;
name = name.name;
function onInstruction(instruction) {
var attributes = {};
if (instruction.body && (instruction.name.toLowerCase() === 'xml' || options.instructionHasAttributes)) {
var attrsRegExp = /([\w:-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|(\w+))\s*/g;
var match;
while ((match = attrsRegExp.exec(instruction.body)) !== null) {
attributes[match[1]] = match[2] || match[3] || match[4];
}
if (options.trim && attributes) {
for (key in attributes) {
if (attributes.hasOwnProperty(key)) {
attributes[key] = attributes[key].trim();
}
}
attributes = manipulateAttributes(attributes);
}
if (instruction.name.toLowerCase() === 'xml') {
if (options.ignoreDeclaration) {
return;
}
if (options.compact) {
element = {};
if (!options.ignoreAttributes && attributes && Object.keys(attributes).length) {
element[options.attributesKey] = {};
for (key in attributes) {
if (attributes.hasOwnProperty(key)) {
element[options.attributesKey][key] = attributes[key];
}
}
}
if (!(name in currentElement) && options.alwaysArray) {
currentElement[name] = [];
}
if (currentElement[name] && !(currentElement[name] instanceof Array)) {
currentElement[name] = [currentElement[name]];
}
if (currentElement[name] instanceof Array) {
currentElement[name].push(element);
} else {
currentElement[name] = element;
}
currentElement[options.declarationKey] = {};
if (Object.keys(attributes).length) {
currentElement[options.declarationKey][options.attributesKey] = attributes;
}
if (options.addParent) {
currentElement[options.declarationKey][options.parentKey] = currentElement;
}
} else {
if (options.ignoreInstruction) {
return;
}
if (options.trim) {
instruction.body = instruction.body.trim();
}
var value = {};
if (options.instructionHasAttributes && Object.keys(attributes).length) {
value[instruction.name] = {};
value[instruction.name][options.attributesKey] = attributes;
} else {
if (!currentElement[options.elementsKey]) {
currentElement[options.elementsKey] = [];
}
element = {};
element[options.typeKey] = 'element';
element[options.nameKey] = name;
if (!options.ignoreAttributes && attributes && Object.keys(attributes).length) {
element[options.attributesKey] = attributes;
}
if (options.alwaysChildren) {
element[options.elementsKey] = [];
}
currentElement[options.elementsKey].push(element);
value[instruction.name] = instruction.body;
}
// if (options.addParent) {
element[options.parentKey] = currentElement;
// }
currentElement = element;
addField('instruction', value);
}
}
function onText(text) {
if (options.ignoreText) {
return;
function onStartElement(name, attributes) {
var element;
if (typeof name === 'object') {
attributes = name.attributes;
name = name.name;
}
attributes = manipulateAttributes(attributes);
if ('elementNameFn' in options) {
name = options.elementNameFn(name, currentElement);
}
if (options.compact) {
element = {};
if (!options.ignoreAttributes && attributes && Object.keys(attributes).length) {
element[options.attributesKey] = {};
var key;
for (key in attributes) {
if (attributes.hasOwnProperty(key)) {
element[options.attributesKey][key] = attributes[key];
}
}
}
if (!text.trim() && !options.captureSpacesBetweenElements) {
return;
if (!(name in currentElement) && options.alwaysArray) {
currentElement[name] = [];
}
if (options.trim) {
text = text.trim();
if (currentElement[name] && !(currentElement[name] instanceof Array)) {
currentElement[name] = [currentElement[name]];
}
if (options.nativeType) {
text = nativeType(text);
if (currentElement[name] instanceof Array) {
currentElement[name].push(element);
} else {
currentElement[name] = element;
}
if (options.sanitize) {
text = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
} else {
if (!currentElement[options.elementsKey]) {
currentElement[options.elementsKey] = [];
}
addField('text', text, options);
element = {};
element[options.typeKey] = 'element';
element[options.nameKey] = name;
if (!options.ignoreAttributes && attributes && Object.keys(attributes).length) {
element[options.attributesKey] = attributes;
}
if (options.alwaysChildren) {
element[options.elementsKey] = [];
}
currentElement[options.elementsKey].push(element);
}
// if (options.addParent) {
element[options.parentKey] = currentElement;
// }
currentElement = element;
}
function onText(text) {
if (options.ignoreText) {
return;
}
if (!text.trim() && !options.captureSpacesBetweenElements) {
return;
}
if (options.trim) {
text = text.trim();
}
if (options.nativeType) {
text = nativeType(text);
}
if (options.sanitize) {
text = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
addField('text', text);
}
function onComment(comment) {
if (options.ignoreComment) {
return;
}
if (options.trim) {
comment = comment.trim();
}
addField('comment', comment, options);
if (options.ignoreComment) {
return;
}
if (options.trim) {
comment = comment.trim();
}
addField('comment', comment);
}
function onEndElement(name) {
var parentElement = currentElement[options.parentKey];
if (!options.addParent) {
delete currentElement[options.parentKey];
}
currentElement = parentElement;
var parentElement = currentElement[options.parentKey];
if (!options.addParent) {
delete currentElement[options.parentKey];
}
currentElement = parentElement;
}
function onCdata(cdata) {
if (options.ignoreCdata) {
return;
}
if (options.trim) {
cdata = cdata.trim();
}
addField('cdata', cdata, options);
if (options.ignoreCdata) {
return;
}
if (options.trim) {
cdata = cdata.trim();
}
addField('cdata', cdata);
}
function onDoctype(doctype) {
if (options.ignoreDoctype) {
return;
}
doctype = doctype.replace(/^ /, '');
if (options.trim) {
doctype = doctype.trim();
}
addField('doctype', doctype, options);
if (options.ignoreDoctype) {
return;
}
doctype = doctype.replace(/^ /, '');
if (options.trim) {
doctype = doctype.trim();
}
addField('doctype', doctype);
}
function onError(error) {
error.note = error; //console.error(error);
error.note = error; //console.error(error);
}

@@ -254,45 +310,45 @@

var parser = pureJsParser ? sax.parser(true, {}) : parser = new expat.Parser('UTF-8');
var result = {};
currentElement = result;
var parser = pureJsParser ? sax.parser(true, {}) : parser = new expat.Parser('UTF-8');
var result = {};
currentElement = result;
options = validateOptions(userOptions);
options = validateOptions(userOptions);
if (pureJsParser) {
parser.onopentag = onStartElement;
parser.ontext = onText;
parser.oncomment = onComment;
parser.onclosetag = onEndElement;
parser.onerror = onError;
parser.oncdata = onCdata;
parser.ondoctype = onDoctype;
parser.onprocessinginstruction = onInstruction;
} else {
parser.on('startElement', onStartElement);
parser.on('text', onText);
parser.on('comment', onComment);
parser.on('endElement', onEndElement);
parser.on('error', onError);
//parser.on('startCdata', onStartCdata);
//parser.on('endCdata', onEndCdata);
//parser.on('entityDecl', onEntityDecl);
}
if (pureJsParser) {
parser.onopentag = onStartElement;
parser.ontext = onText;
parser.oncomment = onComment;
parser.onclosetag = onEndElement;
parser.onerror = onError;
parser.oncdata = onCdata;
parser.ondoctype = onDoctype;
parser.onprocessinginstruction = onInstruction;
} else {
parser.on('startElement', onStartElement);
parser.on('text', onText);
parser.on('comment', onComment);
parser.on('endElement', onEndElement);
parser.on('error', onError);
//parser.on('startCdata', onStartCdata);
//parser.on('endCdata', onEndCdata);
//parser.on('entityDecl', onEntityDecl);
}
if (pureJsParser) {
parser.write(xml).close();
} else {
if (!parser.parse(xml)) {
throw new Error('XML parsing error: ' + parser.getError());
}
if (pureJsParser) {
parser.write(xml).close();
} else {
if (!parser.parse(xml)) {
throw new Error('XML parsing error: ' + parser.getError());
}
}
if (result[options.elementsKey]) {
var temp = result[options.elementsKey];
delete result[options.elementsKey];
result[options.elementsKey] = temp;
delete result.text;
}
if (result[options.elementsKey]) {
var temp = result[options.elementsKey];
delete result[options.elementsKey];
result[options.elementsKey] = temp;
delete result.text;
}
return result;
return result;
};

@@ -1,23 +0,22 @@

var common = require('./common');
var helper = require('./options-helper');
var xml2js = require('./xml2js');
function validateOptions (userOptions) {
var options = common.copyOptions(userOptions);
common.ensureSpacesExists(options);
return options;
var options = helper.copyOptions(userOptions);
helper.ensureSpacesExists(options);
return options;
}
module.exports = function(xml, userOptions) {
'use strict';
var options, js, json, parentKey;
options = validateOptions(userOptions);
js = xml2js(xml, options);
parentKey = 'compact' in options && options.compact ? '_parent' : 'parent';
// parentKey = ptions.compact ? '_parent' : 'parent'; // consider this
if ('addParent' in options && options.addParent) {
json = JSON.stringify(js, function (k, v) { return k === parentKey? '_' : v; }, options.spaces);
} else {
json = JSON.stringify(js, null, options.spaces);
}
return json.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
var options, js, json, parentKey;
options = validateOptions(userOptions);
js = xml2js(xml, options);
parentKey = 'compact' in options && options.compact ? '_parent' : 'parent';
// parentKey = ptions.compact ? '_parent' : 'parent'; // consider this
if ('addParent' in options && options.addParent) {
json = JSON.stringify(js, function (k, v) { return k === parentKey? '_' : v; }, options.spaces);
} else {
json = JSON.stringify(js, null, options.spaces);
}
return json.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
};
{
"name": "xml-js",
"version": "1.5.2",
"version": "1.6.0",
"description": "A convertor between XML text and Javascript object / JSON text.",

@@ -51,8 +51,10 @@ "repository": {

"bundle:jasmine": "globify test/*_test.js --watch --verbose --list --outfile test/browse-jasmine/bundle.js",
"live:jasmine": "browser-sync start --port 9991 --server test/browse-jasmine/ --files test/browse-jasmine/ --no-open --no-ui --no-online",
"open:jasmine": "biased-opener --browser chrome http://localhost:9991",
"istanbul": "istanbul cover --dir test/browse-coverage -x test/browse-** test/index.js",
"live:jasmine": "browser-sync start --port 9999 --server test/browse-jasmine/ --files test/browse-jasmine/ --no-open --no-ui --no-online",
"open-help": "biased-opener --help",
"open:jasmine": "biased-opener --browser chrome http://localhost:9999",
"istanbul-original": "istanbul cover --dir test/browse-coverage -x test/browse-** test/index.js",
"istanbul": "istanbul cover --dir test/browse-coverage test/index.js",
"watch:istanbul": "watch \"npm run istanbul\" lib/ test/ --ignoreDirectoryPattern=/browse-.+/",
"live:istanbul": "browser-sync start --port 9992 --server test/browse-coverage/lcov-report/ --files test/browse-coverage/lcov-report/ --no-open --no-ui --no-online",
"open:istanbul": "biased-opener --browser chrome http://localhost:9992",
"live:istanbul": "browser-sync start --port 9998 --server test/browse-coverage/lcov-report/ --files test/browse-coverage/lcov-report/ --no-open --no-ui --no-online",
"open:istanbul": "biased-opener --browser chrome http://localhost:9998",
"live": "npm-run-all --parallel live:* open:*",

@@ -66,3 +68,4 @@ "start": "npm-run-all --parallel bundle:jasmine watch:istanbul live:* open:*",

"coverage:coveralls": "cat ./test/browse-coverage/lcov.info | coveralls",
"coverage:codacy": "cross-env CODACY_PROJECT_TOKEN=0207815122ea49a68241d1aa435f21f1 cat ./test/browse-coverage/lcov.info | codacy-coverage",
"coverage:codecov": "codecov --token=0e52af41-702b-4d7f-8aa3-61145ac36624",
"coverage:codacy": "cross-env CODACY_PROJECT_TOKEN=0207815122ea49a68241d1aa435f21f1 && cat ./test/browse-coverage/lcov.info | codacy-coverage",
"coverage:codeclimate": "cross-env CODECLIMATE_REPO_TOKEN=60848a077f9070acf358b0c7145f0a2698a460ddeca7d8250815e75aa4333f7d codeclimate-test-reporter < test\\browse-coverage\\lcov.info",

@@ -82,12 +85,14 @@ "prepublish": "npm run test",

"codeclimate-test-reporter": "^0.5.0",
"codecov": "^3.0.0",
"coveralls": "^3.0.0",
"cross-env": "^5.1.1",
"globify": "^2.1.0",
"eslint": "^4.13.1",
"globify": "^2.2.1",
"istanbul": "^0.4.5",
"jasmine": "^2.8.0",
"nodemon": "^1.12.1",
"nodemon": "^1.13.3",
"npm-run-all": "^4.1.2",
"typescript": "^2.6.1",
"typescript": "^2.6.2",
"watch": "^1.0.1"
}
}

@@ -11,7 +11,9 @@ ![XML ⇔ JS/JSON](http://nashwaan.github.io/xml-js/images/logo.svg)

[![Coverage Status](https://coveralls.io/repos/github/nashwaan/xml-js/badge.svg?branch=master)](https://coveralls.io/github/nashwaan/xml-js?branch=master)
[![codecov](https://codecov.io/gh/nashwaan/xml-js/branch/master/graph/badge.svg)](https://codecov.io/gh/nashwaan/xml-js)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f6ed5dd79a5b4041bfd2732963c4d09b)](https://www.codacy.com/app/ysf953/xml-js?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=nashwaan/xml-js&amp;utm_campaign=Badge_Grade)
[![Code Climate](https://codeclimate.com/github/nashwaan/xml-js/badges/gpa.svg)](https://codeclimate.com/github/nashwaan/xml-js)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f6ed5dd79a5b4041bfd2732963c4d09b)](https://www.codacy.com/app/ysf953/xml-js?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=nashwaan/xml-js&amp;utm_campaign=Badge_Grade)
[![npm](http://img.shields.io/npm/v/xml-js.svg)](https://www.npmjs.com/package/xml-js)
[![License](https://img.shields.io/npm/l/xml-js.svg)](LICENSE)
[![Downloads/month](https://img.shields.io/npm/dm/xml-js.svg)](http://www.npmtrends.com/xml-js)
[![Dependency Status](https://david-dm.org/nashwaan/xml-js.svg)](https://david-dm.org/nashwaan/xml-js)

@@ -25,10 +27,10 @@ [![Package Quality](http://npm.packagequality.com/shield/xml-js.svg)](http://packagequality.com/#?package=xml-js)

# Motivation
# Features
There are many XML to JavaScript object / JSON converters out there, but could not satisfy the following requirements:
* **Maintain Order of Elements**:
Instead of converting `<a/><b/><a/>` to `{a:[{},{}],b:{}}`, I wanted to preserve order of elements by doing this:
Most libraries will convert `<a/><b/><a/>` to `{a:[{},{}],b:{}}` which merges any node of same name into an array. This library can creates the following to preserve the order of elements:
`{"elements":[{"type":"element","name":"a"},{"type":"element","name":"b"},{"type":"element","name":"a"}]}`.
This is very important and it is the main reason why this library was created.
* **Fully XML Compliant**:

@@ -44,3 +46,3 @@ Can parse: elements, attributes, texts, comments, CData, DOCTYPE, XML declarations, and Processing Instructions.

* **Change Property Key Name**:
Usually output of XML attributes are stored in `@attr`, `_atrr`, `$attr`, `$`, or `whatever` in order to avoid conflicting with name of sub-elements.
Usually output of XML attributes are stored in `@attr`, `_atrr`, `$attr` or `$` in order to avoid conflicting with name of sub-elements.
This library store them in `attributes`, but most importantly, you can change this to whatever you like.

@@ -52,8 +54,11 @@

* **Support Command Line**:
To quickly convert xml or json files, this module can be installed globally or locally (i.e. use it as [script](https://docs.npmjs.com/misc/scripts) in package.json).
* **Customize Processing using Callback Hooks**:
[Custom functions](#options-for-custom-processing-functions) can be supplied to do additional processing for different parts of xml or json (like cdata, comments, elements, attributes ...etc).
* **Portable Code**:
Written purely in JavaScript which means it can be used in Node environment and **browser** environment (via bundlers like browserify/JSPM/Webpack).
* **Support Command Line**:
To quickly convert xml or json files, this module can be installed globally or locally (i.e. use it as [script](https://docs.npmjs.com/misc/scripts) in package.json).
* **Typings Info Included**:

@@ -163,3 +168,3 @@ Support type checking and code suggestion via intellisense.

|:----------------------|:--------|:------------|
| `spaces` | `0` | Number of spaces to be used for indenting XML output. Passing characters like `' '` or `'\t'` are also accpeted. |
| `spaces` | `0` | Number of spaces to be used for indenting XML output. Passing characters like `' '` or `'\t'` are also accepted. |
| `compact` | `false` | Whether the *input* object is in compact form or not. |

@@ -240,2 +245,34 @@ | `fullTagEmptyElement` | `false` | Whether to produce element without sub-elements as full tag pairs `<a></a>` rather than self closing tag `<a/>`. |

## Options for Custom Processing Functions
For XML → JS object / JSON, following custom callback functions can be supplied:
| Option | Signature | Description |
|:--------------------|:----------|:------------|
| `doctypeFn` | `(value, parentElement)` | To perform additional processing for DOCTYPE. For example, `{doctypeFn: function(val) {return val.toUpperCase();}` |
| `instructionFn` | `(instructionValue, instructionName, parentElement)` | To perform additional processing for content of Processing Instruction value. For example, `{instructionFn: function(val) {return val.toUpperCase();}`. Note: `instructionValue` will be an object if `instructionHasAttributes` is enabled. |
| `cdataFn` | `(value, parentElement)` | To perform additional processing for CData. For example, `{cdataFn: function(val) {return val.toUpperCase();}`. |
| `commentFn` | `(value, parentElement)` | To perform additional processing for comments. For example, `{commentFn: function(val) {return val.toUpperCase();}`. |
| `textFn` | `(value, parentElement)` | To perform additional processing for texts inside elements. For example, `{textFn: function(val) {return val.toUpperCase();}`. |
| `instructionNameFn` | `(instructionName, instructionValue, parentElement)` | To perform additional processing for Processing Instruction name. For example, `{instructionNameFn: function(val) {return val.toUpperCase();}`. Note: `instructionValue` will be an object if `instructionHasAttributes` is enabled. |
| `elementNameFn` | `(value, parentElement)` | To perform additional processing for element name. For example, `{elementNameFn: function(val) {return val.toUpperCase();}`. |
| `attributeNameFn` | `(attributeName, attributeValue, parentElement)` | To perform additional processing for attribute name. For example, `{attributeNameFn: function(val) {return val.toUpperCase();}`. |
| `attributeValueFn` | `(attributeValue, attributeName, parentElement)` | To perform additional processing for attributeValue. For example, `{attributeValueFn: function(val) {return val.toUpperCase();}`. |
| `attributesFn` | `(value, parentElement)` | To perform additional processing for attributes object. For example, `{attributesFn: function(val) {return val.toUpperCase();}`. |
For JS object / JSON → XML, following custom callback functions can be supplied:
| Option | Signature | Description |
|:--------------------|:----------|:------------|
| `doctypeFn` | `(value, currentElementName, currentElementObj)` | To perform additional processing for DOCTYPE. For example, `{doctypeFn: function(val) {return val.toUpperCase();}` |
| `instructionFn` | `(instructionValue, instructionName, currentElementName, currentElementObj)` | To perform additional processing for content of Processing Instruction value. For example, `{instructionFn: function(val) {return val.toUpperCase();}`. Note: `instructionValue` will be an object if `instructionHasAttributes` is enabled. |
| `cdataFn` | `(value, currentElementName, currentElementObj)` | To perform additional processing for CData. For example, `{cdataFn: function(val) {return val.toUpperCase();}`. |
| `commentFn` | `(value, currentElementName, currentElementObj)` | To perform additional processing for comments. For example, `{commentFn: function(val) {return val.toUpperCase();}`. |
| `textFn` | `(value, currentElementName, currentElementObj)` | To perform additional processing for texts inside elements. For example, `{textFn: function(val) {return val.toUpperCase();}`. |
| `instructionNameFn` | `(instructionName, instructionValue, currentElementName, currentElementObj)` | To perform additional processing for Processing Instruction name. For example, `{instructionNameFn: function(val) {return val.toUpperCase();}`. Note: `instructionValue` will be an object if `instructionHasAttributes` is enabled. |
| `elementNameFn` | `(value, currentElementName, currentElementObj)` | To perform additional processing for element name. For example, `{elementNameFn: function(val) {return val.toUpperCase();}`. |
| `attributeNameFn` | `(attributeName, attributeValue, currentElementName, currentElementObj)` | To perform additional processing for attribute name. For example, `{attributeNameFn: function(val) {return val.toUpperCase();}`. |
| `attributeValueFn` | `(attributeValue, attributeName, currentElementName, currentElementObj)` | To perform additional processing for attributeValue. For example, `{attributeValueFn: function(val) {return val.toUpperCase();}`. |
| `attributesFn` | `(value, currentElementName, currentElementObj)` | To perform additional processing for attributes object. For example, `{attributesFn: function(val) {return val.toUpperCase();}`. |
# Command Line

@@ -242,0 +279,0 @@

export interface ElementCompact {
[key: string]: any
_declaration?: {
_attributes?: {
version?: string | number
encoding?: string | number
}
}
_instruction?: {
[key: string]: string
}
[key: string]: any
_declaration?: {
_attributes?: {
[key: string]: string | number
version?: string | number
encoding?: string | number
}
_cdata?: string
_doctype?: string
_comment?: string
_text?: string | number
}
_instruction?: {
[key: string]: string
}
_attributes?: {
[key: string]: string | number
}
_cdata?: string
_doctype?: string
_comment?: string
_text?: string | number
}
export interface Element {
declaration?: {
attributes?: {
version: string | number
encoding: string | number
}
}
instruction?: string
declaration?: {
attributes?: {
[key: string]: string | number
version: string | number
encoding: string | number
}
cdata?: string
doctype?: string
comment?: string
text?: string | number | boolean
type?: string
name?: string
elements?: Array<Element>
}
instruction?: string
attributes?: {
[key: string]: string | number
}
cdata?: string
doctype?: string
comment?: string
text?: string | number | boolean
type?: string
name?: string
elements?: Array<Element>
}
declare namespace Options {
interface XML2JSON extends XML2JS {
spaces?: number | string
}
interface XML2JSON extends XML2JS {
spaces?: number | string
}
interface XML2JS extends ChangingKeyNames, IgnoreOptions {
compact?: boolean
trim?: boolean
sanitize?: boolean
nativeType?: boolean
addParent?: boolean
alwaysArray?: boolean
alwaysChildren?: boolean
instructionHasAttributes?: boolean
captureSpacesBetweenElements?: boolean
}
interface XML2JS extends ChangingKeyNames, IgnoreOptions {
compact?: boolean
trim?: boolean
sanitize?: boolean
nativeType?: boolean
addParent?: boolean
alwaysArray?: boolean
alwaysChildren?: boolean
instructionHasAttributes?: boolean
captureSpacesBetweenElements?: boolean
}
interface JS2XML extends ChangingKeyNames, IgnoreOptions {
spaces?: number | string
compact?: boolean
indentText?: boolean
indentCdata?: boolean
indentAttributes?: boolean
indentInstruction?: boolean
fullTagEmptyElement?: boolean
noQuotesForNativeAttributes?: boolean
}
interface JS2XML extends ChangingKeyNames, IgnoreOptions {
spaces?: number | string
compact?: boolean
indentText?: boolean
indentCdata?: boolean
indentAttributes?: boolean
indentInstruction?: boolean
fullTagEmptyElement?: boolean
noQuotesForNativeAttributes?: boolean
}
interface IgnoreOptions {
ignoreDeclaration?: boolean
ignoreInstruction?: boolean
ignoreAttributes?: boolean
ignoreComment?: boolean
ignoreCdata?: boolean
ignoreDoctype?: boolean
ignoreText?: boolean
}
interface IgnoreOptions {
ignoreDeclaration?: boolean
ignoreInstruction?: boolean
ignoreAttributes?: boolean
ignoreComment?: boolean
ignoreCdata?: boolean
ignoreDoctype?: boolean
ignoreText?: boolean
}
interface ChangingKeyNames {
declarationKey?: string
instructionKey?: string
attributesKey?: string
textKey?: string
cdataKey?: string
doctypeKey?: string
commentKey?: string
parentKey?: string
typeKey?: string
nameKey?: string
elementsKey?: string
}
interface ChangingKeyNames {
declarationKey?: string
instructionKey?: string
attributesKey?: string
textKey?: string
cdataKey?: string
doctypeKey?: string
commentKey?: string
parentKey?: string
typeKey?: string
nameKey?: string
elementsKey?: string
}
}

@@ -93,0 +93,0 @@

@@ -41,5 +41,5 @@ import { Element, ElementCompact } from './index'

<note importance="high" logged="true">
<title>Happy</title>
<todo>Work</todo>
<todo>Play</todo>
<title>Happy</title>
<todo>Work</todo>
<todo>Play</todo>
</note>`;

@@ -46,0 +46,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc