Skip to content

Commit

Permalink
Committed by npm script.
Browse files Browse the repository at this point in the history
  • Loading branch information
nashwaan committed Apr 26, 2017
1 parent a4aab32 commit 6a6090e
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 85 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ This library store them in `attributes`, but most importantly, you can change th

* **Support Upwards Traversal**:
By setting `{addParent: true}` option, an extra property named `parent` will be generated along each element so that its parent can be referenced.
Therefore, anywhere during the traversal of an element node, its children **and** its parent can be easily accessed.
Therefore, anywhere during the traversal of an element, its children **and** its parent can be easily accessed.

* **Portable Code**:
Written purely in JavaScript which means it can be used in Node environment and **browser** environment (via bundlers like browserify/JSPM/Webpack).
Expand All @@ -67,7 +67,9 @@ which has merged both `<a>` elements into an array! If you try to convert this b
which has not preserved the order of elements! This is an inherit limitation in the compact representation
because output like `{a:{_:{x:"1"}}, b:{_:{x:"2"}}, a:{_:{x:"3"}}}` is illegal (same property name `a` should not appear twice in an object).

The non-compact output which is supported by this library will produce more information and always gurantees the order of the elements as they appeared in the XML file.
The non-compact output, which is supported by this library, will produce more information and always gurantees the order of the elements as they appeared in the XML file.

Another drawback of compact output is the resultant element can be an object or an array and therefore makes the client code a little awkwards in terms of extra check of object type before processing.

NOTE: Although non-compact output is more accurate representation of original XML than compact version, the non-compact version is verbose and consumes more space.
This library provides both options. Use `{compact: false}` if you are not sure because it preserves everything;
Expand Down Expand Up @@ -150,14 +152,15 @@ The below options are applicable for both `js2xml()` and `json2xml()` functions.

| Option | Default | Description |
|:----------------------|:--------|:------------|
| `spaces` | `0` | Number of spaces to be used for indenting XML output. |
| `spaces` | `0` | Number of spaces to be used for indenting XML output. Passing characters like `'` &nbsp;&nbsp;&nbsp; `'` or `'\t'` are also accpeted. |
| `compact` | `false` | Whether the *input* object is in compact form or not. |
| `fullTagEmptyElement` | `false` | Whether to produce element without sub-elements as full tag pairs `<a></a>` rather than self closing tag `<a/>`. |
| `indentCdata` | `false` | Whether to write CData in a new line and indent it. Will generate `<a>\n <![CDATA[foo]]></a>` instead of `<a><![CDATA[foo]]></a>`. |
| `ignoreDeclaration` | `false` | Whether to ignore writing declaration directives of xml. For example, `<?xml?>` will be ignored. |
| `ignoreAttributes` | `false` | Whether to ignore writing attributes of the elements. For example, `x="1"` in `<a x="1"></a>` will be ignored |
| `ignoreComment` | `false` | Whether to ignore writing comments of the elements. That is, no `<!-- -->` will be generated. |
| `ignoreCdata` | `false` | Whether to ignore writing CData of the elements. That is, no `<![CDATA[ ]]>` will be generated. |
| `ignoreDoctype` | `false` | Whether to ignore writing Doctype of the elements. That is, no `<!DOCTYPE >` will be generated. |
| `ignoreDoctype` | `false` | Whether to ignore writing Doctype of the elements. That is, no `<!DOCTYPE ]>` will be generated. |
| `ignoreText` | `false` | Whether to ignore writing texts of the elements. For example, `hi` text in `<a>hi</a>` will be ignored. |

## Convert XML → JS object / JSON
Expand Down Expand Up @@ -195,7 +198,7 @@ The below option is applicable only for `xml2json()` function.

| Option | Default | Description |
|:--------------------|:--------|:------------|
| `spaces` | `0` | Number of spaces to be used for indenting JSON output. |
| `spaces` | `0` | Number of spaces to be used for indenting JSON output. Passing characters like `'` &nbsp;&nbsp;&nbsp; `'` or `'\t'` are also accpeted. |

## Options for Changing Key Names

