Skip to content

Commit 6a6090e

Browse files
committed
Committed by npm script.
1 parent a4aab32 commit 6a6090e

9 files changed

Lines changed: 260 additions & 85 deletions

File tree

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ This library store them in `attributes`, but most importantly, you can change th
4444

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

4949
* **Portable Code**:
5050
Written purely in JavaScript which means it can be used in Node environment and **browser** environment (via bundlers like browserify/JSPM/Webpack).
@@ -67,7 +67,9 @@ which has merged both `<a>` elements into an array! If you try to convert this b
6767
which has not preserved the order of elements! This is an inherit limitation in the compact representation
6868
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).
6969

70-
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.
70+
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.
71+
72+
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.
7173

7274
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.
7375
This library provides both options. Use `{compact: false}` if you are not sure because it preserves everything;
@@ -150,14 +152,15 @@ The below options are applicable for both `js2xml()` and `json2xml()` functions.
150152

151153
| Option | Default | Description |
152154
|:----------------------|:--------|:------------|
153-
| `spaces` | `0` | Number of spaces to be used for indenting XML output. |
155+
| `spaces` | `0` | Number of spaces to be used for indenting XML output. Passing characters like `'` &nbsp;&nbsp;&nbsp; `'` or `'\t'` are also accpeted. |
154156
| `compact` | `false` | Whether the *input* object is in compact form or not. |
155157
| `fullTagEmptyElement` | `false` | Whether to produce element without sub-elements as full tag pairs `<a></a>` rather than self closing tag `<a/>`. |
158+
| `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>`. |
156159
| `ignoreDeclaration` | `false` | Whether to ignore writing declaration directives of xml. For example, `<?xml?>` will be ignored. |
157160
| `ignoreAttributes` | `false` | Whether to ignore writing attributes of the elements. For example, `x="1"` in `<a x="1"></a>` will be ignored |
158161
| `ignoreComment` | `false` | Whether to ignore writing comments of the elements. That is, no `<!-- -->` will be generated. |
159162
| `ignoreCdata` | `false` | Whether to ignore writing CData of the elements. That is, no `<![CDATA[ ]]>` will be generated. |
160-
| `ignoreDoctype` | `false` | Whether to ignore writing Doctype of the elements. That is, no `<!DOCTYPE >` will be generated. |
163+
| `ignoreDoctype` | `false` | Whether to ignore writing Doctype of the elements. That is, no `<!DOCTYPE ]>` will be generated. |
161164
| `ignoreText` | `false` | Whether to ignore writing texts of the elements. For example, `hi` text in `<a>hi</a>` will be ignored. |
162165

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

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

200203
## Options for Changing Key Names
201204

bin/cli.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var optionalArgs = [
2323
{arg: 'trim', type: 'flag', option:'trim', desc: 'Any whitespaces surrounding texts will be trimmed.'},
2424
{arg: 'sanitize', type: 'flag', option:'sanitize', desc: 'Special xml characters will be replaced with entity codes.'},
2525
{arg: 'native-type', type: 'flag', option:'nativeType', desc: 'Numbers and boolean will be converted (coreced) to native type instead of text.'},
26+
{arg: 'always-array', type: 'flag', option:'alwaysArray', desc: 'Every element will always be an array type (applicable if --compact is set).'},
2627
{arg: 'always-children', type: 'flag', option:'alwaysChildren', desc: 'Every element will always contain sub-elements (applicable if --compact is not set).'},
2728
{arg: 'full-tag', type: 'flag', option:'fullTagEmptyElement', desc: 'XML elements will always be in <a></a> form.'},
2829
{arg: 'no-decl', type: 'flag', option:'ignoreDeclaration', desc: 'Declaration instruction <?xml ..?> will be ignored.'},

bin/test.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"elements": [
3+
{
4+
"type": "element",
5+
"name": "a",
6+
"attributes": {
7+
"x": "1"
8+
},
9+
"elements": [
10+
{
11+
"type": "element",
12+
"name": "b",
13+
"elements": [
14+
{
15+
"type": "text",
16+
"text": "bye!"
17+
}
18+
]
19+
}
20+
]
21+
}
22+
]
23+
}

