Comparing version 1.5.2 to 1.6.0
@@ -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" |
112
bin/cli.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, '"'); | ||
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, '"') + 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(/&/g, '&'); // desanitize to avoid double sanitization | ||
return options.ignoreText ? '' : text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); | ||
if (options.ignoreText) return ''; | ||
text = '' + text; // ensure Number and Boolean are converted to String | ||
text = text.replace(/&/g, '&'); // desanitize to avoid double sanitization | ||
text = text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); | ||
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, '&').replace(/</g, '<').replace(/>/g, '>'); | ||
} 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, '&').replace(/</g, '<').replace(/>/g, '>'); | ||
} | ||
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&utm_medium=referral&utm_content=nashwaan/xml-js&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&utm_medium=referral&utm_content=nashwaan/xml-js&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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
71122
1024
368
16
22