Expand Down
1 change: 1 addition & 0 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var optionalArgs = [
{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 (coreced) 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: '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.'},
Expand Down
23 changes: 23 additions & 0 deletions bin/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"elements": [
{
"type": "element",
"name": "a",
"attributes": {
"x": "1"
},
"elements": [
{
"type": "element",
"name": "b",
"elements": [
{
"type": "text",
"text": "bye!"
}
]
}
]
}
]
}
138 changes: 93 additions & 45 deletions lib/js2xml.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ function validateOptions (userOptions) {
common.ensureFlagExists('ignoreCdata', options);
common.ensureFlagExists('ignoreDoctype', options);
common.ensureFlagExists('compact', options);
common.ensureFlagExists('indentText', options);
common.ensureFlagExists('indentCdata', options);
common.ensureFlagExists('fullTagEmptyElement', options);
common.ensureSpacesExists(options);
if (typeof options.spaces === 'number') {
Expand Down Expand Up @@ -44,20 +46,47 @@ function writeDeclaration (declaration, options) {
return '<?xml' + writeAttributes(declaration[options.attributesKey]) + '?>';
}

function writeComment (element, options) {
return options.ignoreComment ? '' : '<!--' + element[options.commentKey] + '-->';
function writeComment (comment, options) {
return options.ignoreComment ? '' : '<!--' + comment + '-->';
}

function writeCdata (element, options) {
return options.ignoreCdata ? '' : '<![CDATA[' + element[options.cdataKey] + ']]>';
function writeCdata (cdata, options) {
return options.ignoreCdata ? '' : '<![CDATA[' + cdata + ']]>';
}

function writeDoctype (element, options) {
return options.ignoreDoctype ? '' : '<!Doctype' + element[options.DoctypeKey] + ']>';
function writeDoctype (doctype, options) {
return options.ignoreDoctype ? '' : '<!DOCTYPE' + doctype + '>';

This comment has been minimized.

Copy link
@DenisCarriere

DenisCarriere Apr 27, 2017

Contributor

Might want to leave an extra space after DOCTYPE.

'<!DOCTYPE ' + doctype + '>';
}

function writeText (element, options) {
return options.ignoreText ? '' : element[options.textKey].replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
function writeText (text, options) {
return options.ignoreText ? '' : text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
}

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 'doctype':
case 'comment':
case 'element':
return true;
default:
return true;
}
}
}
return false;
}

function writeElement (element, options, depth) {
Expand All @@ -71,7 +100,7 @@ function writeElement (element, options, depth) {
if (element[options.elementsKey] && element[options.elementsKey].length) {
xml += writeElements(element[options.elementsKey], options, depth + 1);
}
xml += (options.spaces && element[options.elementsKey] && element[options.elementsKey].length && (element[options.elementsKey].length > 1 || element[options.elementsKey][0].type !== 'text') ? '\n' + Array(depth + 1).join(options.spaces) : '');
xml += options.spaces && hasContent(element, options) ? '\n' + Array(depth + 1).join(options.spaces) : '';
xml += '</' + element.name + '>';
} else {
xml += '/>';
Expand All @@ -80,37 +109,37 @@ function writeElement (element, options, depth) {
}

function writeElements (elements, options, depth, firstLine) {
var indent = writeIndentation(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);
case 'cdata': return xml + indent + writeCdata(element, options);
case 'doctype': return xml + indent + writeDoctype(element, options);
case 'text': return xml + writeText(element, options);
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);
}
}, '');
}