lib/js2xml.js

Lines changed: 93 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ function validateOptions (userOptions) {
99
common.ensureFlagExists('ignoreCdata', options);
1010
common.ensureFlagExists('ignoreDoctype', options);
1111
common.ensureFlagExists('compact', options);
12+
common.ensureFlagExists('indentText', options);
13+
common.ensureFlagExists('indentCdata', options);
1214
common.ensureFlagExists('fullTagEmptyElement', options);
1315
common.ensureSpacesExists(options);
1416
if (typeof options.spaces === 'number') {
@@ -44,20 +46,47 @@ function writeDeclaration (declaration, options) {
4446
return '<?xml' + writeAttributes(declaration[options.attributesKey]) + '?>';
4547
}
4648

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

51-
function writeCdata (element, options) {
52-
return options.ignoreCdata ? '' : '<![CDATA[' + element[options.cdataKey] + ']]>';
53+
function writeCdata (cdata, options) {
54+
return options.ignoreCdata ? '' : '<![CDATA[' + cdata + ']]>';
5355
}
5456

55-
function writeDoctype (element, options) {
56-
return options.ignoreDoctype ? '' : '<!Doctype' + element[options.DoctypeKey] + ']>';
57+
function writeDoctype (doctype, options) {
58+
return options.ignoreDoctype ? '' : '<!DOCTYPE' + doctype + '>';
5759
}
5860

59-
function writeText (element, options) {
60-
return options.ignoreText ? '' : element[options.textKey].replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
61+
function writeText (text, options) {
62+
return options.ignoreText ? '' : text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
63+
}
64+
65+
function hasContent (element, options) {
66+
var i;
67+
if (element.elements && element.elements.length) {
68+
for (i = 0; i < element.elements.length; ++i) {
69+
switch (element.elements[i][options.typeKey]) {
70+
case 'text':
71+
if (options.indentText) {
72+
return true;
73+
}
74+
break; // skip to next key
75+
case 'cdata':
76+
if (options.indentCdata) {
77+
return true;
78+
}
79+
break; // skip to next key
80+
case 'doctype':
81+
case 'comment':
82+
case 'element':
83+
return true;
84+
default:
85+
return true;
86+
}
87+
}
88+
}
89+
return false;
6190
}
6291

6392
function writeElement (element, options, depth) {
@@ -71,7 +100,7 @@ function writeElement (element, options, depth) {
71100
if (element[options.elementsKey] && element[options.elementsKey].length) {
72101
xml += writeElements(element[options.elementsKey], options, depth + 1);
73102
}
74-
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) : '');
103+
xml += options.spaces && hasContent(element, options) ? '\n' + Array(depth + 1).join(options.spaces) : '';
75104
xml += '</' + element.name + '>';
76105
} else {
77106
xml += '/>';
@@ -80,37 +109,37 @@ function writeElement (element, options, depth) {
80109
}
81110

82111
function writeElements (elements, options, depth, firstLine) {
83-
var indent = writeIndentation(options, depth, firstLine);
84112
return elements.reduce(function (xml, element) {
113+
var indent = writeIndentation(options, depth, firstLine && !xml);
85114
switch (element.type) {
86115
case 'element': return xml + indent + writeElement(element, options, depth);
87-
case 'comment': return xml + indent + writeComment(element, options);
88-
case 'cdata': return xml + indent + writeCdata(element, options);
89-
case 'doctype': return xml + indent + writeDoctype(element, options);
90-
case 'text': return xml + writeText(element, options);
116+
case 'comment': return xml + indent + writeComment(element[options.commentKey], options);
117+
case 'doctype': return xml + indent + writeDoctype(element[options.doctypeKey], options);
118+
case 'cdata': return xml + (options.indentCdata ? indent : '') + writeCdata(element[options.cdataKey], options);
119+
case 'text': return xml + (options.indentText ? indent : '') + writeText(element[options.textKey], options);
91120
}
92121
}, '');
93122
}
94123

95-
function hasContent (element, options, skipText) {
124+
function hasContentCompact (element, options, anyContent) {
96125
var key;
97126
for (key in element) {
98127
if (element.hasOwnProperty(key)) {
99128
switch (key) {
129+
case options.parentKey:
130+
case options.attributesKey:
131+
break; // skip to next key
100132
case options.textKey:
101-
if (!skipText) {
133+
if (options.indentText || anyContent) {
102134
return true;
103135
}
104136
break; // skip to next key
105-
case options.parentKey:
106-
case options.attributesKey:
107-
break; // skip to next key
108137
case options.cdataKey:
109-
<<<<<<< HEAD
138+
if (options.indentCdata || anyContent) {
139+
return true;
140+
}
141+
break; // skip to next key
110142
case options.doctypeKey:
111-
=======
112-
return false;
113-
>>>>>>> origin/master
114143
case options.commentKey:
115144
case options.declarationKey:
116145
return true;
@@ -129,7 +158,7 @@ function writeElementCompact (element, name, options, depth, indent) {
129158
if (element[options.attributesKey]) {
130159
xml += writeAttributes(element[options.attributesKey]);
131160
}
132-
if (options.fullTagEmptyElement || hasContent(element, options) || element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve') {
161+
if (options.fullTagEmptyElement || hasContentCompact(element, options, true) || element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve') {
133162
xml += '>';
134163
} else {
135164
xml += '/>';
@@ -143,31 +172,50 @@ function writeElementCompact (element, name, options, depth, indent) {
143172
return xml;
144173
}
145174

175+
// function writeElementsCompact (element, options, depth, firstLine) {
176+
// var key, xml = '';
177+
// for (key in element) {
178+
// if (element.hasOwnProperty(key)) {
179+
// switch (key) {
180+
// case options.declarationKey: xml += writeDeclaration(element[options.declarationKey], options); break;
181+
// case options.attributesKey: case options.parentKey: break; // skip
182+
// case options.textKey: xml += (options.indentText ? writeIndentation(options, depth, firstLine) : '') + writeText(element, options); break;
183+
// case options.cdataKey: xml += (options.indentCdata ? writeIndentation(options, depth, firstLine) : '') + writeCdata(element, options); break;
184+
// case options.doctypeKey: xml += writeIndentation(options, depth, firstLine) + writeDoctype(element, options); break;
185+
// case options.commentKey: xml += writeIndentation(options, depth, firstLine) + writeComment(element, options); break;
186+
// default:
187+
// if (element[key] instanceof Array) {
188+
// element[key].forEach(function (el) {
189+
// xml += writeIndentation(options, depth, firstLine) + writeElementCompact(el, key, options, depth, hasContentCompact(el, options));
190+
// firstLine = firstLine && !xml;
191+
// });
192+
// } else {
193+
// xml += writeIndentation(options, depth, firstLine) + writeElementCompact(element[key], key, options, depth, hasContentCompact(element[key], options));
194+
// }
195+
// }
196+
// firstLine = firstLine && !xml;
197+
// }
198+
// }
199+
// return xml;
200+
// }
201+
146202
function writeElementsCompact (element, options, depth, firstLine) {
147-
var key, xml = '';
203+
var i, key, nodes, xml = '';
148204
for (key in element) {
149205
if (element.hasOwnProperty(key)) {
150-
switch (key) {
151-
case options.declarationKey: xml += writeDeclaration(element[options.declarationKey], options); break;
152-
case options.attributesKey: case options.parentKey: break; // skip
153-
case options.textKey: xml += writeText(element, options); break;
154-
<<<<<<< HEAD
155-
case options.cdataKey: xml += writeIndentation(options, depth, firstLine) + writeCdata(element, options); break;
156-
case options.doctypeKey: xml += writeIndentation(options, depth, firstLine) + writeDoctype(element, options); break;
157-
=======
158-
case options.cdataKey: xml += writeCdata(element, options); break;
159-
>>>>>>> origin/master
160-
case options.commentKey: xml += writeIndentation(options, depth, firstLine) + writeComment(element, options); break;
161-
default:
162-
if (element[key] instanceof Array) {
163-
element[key].forEach(function (el) {
164-
xml += writeIndentation(options, depth, firstLine) + writeElementCompact(el, key, options, depth, hasContent(el, options, true));
165-
});
166-
} else {
167-
xml += writeIndentation(options, depth, firstLine) + writeElementCompact(element[key], key, options, depth, hasContent(element[key], options, true));
168-
}
206+
nodes = element[key] instanceof Array ? element[key] : [element[key]];
207+
for (i = 0; i < nodes.length; ++i) {
208+
switch (key) {
209+
case options.declarationKey: xml += writeDeclaration(nodes[i], options); break;
210+
case options.attributesKey: case options.parentKey: break; // skip
211+
case options.textKey: xml += (options.indentText ? writeIndentation(options, depth, firstLine) : '') + writeText(nodes[i], options); break;
212+
case options.cdataKey: xml += (options.indentCdata ? writeIndentation(options, depth, firstLine) : '') + writeCdata(nodes[i], options); break;
213+
case options.doctypeKey: xml += writeIndentation(options, depth, firstLine) + writeDoctype(nodes[i], options); break;
214+
case options.commentKey: xml += writeIndentation(options, depth, firstLine) + writeComment(nodes[i], options); break;
215+
default: xml += writeIndentation(options, depth, firstLine) + writeElementCompact(nodes[i], key, options, depth, hasContentCompact(nodes[i], options));
216+
}
217+
firstLine = firstLine && !xml;
169218
}
170-
firstLine = firstLine && !xml;
171219
}
172220
}
173221
return xml;

lib/xml2js.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ function validateOptions (userOptions) {
1515
common.ensureFlagExists('ignoreCdata', options);
1616
common.ensureFlagExists('ignoreDoctype', options);
1717
common.ensureFlagExists('compact', options);
18+
common.ensureFlagExists('alwaysArray', options);
1819
common.ensureFlagExists('alwaysChildren', options);
1920
common.ensureFlagExists('addParent', options);
2021
common.ensureFlagExists('trim', options);

package.json

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "xml-js",
3-
"version": "1.0.2",
3+
"version": "1.1.0",
44
"description": "A convertor between XML text and Javascript object / JSON text.",
55
"repository": {
66
"type": "git",
@@ -55,20 +55,14 @@
5555
"globify": "^2.0.0",
5656
"istanbul": "^0.4.5",
5757
"jasmine": "^2.5.3",
58-
"node-inspector": "^1.0.0",
5958
"nodemon": "^1.11.0",
6059
"npm-run-all": "^4.0.1",
6160
"typescript": "^2.2.2",
6261
"watch": "^1.0.1"
6362
},
6463
"scripts": {
6564
"debug": "nodemon --inspect --watch lib/ --watch test/ --debug-brk test/index.js",
66-
"pre-node6.3.1-debug": "npm-run-all --parallel debug:*",
67-
"debug:listener": "node-inspector",
68-
"debug:jasmine": "nodemon --watch lib/ --watch test/ --debug-brk test/index.js",
69-
"xdebug:cli": "nodemon --watch lib/ --debug-brk index.js -- --help",
70-
"debug:live": "browser-sync start --port 8080 --server --startPath ?port=5858 --files lib/ test/ --no-open --no-ui --no-online",
71-
"debug:open": "biased-opener --browser chrome http://localhost:8080/?port=5858",
65+
"debug:cli": "nodemon --inspect --watch lib/ --debug-brk index.js -- --help",
7266
"jasmine": "jasmine JASMINE_CONFIG_PATH=./test/jasmine.json",
7367
"watch:jasmine": "watch \"npm run jasmine\" lib/ test/",
7468
"bundle:jasmine": "globify test/*_test.js --watch --verbose --list --outfile test/browse-jasmine/bundle.js",

test/common_test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ describe('Testing common.js:', function () {
99

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

12-
it('Copy no provided options', function () {
12+
it('Copy unprovided options', function () {
1313
expect(convert.copyOptions()).toEqual({});
1414
});
1515

0 commit comments

Comments
 (0)