function hasContent (element, options, skipText) {
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 (!skipText) {
if (options.indentText || anyContent) {
return true;
}
break; // skip to next key
case options.parentKey:
case options.attributesKey:
break; // skip to next key
case options.cdataKey:
<<<<<<< HEAD
if (options.indentCdata || anyContent) {
return true;
}
break; // skip to next key
case options.doctypeKey:
=======
return false;
>>>>>>> origin/master
case options.commentKey:
case options.declarationKey:
return true;
Expand All @@ -129,7 +158,7 @@ function writeElementCompact (element, name, options, depth, indent) {
if (element[options.attributesKey]) {
xml += writeAttributes(element[options.attributesKey]);
}
if (options.fullTagEmptyElement || hasContent(element, options) || element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve') {
if (options.fullTagEmptyElement || hasContentCompact(element, options, true) || element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve') {
xml += '>';
} else {
xml += '/>';
Expand All @@ -143,31 +172,50 @@ function writeElementCompact (element, name, options, depth, indent) {
return xml;
}

// function writeElementsCompact (element, options, depth, firstLine) {
// var key, xml = '';
// for (key in element) {
// if (element.hasOwnProperty(key)) {
// switch (key) {
// case options.declarationKey: xml += writeDeclaration(element[options.declarationKey], options); break;
// case options.attributesKey: case options.parentKey: break; // skip
// case options.textKey: xml += (options.indentText ? writeIndentation(options, depth, firstLine) : '') + writeText(element, options); break;
// case options.cdataKey: xml += (options.indentCdata ? writeIndentation(options, depth, firstLine) : '') + writeCdata(element, options); break;
// case options.doctypeKey: xml += writeIndentation(options, depth, firstLine) + writeDoctype(element, options); break;
// case options.commentKey: xml += writeIndentation(options, depth, firstLine) + writeComment(element, options); break;
// default:
// if (element[key] instanceof Array) {
// element[key].forEach(function (el) {
// xml += writeIndentation(options, depth, firstLine) + writeElementCompact(el, key, options, depth, hasContentCompact(el, options));
// firstLine = firstLine && !xml;
// });
// } else {
// xml += writeIndentation(options, depth, firstLine) + writeElementCompact(element[key], key, options, depth, hasContentCompact(element[key], options));
// }
// }
// firstLine = firstLine && !xml;
// }
// }
// return xml;
// }

function writeElementsCompact (element, options, depth, firstLine) {
var key, xml = '';
var i, key, nodes, xml = '';
for (key in element) {
if (element.hasOwnProperty(key)) {
switch (key) {
case options.declarationKey: xml += writeDeclaration(element[options.declarationKey], options); break;
case options.attributesKey: case options.parentKey: break; // skip
case options.textKey: xml += writeText(element, options); break;
<<<<<<< HEAD
case options.cdataKey: xml += writeIndentation(options, depth, firstLine) + writeCdata(element, options); break;
case options.doctypeKey: xml += writeIndentation(options, depth, firstLine) + writeDoctype(element, options); break;
=======
case options.cdataKey: xml += writeCdata(element, options); break;
>>>>>>> origin/master
case options.commentKey: xml += writeIndentation(options, depth, firstLine) + writeComment(element, options); break;
default:
if (element[key] instanceof Array) {
element[key].forEach(function (el) {
xml += writeIndentation(options, depth, firstLine) + writeElementCompact(el, key, options, depth, hasContent(el, options, true));
});
} else {
xml += writeIndentation(options, depth, firstLine) + writeElementCompact(element[key], key, options, depth, hasContent(element[key], options, true));
}
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); 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;
}
firstLine = firstLine && !xml;
}
}
return xml;
Expand Down
1 change: 1 addition & 0 deletions lib/xml2js.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function validateOptions (userOptions) {
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);
Expand Down
10 changes: 2 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "xml-js",
"version": "1.0.2",
"version": "1.1.0",
"description": "A convertor between XML text and Javascript object / JSON text.",
"repository": {
"type": "git",
Expand Down Expand Up @@ -55,20 +55,14 @@
"globify": "^2.0.0",
"istanbul": "^0.4.5",
"jasmine": "^2.5.3",
"node-inspector": "^1.0.0",
"nodemon": "^1.11.0",
"npm-run-all": "^4.0.1",
"typescript": "^2.2.2",
"watch": "^1.0.1"
},
"scripts": {
"debug": "nodemon --inspect --watch lib/ --watch test/ --debug-brk test/index.js",
"pre-node6.3.1-debug": "npm-run-all --parallel debug:*",
"debug:listener": "node-inspector",
"debug:jasmine": "nodemon --watch lib/ --watch test/ --debug-brk test/index.js",
"xdebug:cli": "nodemon --watch lib/ --debug-brk index.js -- --help",
"debug:live": "browser-sync start --port 8080 --server --startPath ?port=5858 --files lib/ test/ --no-open --no-ui --no-online",
"debug:open": "biased-opener --browser chrome http://localhost:8080/?port=5858",
"debug:cli": "nodemon --inspect --watch lib/ --debug-brk index.js -- --help",
"jasmine": "jasmine JASMINE_CONFIG_PATH=./test/jasmine.json",
"watch:jasmine": "watch \"npm run jasmine\" lib/ test/",
"bundle:jasmine": "globify test/*_test.js --watch --verbose --list --outfile test/browse-jasmine/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion test/common_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('Testing common.js:', function () {

describe('Copy Options:', function () {

it('Copy no provided options', function () {
it('Copy unprovided options', function () {
expect(convert.copyOptions()).toEqual({});
});

Expand Down
Loading

0 comments on commit 6a6090e

Please sign in to comment.