├── .babelrc
├── .bithoundrc
├── .codeclimate.yml
├── .coveralls.yml
├── .editorconfig
├── .eslintrc.json
├── .gitattributes
├── .gitignore
├── .gitlab-ci.yml
├── .npmignore
├── .travis.yml
├── .vscode
└── launch.json
├── LICENSE
├── README.md
├── appveyor.yml
├── artwork
├── logo.svg
├── synopsis.svg
└── xml-js.vsdx
├── bin
├── cli-helper.js
├── cli.js
├── test.json
└── test.xml
├── circle.yml
├── dist
├── xml-js.js
└── xml-js.min.js
├── index.js
├── lib
├── array-helper.js
├── index.js
├── js2xml.js
├── json2xml.js
├── options-helper.js
├── xml2js.js
└── xml2json.js
├── package-lock.json
├── package.json
├── test
├── array-helper.spec.js
├── browse-jasmine
│ ├── bundle.js
│ ├── index.html
│ ├── jasmine-standalone-2.6.1.zip
│ └── lib
│ │ └── jasmine-2.6.1
│ │ ├── boot.js
│ │ ├── console.js
│ │ ├── jasmine-html.js
│ │ ├── jasmine.css
│ │ ├── jasmine.js
│ │ └── jasmine_favicon.png
├── cli-helper.spec.js
├── cli.spec.js
├── convert-fixtures.js
├── coverage-jest
│ ├── base.css
│ ├── coverage-final.json
│ ├── index.html
│ ├── lcov-report
│ │ ├── base.css
│ │ ├── index.html
│ │ ├── prettify.css
│ │ ├── prettify.js
│ │ ├── sort-arrow-sprite.png
│ │ └── sorter.js
│ ├── lcov.info
│ ├── prettify.css
│ ├── prettify.js
│ ├── sort-arrow-sprite.png
│ └── sorter.js
├── index.js
├── jasmine.json
├── jest.conf.js
├── js2xml-callbacks.spec.js
├── js2xml-issues.spec.js
├── js2xml-options.spec.js
├── options-helper.spec.js
├── pretest-jest.js
├── test-items.js
├── usage-example.js
├── xml2js-callbacks.spec.js
├── xml2js-issues.spec.js
├── xml2js-keys.spec.js
└── xml2js-options.spec.js
├── types
├── index.d.ts
├── tsconfig.json
├── typings.json
└── xml-js-tests.ts
├── webpack.config.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"]
3 | }
4 |
--------------------------------------------------------------------------------
/.bithoundrc:
--------------------------------------------------------------------------------
1 | {
2 | "ignore": [
3 | "**/_playground/**",
4 | "**/node_modules/**",
5 | "**/coverage/**",
6 | "**/jasmine/**",
7 | "**/test/**",
8 | "**/**-min-**",
9 | "**/**-min.**",
10 | "**/**.min.**"
11 | ],
12 | "test": [
13 | "**/test/**"
14 | ]
15 | }
--------------------------------------------------------------------------------
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | engines:
2 | csslint:
3 | enabled: true
4 | duplication:
5 | enabled: true
6 | config:
7 | languages:
8 | - javascript
9 | eslint:
10 | enabled: true
11 | fixme:
12 | enabled: true
13 | ratings:
14 | paths:
15 | - "**.css"
16 | - "**.js"
17 | exclude_paths:
18 | - _playground/
19 | - node_modules/
20 | - coverage/
21 | - jasmine/
22 | - test/
--------------------------------------------------------------------------------
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | repo_token: CaEwzjHxsKRqomJSYmGagrJdlR7uLHhHC
2 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | end_of_line = lf
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 |
10 | [*.{html,css,js,ts,json,yml}]
11 | charset = utf-8
12 | indent_style = space
13 | indent_size = 2
14 |
15 | [*.{xml}]
16 | indent_style = space
17 | indent_size = 4
18 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint:recommended",
3 | "env": {
4 | "node": true,
5 | "browser": true
6 | },
7 | "rules": {
8 | "excludedFiles": ["**/*.min.js"],
9 | "indent": ["error", 2],
10 | "linebreak-style": ["error", "unix"],
11 | "quotes": ["error", "single"],
12 | "semi": ["error", "always"],
13 | "no-cond-assign": ["error", "always"],
14 | "no-console": "off",
15 | "no-else-return": "warn"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=lf
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | _playground/
2 | node_modules/
3 | test/coverage-jasmine/
4 | test/coverage-jest/
5 | test/fixtures/
6 | npm-debug.log
7 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | # Official framework image. Look for the different tagged releases at:
2 | # https://hub.docker.com/r/library/node/tags/
3 | image: node:latest
4 |
5 | # This folder is cached between builds
6 | # http://docs.gitlab.com/ce/ci/yaml/README.html#cache
7 | cache:
8 | paths:
9 | - node_modules/
10 |
11 | test:
12 | script:
13 | - npm install
14 | - npm test
15 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | _playground/
3 | artwork/
4 | test/
5 | doc/
6 | package-lock.json
7 | yarn.lock
8 | webpack.config.json
9 | *.log
10 | *.yml
11 | .*
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8"
4 | - "node"
5 | - "lts/*"
6 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible Node.js debug attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "launch",
10 | "name": "Test Library",
11 | "program": "${workspaceRoot}/test/index",
12 | "outFiles": [
13 | "${workspaceRoot}/out/**/*.js"
14 | ]
15 | },
16 | {
17 | "type": "node",
18 | "request": "launch",
19 | "name": "Compile Docs",
20 | "program": "${workspaceRoot}/doc/compile-doc",
21 | "outFiles": [
22 | "${workspaceRoot}/out/**/*.js"
23 | ]
24 | }
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016-2017 Yousuf Almarzooqi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # Test against this version of Node.js
2 | #environment:
3 | # nodejs_version: "6"
4 |
5 | # Install scripts. (runs after repo cloning)
6 | install:
7 | # Get the latest stable version of Node.js or io.js
8 | - ps: Install-Product node ''
9 | # install modules
10 | - npm install
11 |
12 | # Post-install test scripts.
13 | test_script:
14 | # Output useful info for debugging.
15 | - node --version
16 | - npm --version
17 | # run tests
18 | - npm test
19 |
20 | # Don't actually build.
21 | build: off
22 |
23 | # branches to build
24 | branches:
25 | # whitelist
26 | only:
27 | - master
28 | - production
29 |
30 | # blacklist
31 | except:
32 | - gh-pages
33 |
--------------------------------------------------------------------------------
/artwork/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/artwork/xml-js.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nashwaan/xml-js/f0376f265c4f299100fb4766828ebf066a0edeec/artwork/xml-js.vsdx
--------------------------------------------------------------------------------
/bin/cli-helper.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 |
3 | getCommandLineHelp: function (command, requiredArgs, optionalArgs) {
4 | var reqArgs = requiredArgs.reduce(function (res, arg) {return res + ' <' + arg.arg + '>';}, '');
5 | var output = 'Usage: ' + command + reqArgs + ' [options]\n';
6 | requiredArgs.forEach(function (argument) {
7 | output += ' <' + argument.arg + '>' + Array(20 - argument.arg.length).join(' ') + argument.desc + '\n';
8 | });
9 | output += '\nOptions:\n';
10 | optionalArgs.forEach(function (argument) {
11 | output += ' --' + argument.arg + Array(20 - argument.arg.length).join(' ') + argument.desc + '\n';
12 | });
13 | return output;
14 | },
15 |
16 | mapCommandLineArgs: function (requiredArgs, optionalArgs) {
17 | var options = {}, r, o, a = 2;
18 | for (r = 0; r < requiredArgs.length; r += 1) {
19 | if (a < process.argv.length && process.argv[a].substr(0, 1) !== '-' && process.argv[a] !== 'JASMINE_CONFIG_PATH=./jasmine.json') {
20 | options[requiredArgs[r].option] = process.argv[a++];
21 | } else {
22 | break;
23 | }
24 | }
25 | for (; a < process.argv.length; a += 1) {
26 | for (o = 0; o < optionalArgs.length; o += 1) {
27 | if (optionalArgs[o].alias === process.argv[a].slice(1) || optionalArgs[o].arg === process.argv[a].slice(2)) {
28 | break;
29 | }
30 | }
31 | if (o < optionalArgs.length) {
32 | switch (optionalArgs[o].type) {
33 | case 'file': case 'string': case 'number':
34 | if (a + 1 < process.argv.length) {
35 | a += 1;
36 | options[optionalArgs[o].option] = (optionalArgs[o].type === 'number' ? Number(process.argv[a]) : process.argv[a]);
37 | }
38 | break;
39 | case 'flag':
40 | options[optionalArgs[o].option] = true; break;
41 | }
42 | }
43 | }
44 | return options;
45 | }
46 |
47 | };
48 |
--------------------------------------------------------------------------------
/bin/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | var fs = require('fs');
4 | var helper = require('./cli-helper');
5 | var project = require('../package.json');
6 | var xml2json = require('../lib/xml2json');
7 | var json2xml = require('../lib/json2xml');
8 |
9 | var output = '';
10 | var stream = '';
11 | var options = {};
12 | var requiredArgs = [
13 | { arg: 'src', type: 'file', option: 'src', desc: 'Input file that need to be converted.'}
14 | ];
15 | var optionalArgs = [
16 | { arg: 'help', alias: 'h', type: 'flag', option: 'help', desc: 'Display this help content.' },
17 | { arg: 'version', alias: 'v', type: 'flag', option: 'version', desc: 'Display version number of this module.' },
18 | { arg: 'out', type: 'file', option: 'out', desc: 'Output file where the converted result should be written.' },
19 | { arg: 'to-json', type: 'flag', option:'toJason', desc: 'Convert.' },
20 | { arg: 'compact', type: 'flag', option:'compact', desc: 'Compact JSON form (see explanation in www.npmjs.com/package/xml-js).' },
21 | { arg: 'spaces', type: 'number', option:'spaces', desc: 'Specifies amount of space indentation in the output.' },
22 | { arg: 'trim', type: 'flag', option:'trim', desc: 'Any whitespaces surrounding texts will be trimmed.' },
23 | // { arg: 'sanitize', type: 'flag', option:'sanitize', desc: 'Special xml characters will be replaced with entity codes.' },
24 | { arg: 'native-type', type: 'flag', option:'nativeType', desc: 'Numbers and boolean will be converted (coerced) to native type instead of text.' },
25 | { arg: 'always-array', type: 'flag', option:'alwaysArray', desc: 'Every element will always be an array type (applicable if --compact is set). If the passed value is an array, only elements with names in the passed array are always made arrays.' },
26 | { arg: 'always-children', type: 'flag', option:'alwaysChildren', desc: 'Every element will always contain sub-elements (applicable if --compact is not set).' },
27 | { arg: 'instruction-attr', type: 'flag', option:'instructionHasAttributes', desc: 'Whether to parse contents of processing instruction as attributes.' },
28 | { arg: 'full-tag', type: 'flag', option:'fullTagEmptyElement', desc: 'XML elements will always be in form.' },
29 | { arg: 'no-decl', type: 'flag', option:'ignoreDeclaration', desc: 'Declaration instruction will be ignored.' },
30 | { arg: 'no-decl', type: 'flag', option:'ignoreInstruction', desc: 'Processing instruction ...?> will be ignored.' },
31 | { arg: 'no-attr', type: 'flag', option:'ignoreAttributes', desc: 'Attributes of elements will be ignored.' },
32 | { arg: 'no-text', type: 'flag', option:'ignoreText', desc: 'Texts of elements will be ignored.' },
33 | { arg: 'no-cdata', type: 'flag', option:'ignoreCdata', desc: 'CData of elements will be ignored.' },
34 | { arg: 'no-doctype', type: 'flag', option:'ignoreDoctype', desc: 'DOCTYPE of elements will be ignored.' },
35 | { arg: 'no-comment', type: 'flag', option:'ignoreComment', desc: 'Comments of elements will be ignored.' },
36 | { arg: 'text-key', type: 'string', option:'textKey', desc: 'To change the default \'text\' key.' },
37 | { arg: 'cdata-key', type: 'string', option:'cdataKey', desc: 'To change the default \'cdata\' key.' },
38 | { arg: 'doctype-key', type: 'string', option:'doctypeKey', desc: 'To change the default \'doctype\' key.' },
39 | { arg: 'comment-key', type: 'string', option:'commentKey', desc: 'To change the default \'comment\' key.' },
40 | { arg: 'attributes-key', type: 'string', option:'attributesKey', desc: 'To change the default \'attributes\' key.' },
41 | { arg: 'declaration-key', type: 'string', option:'declarationKey', desc: 'To change the default \'declaration\' key .' },
42 | { arg: 'instruction-key', type: 'string', option:'instructionKey', desc: 'To change the default \'processing instruction\' key ...?>.' },
43 | { arg: 'type-key', type: 'string', option:'typeKey', desc: 'To change the default \'type\' key (applicable if --compact is not set).' },
44 | { arg: 'name-key', type: 'string', option:'nameKey', desc: 'To change the default \'name\' key (applicable if --compact is not set).' },
45 | { arg: 'elements-key', type: 'string', option:'elementsKey', desc: 'To change the default \'elements\' key (applicable if --compact is not set).' }
46 | ];
47 |
48 | process.stdin.setEncoding('utf8');
49 | process.stdin.on('readable', function () {
50 | var chunk = process.stdin.read();
51 | if (chunk !== null) {
52 | stream += chunk;
53 | }
54 | });
55 | process.stdin.on('end', function () {
56 | process.stdout.write(xml2json(stream, {}) + '\n');
57 | });
58 |
59 | options = helper.mapCommandLineArgs(requiredArgs, optionalArgs);
60 |
61 | if (options.version) {
62 | console.log(project.version);
63 | process.exit(0);
64 | } else if (options.help || process.argv.length <= 2 + requiredArgs.length - 1) {
65 | console.log(helper.getCommandLineHelp('xml-js', requiredArgs, optionalArgs));
66 | process.exit(process.argv.length <= 2 ? 1 : 0);
67 | } else if ('src' in options) {
68 | if (fs.statSync(options.src).isFile()) {
69 | if (options.src.split('.').pop() === 'xml') {
70 | output = xml2json(fs.readFileSync(options.src, 'utf8'), options);
71 | } else if (options.src.split('.').pop() === 'json') {
72 | output = json2xml(fs.readFileSync(options.src, 'utf8'), options);
73 | }
74 | if (options.out) {
75 | fs.writeFileSync(options.out, output, 'utf8');
76 | } else {
77 | console.log(output);
78 | }
79 | process.exit(0);
80 | }
81 | } else {
82 | process.exit(1);
83 | }
84 |
--------------------------------------------------------------------------------
/bin/test.json:
--------------------------------------------------------------------------------
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 | }
--------------------------------------------------------------------------------
/bin/test.xml:
--------------------------------------------------------------------------------
1 |
2 | bye!
3 |
4 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | general:
2 | branches:
3 | ignore:
4 | - gh-pages
5 | machine:
6 | node:
7 | version: 8.6.0
8 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib');
2 |
--------------------------------------------------------------------------------
/lib/array-helper.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 |
3 | isArray: function(value) {
4 | if (Array.isArray) {
5 | return Array.isArray(value);
6 | }
7 | // fallback for older browsers like IE 8
8 | return Object.prototype.toString.call( value ) === '[object Array]';
9 | }
10 |
11 | };
12 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | /*jslint node:true */
2 |
3 | var xml2js = require('./xml2js');
4 | var xml2json = require('./xml2json');
5 | var js2xml = require('./js2xml');
6 | var json2xml = require('./json2xml');
7 |
8 | module.exports = {
9 | xml2js: xml2js,
10 | xml2json: xml2json,
11 | js2xml: js2xml,
12 | json2xml: json2xml
13 | };
14 |
--------------------------------------------------------------------------------
/lib/js2xml.js:
--------------------------------------------------------------------------------
1 | var helper = require('./options-helper');
2 | var isArray = require('./array-helper').isArray;
3 |
4 | var currentElement, currentElementName;
5 |
6 | function validateOptions(userOptions) {
7 | var options = helper.copyOptions(userOptions);
8 | helper.ensureFlagExists('ignoreDeclaration', options);
9 | helper.ensureFlagExists('ignoreInstruction', options);
10 | helper.ensureFlagExists('ignoreAttributes', options);
11 | helper.ensureFlagExists('ignoreText', options);
12 | helper.ensureFlagExists('ignoreComment', options);
13 | helper.ensureFlagExists('ignoreCdata', options);
14 | helper.ensureFlagExists('ignoreDoctype', options);
15 | helper.ensureFlagExists('compact', options);
16 | helper.ensureFlagExists('indentText', options);
17 | helper.ensureFlagExists('indentCdata', options);
18 | helper.ensureFlagExists('indentAttributes', options);
19 | helper.ensureFlagExists('indentInstruction', options);
20 | helper.ensureFlagExists('fullTagEmptyElement', options);
21 | helper.ensureFlagExists('noQuotesForNativeAttributes', options);
22 | helper.ensureSpacesExists(options);
23 | if (typeof options.spaces === 'number') {
24 | options.spaces = Array(options.spaces + 1).join(' ');
25 | }
26 | helper.ensureKeyExists('declaration', options);
27 | helper.ensureKeyExists('instruction', options);
28 | helper.ensureKeyExists('attributes', options);
29 | helper.ensureKeyExists('text', options);
30 | helper.ensureKeyExists('comment', options);
31 | helper.ensureKeyExists('cdata', options);
32 | helper.ensureKeyExists('doctype', options);
33 | helper.ensureKeyExists('type', options);
34 | helper.ensureKeyExists('name', options);
35 | helper.ensureKeyExists('elements', options);
36 | helper.checkFnExists('doctype', options);
37 | helper.checkFnExists('instruction', options);
38 | helper.checkFnExists('cdata', options);
39 | helper.checkFnExists('comment', options);
40 | helper.checkFnExists('text', options);
41 | helper.checkFnExists('instructionName', options);
42 | helper.checkFnExists('elementName', options);
43 | helper.checkFnExists('attributeName', options);
44 | helper.checkFnExists('attributeValue', options);
45 | helper.checkFnExists('attributes', options);
46 | helper.checkFnExists('fullTagEmptyElement', options);
47 | return options;
48 | }
49 |
50 | function writeIndentation(options, depth, firstLine) {
51 | return (!firstLine && options.spaces ? '\n' : '') + Array(depth + 1).join(options.spaces);
52 | }
53 |
54 | function writeAttributes(attributes, options, depth) {
55 | if (options.ignoreAttributes) {
56 | return '';
57 | }
58 | if ('attributesFn' in options) {
59 | attributes = options.attributesFn(attributes, currentElementName, currentElement);
60 | }
61 | var key, attr, attrName, quote, result = [];
62 | for (key in attributes) {
63 | if (attributes.hasOwnProperty(key) && attributes[key] !== null && attributes[key] !== undefined) {
64 | quote = options.noQuotesForNativeAttributes && typeof attributes[key] !== 'string' ? '' : '"';
65 | attr = '' + attributes[key]; // ensure number and boolean are converted to String
66 | attr = attr.replace(/"/g, '"');
67 | attrName = 'attributeNameFn' in options ? options.attributeNameFn(key, attr, currentElementName, currentElement) : key;
68 | result.push((options.spaces && options.indentAttributes? writeIndentation(options, depth+1, false) : ' '));
69 | result.push(attrName + '=' + quote + ('attributeValueFn' in options ? options.attributeValueFn(attr, key, currentElementName, currentElement) : attr) + quote);
70 | }
71 | }
72 | if (attributes && Object.keys(attributes).length && options.spaces && options.indentAttributes) {
73 | result.push(writeIndentation(options, depth, false));
74 | }
75 | return result.join('');
76 | }
77 |
78 | function writeDeclaration(declaration, options, depth) {
79 | currentElement = declaration;
80 | currentElementName = 'xml';
81 | return options.ignoreDeclaration ? '' : '' + 'xml' + writeAttributes(declaration[options.attributesKey], options, depth) + '?>';
82 | }
83 |
84 | function writeInstruction(instruction, options, depth) {
85 | if (options.ignoreInstruction) {
86 | return '';
87 | }
88 | var key;
89 | for (key in instruction) {
90 | if (instruction.hasOwnProperty(key)) {
91 | break;
92 | }
93 | }
94 | var instructionName = 'instructionNameFn' in options ? options.instructionNameFn(key, instruction[key], currentElementName, currentElement) : key;
95 | if (typeof instruction[key] === 'object') {
96 | currentElement = instruction;
97 | currentElementName = instructionName;
98 | return '' + instructionName + writeAttributes(instruction[key][options.attributesKey], options, depth) + '?>';
99 | } else {
100 | var instructionValue = instruction[key] ? instruction[key] : '';
101 | if ('instructionFn' in options) instructionValue = options.instructionFn(instructionValue, key, currentElementName, currentElement);
102 | return '' + instructionName + (instructionValue ? ' ' + instructionValue : '') + '?>';
103 | }
104 | }
105 |
106 | function writeComment(comment, options) {
107 | return options.ignoreComment ? '' : '';
108 | }
109 |
110 | function writeCdata(cdata, options) {
111 | return options.ignoreCdata ? '' : '', ']]]]>')) + ']]>';
112 | }
113 |
114 | function writeDoctype(doctype, options) {
115 | return options.ignoreDoctype ? '' : '';
116 | }
117 |
118 | function writeText(text, options) {
119 | if (options.ignoreText) return '';
120 | text = '' + text; // ensure Number and Boolean are converted to String
121 | text = text.replace(/&/g, '&'); // desanitize to avoid double sanitization
122 | text = text.replace(/&/g, '&').replace(//g, '>');
123 | return 'textFn' in options ? options.textFn(text, currentElementName, currentElement) : text;
124 | }
125 |
126 | function hasContent(element, options) {
127 | var i;
128 | if (element.elements && element.elements.length) {
129 | for (i = 0; i < element.elements.length; ++i) {
130 | switch (element.elements[i][options.typeKey]) {
131 | case 'text':
132 | if (options.indentText) {
133 | return true;
134 | }
135 | break; // skip to next key
136 | case 'cdata':
137 | if (options.indentCdata) {
138 | return true;
139 | }
140 | break; // skip to next key
141 | case 'instruction':
142 | if (options.indentInstruction) {
143 | return true;
144 | }
145 | break; // skip to next key
146 | case 'doctype':
147 | case 'comment':
148 | case 'element':
149 | return true;
150 | default:
151 | return true;
152 | }
153 | }
154 | }
155 | return false;
156 | }
157 |
158 | function writeElement(element, options, depth) {
159 | currentElement = element;
160 | currentElementName = element.name;
161 | var xml = [], elementName = 'elementNameFn' in options ? options.elementNameFn(element.name, element) : element.name;
162 | xml.push('<' + elementName);
163 | if (element[options.attributesKey]) {
164 | xml.push(writeAttributes(element[options.attributesKey], options, depth));
165 | }
166 | var withClosingTag = element[options.elementsKey] && element[options.elementsKey].length || element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve';
167 | if (!withClosingTag) {
168 | if ('fullTagEmptyElementFn' in options) {
169 | withClosingTag = options.fullTagEmptyElementFn(element.name, element);
170 | } else {
171 | withClosingTag = options.fullTagEmptyElement;
172 | }
173 | }
174 | if (withClosingTag) {
175 | xml.push('>');
176 | if (element[options.elementsKey] && element[options.elementsKey].length) {
177 | xml.push(writeElements(element[options.elementsKey], options, depth + 1));
178 | currentElement = element;
179 | currentElementName = element.name;
180 | }
181 | xml.push(options.spaces && hasContent(element, options) ? '\n' + Array(depth + 1).join(options.spaces) : '');
182 | xml.push('' + elementName + '>');
183 | } else {
184 | xml.push('/>');
185 | }
186 | return xml.join('');
187 | }
188 |
189 | function writeElements(elements, options, depth, firstLine) {
190 | return elements.reduce(function (xml, element) {
191 | var indent = writeIndentation(options, depth, firstLine && !xml);
192 | switch (element.type) {
193 | case 'element': return xml + indent + writeElement(element, options, depth);
194 | case 'comment': return xml + indent + writeComment(element[options.commentKey], options);
195 | case 'doctype': return xml + indent + writeDoctype(element[options.doctypeKey], options);
196 | case 'cdata': return xml + (options.indentCdata ? indent : '') + writeCdata(element[options.cdataKey], options);
197 | case 'text': return xml + (options.indentText ? indent : '') + writeText(element[options.textKey], options);
198 | case 'instruction':
199 | var instruction = {};
200 | instruction[element[options.nameKey]] = element[options.attributesKey] ? element : element[options.instructionKey];
201 | return xml + (options.indentInstruction ? indent : '') + writeInstruction(instruction, options, depth);
202 | }
203 | }, '');
204 | }
205 |
206 | function hasContentCompact(element, options, anyContent) {
207 | var key;
208 | for (key in element) {
209 | if (element.hasOwnProperty(key)) {
210 | switch (key) {
211 | case options.parentKey:
212 | case options.attributesKey:
213 | break; // skip to next key
214 | case options.textKey:
215 | if (options.indentText || anyContent) {
216 | return true;
217 | }
218 | break; // skip to next key
219 | case options.cdataKey:
220 | if (options.indentCdata || anyContent) {
221 | return true;
222 | }
223 | break; // skip to next key
224 | case options.instructionKey:
225 | if (options.indentInstruction || anyContent) {
226 | return true;
227 | }
228 | break; // skip to next key
229 | case options.doctypeKey:
230 | case options.commentKey:
231 | return true;
232 | default:
233 | return true;
234 | }
235 | }
236 | }
237 | return false;
238 | }
239 |
240 | function writeElementCompact(element, name, options, depth, indent) {
241 | currentElement = element;
242 | currentElementName = name;
243 | var elementName = 'elementNameFn' in options ? options.elementNameFn(name, element) : name;
244 | if (typeof element === 'undefined' || element === null || element === '') {
245 | return 'fullTagEmptyElementFn' in options && options.fullTagEmptyElementFn(name, element) || options.fullTagEmptyElement ? '<' + elementName + '>' + elementName + '>' : '<' + elementName + '/>';
246 | }
247 | var xml = [];
248 | if (name) {
249 | xml.push('<' + elementName);
250 | if (typeof element !== 'object') {
251 | xml.push('>' + writeText(element,options) + '' + elementName + '>');
252 | return xml.join('');
253 | }
254 | if (element[options.attributesKey]) {
255 | xml.push(writeAttributes(element[options.attributesKey], options, depth));
256 | }
257 | var withClosingTag = hasContentCompact(element, options, true) || element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve';
258 | if (!withClosingTag) {
259 | if ('fullTagEmptyElementFn' in options) {
260 | withClosingTag = options.fullTagEmptyElementFn(name, element);
261 | } else {
262 | withClosingTag = options.fullTagEmptyElement;
263 | }
264 | }
265 | if (withClosingTag) {
266 | xml.push('>');
267 | } else {
268 | xml.push('/>');
269 | return xml.join('');
270 | }
271 | }
272 | xml.push(writeElementsCompact(element, options, depth + 1, false));
273 | currentElement = element;
274 | currentElementName = name;
275 | if (name) {
276 | xml.push((indent ? writeIndentation(options, depth, false) : '') + '' + elementName + '>');
277 | }
278 | return xml.join('');
279 | }
280 |
281 | function writeElementsCompact(element, options, depth, firstLine) {
282 | var i, key, nodes, xml = [];
283 | for (key in element) {
284 | if (element.hasOwnProperty(key)) {
285 | nodes = isArray(element[key]) ? element[key] : [element[key]];
286 | for (i = 0; i < nodes.length; ++i) {
287 | switch (key) {
288 | case options.declarationKey: xml.push(writeDeclaration(nodes[i], options, depth)); break;
289 | case options.instructionKey: xml.push((options.indentInstruction ? writeIndentation(options, depth, firstLine) : '') + writeInstruction(nodes[i], options, depth)); break;
290 | case options.attributesKey: case options.parentKey: break; // skip
291 | case options.textKey: xml.push((options.indentText ? writeIndentation(options, depth, firstLine) : '') + writeText(nodes[i], options)); break;
292 | case options.cdataKey: xml.push((options.indentCdata ? writeIndentation(options, depth, firstLine) : '') + writeCdata(nodes[i], options)); break;
293 | case options.doctypeKey: xml.push(writeIndentation(options, depth, firstLine) + writeDoctype(nodes[i], options)); break;
294 | case options.commentKey: xml.push(writeIndentation(options, depth, firstLine) + writeComment(nodes[i], options)); break;
295 | default: xml.push(writeIndentation(options, depth, firstLine) + writeElementCompact(nodes[i], key, options, depth, hasContentCompact(nodes[i], options)));
296 | }
297 | firstLine = firstLine && !xml.length;
298 | }
299 | }
300 | }
301 | return xml.join('');
302 | }
303 |
304 | module.exports = function (js, options) {
305 | options = validateOptions(options);
306 | var xml = [];
307 | currentElement = js;
308 | currentElementName = '_root_';
309 | if (options.compact) {
310 | xml.push(writeElementsCompact(js, options, 0, true));
311 | } else {
312 | if (js[options.declarationKey]) {
313 | xml.push(writeDeclaration(js[options.declarationKey], options, 0));
314 | }
315 | if (js[options.elementsKey] && js[options.elementsKey].length) {
316 | xml.push(writeElements(js[options.elementsKey], options, 0, !xml.length));
317 | }
318 | }
319 | return xml.join('');
320 | };
321 |
--------------------------------------------------------------------------------
/lib/json2xml.js:
--------------------------------------------------------------------------------
1 | var js2xml = require('./js2xml.js');
2 |
3 | module.exports = function (json, options) {
4 | if (json instanceof Buffer) {
5 | json = json.toString();
6 | }
7 | var js = null;
8 | if (typeof (json) === 'string') {
9 | try {
10 | js = JSON.parse(json);
11 | } catch (e) {
12 | throw new Error('The JSON structure is invalid');
13 | }
14 | } else {
15 | js = json;
16 | }
17 | return js2xml(js, options);
18 | };
19 |
--------------------------------------------------------------------------------
/lib/options-helper.js:
--------------------------------------------------------------------------------
1 | var isArray = require('./array-helper').isArray;
2 |
3 | module.exports = {
4 |
5 | copyOptions: function (options) {
6 | var key, copy = {};
7 | for (key in options) {
8 | if (options.hasOwnProperty(key)) {
9 | copy[key] = options[key];
10 | }
11 | }
12 | return copy;
13 | },
14 |
15 | ensureFlagExists: function (item, options) {
16 | if (!(item in options) || typeof options[item] !== 'boolean') {
17 | options[item] = false;
18 | }
19 | },
20 |
21 | ensureSpacesExists: function (options) {
22 | if (!('spaces' in options) || (typeof options.spaces !== 'number' && typeof options.spaces !== 'string')) {
23 | options.spaces = 0;
24 | }
25 | },
26 |
27 | ensureAlwaysArrayExists: function (options) {
28 | if (!('alwaysArray' in options) || (typeof options.alwaysArray !== 'boolean' && !isArray(options.alwaysArray))) {
29 | options.alwaysArray = false;
30 | }
31 | },
32 |
33 | ensureKeyExists: function (key, options) {
34 | if (!(key + 'Key' in options) || typeof options[key + 'Key'] !== 'string') {
35 | options[key + 'Key'] = options.compact ? '_' + key : key;
36 | }
37 | },
38 |
39 | checkFnExists: function (key, options) {
40 | return key + 'Fn' in options;
41 | }
42 |
43 | };
44 |
--------------------------------------------------------------------------------
/lib/xml2js.js:
--------------------------------------------------------------------------------
1 | var sax = require('sax');
2 | var expat /*= require('node-expat');*/ = { on: function () { }, parse: function () { } };
3 | var helper = require('./options-helper');
4 | var isArray = require('./array-helper').isArray;
5 |
6 | var options;
7 | var pureJsParser = true;
8 | var currentElement;
9 |
10 | function validateOptions(userOptions) {
11 | options = helper.copyOptions(userOptions);
12 | helper.ensureFlagExists('ignoreDeclaration', options);
13 | helper.ensureFlagExists('ignoreInstruction', options);
14 | helper.ensureFlagExists('ignoreAttributes', options);
15 | helper.ensureFlagExists('ignoreText', options);
16 | helper.ensureFlagExists('ignoreComment', options);
17 | helper.ensureFlagExists('ignoreCdata', options);
18 | helper.ensureFlagExists('ignoreDoctype', options);
19 | helper.ensureFlagExists('compact', options);
20 | helper.ensureFlagExists('alwaysChildren', options);
21 | helper.ensureFlagExists('addParent', options);
22 | helper.ensureFlagExists('trim', options);
23 | helper.ensureFlagExists('nativeType', options);
24 | helper.ensureFlagExists('nativeTypeAttributes', options);
25 | helper.ensureFlagExists('sanitize', options);
26 | helper.ensureFlagExists('instructionHasAttributes', options);
27 | helper.ensureFlagExists('captureSpacesBetweenElements', options);
28 | helper.ensureAlwaysArrayExists(options);
29 | helper.ensureKeyExists('declaration', options);
30 | helper.ensureKeyExists('instruction', options);
31 | helper.ensureKeyExists('attributes', options);
32 | helper.ensureKeyExists('text', options);
33 | helper.ensureKeyExists('comment', options);
34 | helper.ensureKeyExists('cdata', options);
35 | helper.ensureKeyExists('doctype', options);
36 | helper.ensureKeyExists('type', options);
37 | helper.ensureKeyExists('name', options);
38 | helper.ensureKeyExists('elements', options);
39 | helper.ensureKeyExists('parent', options);
40 | helper.checkFnExists('doctype', options);
41 | helper.checkFnExists('instruction', options);
42 | helper.checkFnExists('cdata', options);
43 | helper.checkFnExists('comment', options);
44 | helper.checkFnExists('text', options);
45 | helper.checkFnExists('instructionName', options);
46 | helper.checkFnExists('elementName', options);
47 | helper.checkFnExists('attributeName', options);
48 | helper.checkFnExists('attributeValue', options);
49 | helper.checkFnExists('attributes', options);
50 | return options;
51 | }
52 |
53 | function nativeType(value) {
54 | var nValue = Number(value);
55 | if (!isNaN(nValue)) {
56 | return nValue;
57 | }
58 | var bValue = value.toLowerCase();
59 | if (bValue === 'true') {
60 | return true;
61 | } else if (bValue === 'false') {
62 | return false;
63 | }
64 | return value;
65 | }
66 |
67 | function addField(type, value) {
68 | var key;
69 | if (options.compact) {
70 | if (
71 | !currentElement[options[type + 'Key']] &&
72 | (isArray(options.alwaysArray) ? options.alwaysArray.indexOf(options[type + 'Key']) !== -1 : options.alwaysArray)
73 | ) {
74 | currentElement[options[type + 'Key']] = [];
75 | }
76 | if (currentElement[options[type + 'Key']] && !isArray(currentElement[options[type + 'Key']])) {
77 | currentElement[options[type + 'Key']] = [currentElement[options[type + 'Key']]];
78 | }
79 | if (type + 'Fn' in options && typeof value === 'string') {
80 | value = options[type + 'Fn'](value, currentElement);
81 | }
82 | if (type === 'instruction' && ('instructionFn' in options || 'instructionNameFn' in options)) {
83 | for (key in value) {
84 | if (value.hasOwnProperty(key)) {
85 | if ('instructionFn' in options) {
86 | value[key] = options.instructionFn(value[key], key, currentElement);
87 | } else {
88 | var temp = value[key];
89 | delete value[key];
90 | value[options.instructionNameFn(key, temp, currentElement)] = temp;
91 | }
92 | }
93 | }
94 | }
95 | if (isArray(currentElement[options[type + 'Key']])) {
96 | currentElement[options[type + 'Key']].push(value);
97 | } else {
98 | currentElement[options[type + 'Key']] = value;
99 | }
100 | } else {
101 | if (!currentElement[options.elementsKey]) {
102 | currentElement[options.elementsKey] = [];
103 | }
104 | var element = {};
105 | element[options.typeKey] = type;
106 | if (type === 'instruction') {
107 | for (key in value) {
108 | if (value.hasOwnProperty(key)) {
109 | break;
110 | }
111 | }
112 | element[options.nameKey] = 'instructionNameFn' in options ? options.instructionNameFn(key, value, currentElement) : key;
113 | if (options.instructionHasAttributes) {
114 | element[options.attributesKey] = value[key][options.attributesKey];
115 | if ('instructionFn' in options) {
116 | element[options.attributesKey] = options.instructionFn(element[options.attributesKey], key, currentElement);
117 | }
118 | } else {
119 | if ('instructionFn' in options) {
120 | value[key] = options.instructionFn(value[key], key, currentElement);
121 | }
122 | element[options.instructionKey] = value[key];
123 | }
124 | } else {
125 | if (type + 'Fn' in options) {
126 | value = options[type + 'Fn'](value, currentElement);
127 | }
128 | element[options[type + 'Key']] = value;
129 | }
130 | if (options.addParent) {
131 | element[options.parentKey] = currentElement;
132 | }
133 | currentElement[options.elementsKey].push(element);
134 | }
135 | }
136 |
137 | function manipulateAttributes(attributes) {
138 | if ('attributesFn' in options && attributes) {
139 | attributes = options.attributesFn(attributes, currentElement);
140 | }
141 | if ((options.trim || 'attributeValueFn' in options || 'attributeNameFn' in options || options.nativeTypeAttributes) && attributes) {
142 | var key;
143 | for (key in attributes) {
144 | if (attributes.hasOwnProperty(key)) {
145 | if (options.trim) attributes[key] = attributes[key].trim();
146 | if (options.nativeTypeAttributes) {
147 | attributes[key] = nativeType(attributes[key]);
148 | }
149 | if ('attributeValueFn' in options) attributes[key] = options.attributeValueFn(attributes[key], key, currentElement);
150 | if ('attributeNameFn' in options) {
151 | var temp = attributes[key];
152 | delete attributes[key];
153 | attributes[options.attributeNameFn(key, attributes[key], currentElement)] = temp;
154 | }
155 | }
156 | }
157 | }
158 | return attributes;
159 | }
160 |
161 | function onInstruction(instruction) {
162 | var attributes = {};
163 | if (instruction.body && (instruction.name.toLowerCase() === 'xml' || options.instructionHasAttributes)) {
164 | var attrsRegExp = /([\w:-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|(\w+))\s*/g;
165 | var match;
166 | while ((match = attrsRegExp.exec(instruction.body)) !== null) {
167 | attributes[match[1]] = match[2] || match[3] || match[4];
168 | }
169 | attributes = manipulateAttributes(attributes);
170 | }
171 | if (instruction.name.toLowerCase() === 'xml') {
172 | if (options.ignoreDeclaration) {
173 | return;
174 | }
175 | currentElement[options.declarationKey] = {};
176 | if (Object.keys(attributes).length) {
177 | currentElement[options.declarationKey][options.attributesKey] = attributes;
178 | }
179 | if (options.addParent) {
180 | currentElement[options.declarationKey][options.parentKey] = currentElement;
181 | }
182 | } else {
183 | if (options.ignoreInstruction) {
184 | return;
185 | }
186 | if (options.trim) {
187 | instruction.body = instruction.body.trim();
188 | }
189 | var value = {};
190 | if (options.instructionHasAttributes && Object.keys(attributes).length) {
191 | value[instruction.name] = {};
192 | value[instruction.name][options.attributesKey] = attributes;
193 | } else {
194 | value[instruction.name] = instruction.body;
195 | }
196 | addField('instruction', value);
197 | }
198 | }
199 |
200 | function onStartElement(name, attributes) {
201 | var element;
202 | if (typeof name === 'object') {
203 | attributes = name.attributes;
204 | name = name.name;
205 | }
206 | attributes = manipulateAttributes(attributes);
207 | if ('elementNameFn' in options) {
208 | name = options.elementNameFn(name, currentElement);
209 | }
210 | if (options.compact) {
211 | element = {};
212 | if (!options.ignoreAttributes && attributes && Object.keys(attributes).length) {
213 | element[options.attributesKey] = {};
214 | var key;
215 | for (key in attributes) {
216 | if (attributes.hasOwnProperty(key)) {
217 | element[options.attributesKey][key] = attributes[key];
218 | }
219 | }
220 | }
221 | if (
222 | !(name in currentElement) &&
223 | (isArray(options.alwaysArray) ? options.alwaysArray.indexOf(name) !== -1 : options.alwaysArray)
224 | ) {
225 | currentElement[name] = [];
226 | }
227 | if (currentElement[name] && !isArray(currentElement[name])) {
228 | currentElement[name] = [currentElement[name]];
229 | }
230 | if (isArray(currentElement[name])) {
231 | currentElement[name].push(element);
232 | } else {
233 | currentElement[name] = element;
234 | }
235 | } else {
236 | if (!currentElement[options.elementsKey]) {
237 | currentElement[options.elementsKey] = [];
238 | }
239 | element = {};
240 | element[options.typeKey] = 'element';
241 | element[options.nameKey] = name;
242 | if (!options.ignoreAttributes && attributes && Object.keys(attributes).length) {
243 | element[options.attributesKey] = attributes;
244 | }
245 | if (options.alwaysChildren) {
246 | element[options.elementsKey] = [];
247 | }
248 | currentElement[options.elementsKey].push(element);
249 | }
250 | element[options.parentKey] = currentElement; // will be deleted in onEndElement() if !options.addParent
251 | currentElement = element;
252 | }
253 |
254 | function onText(text) {
255 | if (options.ignoreText) {
256 | return;
257 | }
258 | if (!text.trim() && !options.captureSpacesBetweenElements) {
259 | return;
260 | }
261 | if (options.trim) {
262 | text = text.trim();
263 | }
264 | if (options.nativeType) {
265 | text = nativeType(text);
266 | }
267 | if (options.sanitize) {
268 | text = text.replace(/&/g, '&').replace(//g, '>');
269 | }
270 | addField('text', text);
271 | }
272 |
273 | function onComment(comment) {
274 | if (options.ignoreComment) {
275 | return;
276 | }
277 | if (options.trim) {
278 | comment = comment.trim();
279 | }
280 | addField('comment', comment);
281 | }
282 |
283 | function onEndElement(name) {
284 | var parentElement = currentElement[options.parentKey];
285 | if (!options.addParent) {
286 | delete currentElement[options.parentKey];
287 | }
288 | currentElement = parentElement;
289 | }
290 |
291 | function onCdata(cdata) {
292 | if (options.ignoreCdata) {
293 | return;
294 | }
295 | if (options.trim) {
296 | cdata = cdata.trim();
297 | }
298 | addField('cdata', cdata);
299 | }
300 |
301 | function onDoctype(doctype) {
302 | if (options.ignoreDoctype) {
303 | return;
304 | }
305 | doctype = doctype.replace(/^ /, '');
306 | if (options.trim) {
307 | doctype = doctype.trim();
308 | }
309 | addField('doctype', doctype);
310 | }
311 |
312 | function onError(error) {
313 | error.note = error; //console.error(error);
314 | }
315 |
316 | module.exports = function (xml, userOptions) {
317 |
318 | var parser = pureJsParser ? sax.parser(true, {}) : parser = new expat.Parser('UTF-8');
319 | var result = {};
320 | currentElement = result;
321 |
322 | options = validateOptions(userOptions);
323 |
324 | if (pureJsParser) {
325 | parser.opt = {strictEntities: true};
326 | parser.onopentag = onStartElement;
327 | parser.ontext = onText;
328 | parser.oncomment = onComment;
329 | parser.onclosetag = onEndElement;
330 | parser.onerror = onError;
331 | parser.oncdata = onCdata;
332 | parser.ondoctype = onDoctype;
333 | parser.onprocessinginstruction = onInstruction;
334 | } else {
335 | parser.on('startElement', onStartElement);
336 | parser.on('text', onText);
337 | parser.on('comment', onComment);
338 | parser.on('endElement', onEndElement);
339 | parser.on('error', onError);
340 | //parser.on('startCdata', onStartCdata);
341 | //parser.on('endCdata', onEndCdata);
342 | //parser.on('entityDecl', onEntityDecl);
343 | }
344 |
345 | if (pureJsParser) {
346 | parser.write(xml).close();
347 | } else {
348 | if (!parser.parse(xml)) {
349 | throw new Error('XML parsing error: ' + parser.getError());
350 | }
351 | }
352 |
353 | if (result[options.elementsKey]) {
354 | var temp = result[options.elementsKey];
355 | delete result[options.elementsKey];
356 | result[options.elementsKey] = temp;
357 | delete result.text;
358 | }
359 |
360 | return result;
361 |
362 | };
363 |
--------------------------------------------------------------------------------
/lib/xml2json.js:
--------------------------------------------------------------------------------
1 | var helper = require('./options-helper');
2 | var xml2js = require('./xml2js');
3 |
4 | function validateOptions (userOptions) {
5 | var options = helper.copyOptions(userOptions);
6 | helper.ensureSpacesExists(options);
7 | return options;
8 | }
9 |
10 | module.exports = function(xml, userOptions) {
11 | var options, js, json, parentKey;
12 | options = validateOptions(userOptions);
13 | js = xml2js(xml, options);
14 | parentKey = 'compact' in options && options.compact ? '_parent' : 'parent';
15 | // parentKey = ptions.compact ? '_parent' : 'parent'; // consider this
16 | if ('addParent' in options && options.addParent) {
17 | json = JSON.stringify(js, function (k, v) { return k === parentKey? '_' : v; }, options.spaces);
18 | } else {
19 | json = JSON.stringify(js, null, options.spaces);
20 | }
21 | return json.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
22 | };
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "xml-js",
3 | "version": "1.6.11",
4 | "description": "A convertor between XML text and Javascript object / JSON text.",
5 | "repository": {
6 | "type": "git",
7 | "url": "git+https://github.com/nashwaan/xml-js.git"
8 | },
9 | "author": "Yousuf Almarzooqi ",
10 | "license": "MIT",
11 | "bugs": {
12 | "url": "https://github.com/nashwaan/xml-js/issues"
13 | },
14 | "homepage": "https://github.com/nashwaan/xml-js#readme",
15 | "keywords": [
16 | "XML",
17 | "xml",
18 | "js",
19 | "JSON",
20 | "json",
21 | "cdata",
22 | "CDATA",
23 | "doctype",
24 | "processing instruction",
25 | "Javascript",
26 | "js2xml",
27 | "json2xml",
28 | "xml2js",
29 | "xml2json",
30 | "transform",
31 | "transformer",
32 | "transforming",
33 | "transformation",
34 | "convert",
35 | "convertor",
36 | "converting",
37 | "conversion",
38 | "parse",
39 | "parser",
40 | "parsing"
41 | ],
42 | "main": "lib/index.js",
43 | "bin": "./bin/cli.js",
44 | "types": "./types/index.d.ts",
45 | "scripts": {
46 | "build": "webpack",
47 | "doc": "node doc/compile-doc.js",
48 | "watch:doc": "watch \"npm run doc\" doc/templates/",
49 | "live:doc": "browser-sync start --port 9997 --server doc/ --files doc/templates/ --no-open --no-ui --no-online",
50 | "open:doc": "biased-opener --browser chrome http://localhost:9997",
51 | "start:doc": "npm-run-all --parallel watch:doc live:doc open:doc",
52 | "debug": "nodemon --inspect --watch lib/ --watch test/ --debug-brk test/index.js",
53 | "debug:cli": "nodemon --inspect --watch lib/ --debug-brk index.js -- --help",
54 | "jest": "jest --config=test/jest.conf.js",
55 | "jasmine": "jasmine JASMINE_CONFIG_PATH=./test/jasmine.json",
56 | "watch:jasmine": "watch \"npm run jasmine\" lib/ test/ --ignoreDirectoryPattern=/browse-.+/",
57 | "bundle:jasmine": "globify test/*.spec.js --watch --verbose --list --outfile test/browse-jasmine/bundle.js",
58 | "live:jasmine": "browser-sync start --port 9999 --server test/browse-jasmine/ --files test/browse-jasmine/ --no-open --no-ui --no-online",
59 | "open-help": "biased-opener --help",
60 | "open:jasmine": "biased-opener --browser chrome http://localhost:9999",
61 | "istanbul-original": "istanbul cover --dir test/coverage-jasmine -x test/browse-** test/index.js",
62 | "istanbul": "istanbul cover --dir test/coverage-jasmine test/index.js",
63 | "watch:istanbul": "watch \"npm run istanbul\" lib/ test/ --ignoreDirectoryPattern=/coverage-.+/",
64 | "live:istanbul": "browser-sync start --port 9998 --server test/coverage-jasmine/lcov-report/ --files test/coverage-jasmine/lcov-report/ --no-open --no-ui --no-online",
65 | "open:istanbul": "biased-opener --browser chrome http://localhost:9998",
66 | "live": "npm-run-all --parallel live:* open:*",
67 | "start": "npm-run-all --parallel bundle:jasmine live:jasmine open:jasmine watch:istanbul live:istanbul open:istanbul",
68 | "git:commit": "git add . && git commit -a -m \"Committed by npm script.\" && git push origin master",
69 | "git:push": "git push origin master",
70 | "deploy": "npm-run-all --serial coverage:* git:*",
71 | "coverage": "npm-run-all coverage:*",
72 | "coverage:a-step": "npm run istanbul",
73 | "coverage:coveralls": "cross-env COVERALLS_REPO_TOKEN=CaEwzjHxsKRqomJSYmGagrJdlR7uLHhHC && cat ./test/coverage-jasmine/lcov.info | coveralls",
74 | "coverage:codecov": "codecov --token=0e52af41-702b-4d7f-8aa3-61145ac36624 --file=test/coverage-jasmine/lcov.info ",
75 | "coverage:codacy": "cross-env CODACY_PROJECT_TOKEN=0207815122ea49a68241d1aa435f21f1 && cat ./test/coverage-jasmine/lcov.info | codacy-coverage",
76 | "coverage:codeclimate": "cross-env CODECLIMATE_REPO_TOKEN=60848a077f9070acf358b0c7145f0a2698a460ddeca7d8250815e75aa4333f7d codeclimate-test-reporter < test\\coverage-jasmine\\lcov.info",
77 | "prepublish": "npm run test",
78 | "test": "npm run jasmine && npm run jest && npm run test:types",
79 | "test:types": "tsc -p ./types"
80 | },
81 | "dependencies": {
82 | "sax": "^1.2.4"
83 | },
84 | "devDependencies": {
85 | "babel-core": "^6.26.3",
86 | "babel-loader": "^7.1.4",
87 | "babel-preset-env": "^1.7.0",
88 | "biased-opener": "^0.2.8",
89 | "browser-sync": "^2.26.3",
90 | "cash-cat": "^0.2.0",
91 | "codacy-coverage": "^3.4.0",
92 | "codeclimate-test-reporter": "^0.5.1",
93 | "codecov": "^3.1.0",
94 | "coveralls": "^3.0.2",
95 | "cross-env": "^5.2.0",
96 | "eslint": "^5.12.0",
97 | "globify": "^2.3.4",
98 | "istanbul": "^0.4.5",
99 | "jasmine": "^3.3.1",
100 | "jest": "^20.0.4",
101 | "jest-cli": "^20.0.4",
102 | "jsonpath": "^1.0.0",
103 | "nodemon": "^1.18.9",
104 | "npm-run-all": "^4.1.5",
105 | "prismjs": "^1.15.0",
106 | "typescript": "^3.2.2",
107 | "unminified-webpack-plugin": "^1.4.2",
108 | "watch": "^1.0.1",
109 | "webpack": "^3.10.0"
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/test/array-helper.spec.js:
--------------------------------------------------------------------------------
1 | var helper = require('../lib/array-helper');
2 |
3 | /*global describe,it,expect,beforeEach,afterEach*/
4 |
5 | describe('Testing array-helper.js:', function () {
6 |
7 | describe('Helpers:', function () {
8 |
9 | describe('isArray:', function () {
10 |
11 | var nativeIsArray;
12 | beforeEach(function () {
13 | nativeIsArray = Array.isArray;
14 | });
15 |
16 | afterEach(function () {
17 | Array.isArray = nativeIsArray;
18 | });
19 |
20 | it('Returns true for an array', function () {
21 | expect(helper.isArray([])).toBe(true);
22 | expect(helper.isArray(['one', 'two', 'three'])).toBe(true);
23 | });
24 |
25 | it('Returns false for none array values', function () {
26 | expect(helper.isArray({})).toBe(false);
27 | expect(helper.isArray('[]')).toBe(false);
28 | });
29 |
30 | it('Returns false for undefined values', function () {
31 | expect(helper.isArray(undefined)).toBe(false);
32 | expect(helper.isArray(null)).toBe(false);
33 | });
34 |
35 | it('Use fallback when isArray is not defined', function () {
36 | Array.isArray = undefined;
37 |
38 | expect(helper.isArray(['one', 'two', 'three'])).toBe(true);
39 | expect(helper.isArray({})).toBe(false);
40 | });
41 |
42 | });
43 |
44 | });
45 |
46 | });
47 |
--------------------------------------------------------------------------------
/test/browse-jasmine/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Jasmine Spec Runner v2.6.1
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/test/browse-jasmine/jasmine-standalone-2.6.1.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nashwaan/xml-js/f0376f265c4f299100fb4766828ebf066a0edeec/test/browse-jasmine/jasmine-standalone-2.6.1.zip
--------------------------------------------------------------------------------
/test/browse-jasmine/lib/jasmine-2.6.1/boot.js:
--------------------------------------------------------------------------------
1 | /**
2 | Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
3 |
4 | If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
5 |
6 | The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
7 |
8 | [jasmine-gem]: http://github.com/pivotal/jasmine-gem
9 | */
10 |
11 | (function() {
12 |
13 | /**
14 | * ## Require & Instantiate
15 | *
16 | * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
17 | */
18 | window.jasmine = jasmineRequire.core(jasmineRequire);
19 |
20 | /**
21 | * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
22 | */
23 | jasmineRequire.html(jasmine);
24 |
25 | /**
26 | * Create the Jasmine environment. This is used to run all specs in a project.
27 | */
28 | var env = jasmine.getEnv();
29 |
30 | /**
31 | * ## The Global Interface
32 | *
33 | * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
34 | */
35 | var jasmineInterface = jasmineRequire.interface(jasmine, env);
36 |
37 | /**
38 | * Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
39 | */
40 | extend(window, jasmineInterface);
41 |
42 | /**
43 | * ## Runner Parameters
44 | *
45 | * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
46 | */
47 |
48 | var queryString = new jasmine.QueryString({
49 | getWindowLocation: function() { return window.location; }
50 | });
51 |
52 | var filterSpecs = !!queryString.getParam("spec");
53 |
54 | var catchingExceptions = queryString.getParam("catch");
55 | env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
56 |
57 | var throwingExpectationFailures = queryString.getParam("throwFailures");
58 | env.throwOnExpectationFailure(throwingExpectationFailures);
59 |
60 | var random = queryString.getParam("random");
61 | env.randomizeTests(random);
62 |
63 | var seed = queryString.getParam("seed");
64 | if (seed) {
65 | env.seed(seed);
66 | }
67 |
68 | /**
69 | * ## Reporters
70 | * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
71 | */
72 | var htmlReporter = new jasmine.HtmlReporter({
73 | env: env,
74 | onRaiseExceptionsClick: function() { queryString.navigateWithNewParam("catch", !env.catchingExceptions()); },
75 | onThrowExpectationsClick: function() { queryString.navigateWithNewParam("throwFailures", !env.throwingExpectationFailures()); },
76 | onRandomClick: function() { queryString.navigateWithNewParam("random", !env.randomTests()); },
77 | addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },
78 | getContainer: function() { return document.body; },
79 | createElement: function() { return document.createElement.apply(document, arguments); },
80 | createTextNode: function() { return document.createTextNode.apply(document, arguments); },
81 | timer: new jasmine.Timer(),
82 | filterSpecs: filterSpecs
83 | });
84 |
85 | /**
86 | * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
87 | */
88 | env.addReporter(jasmineInterface.jsApiReporter);
89 | env.addReporter(htmlReporter);
90 |
91 | /**
92 | * Filter which specs will be run by matching the start of the full name against the `spec` query param.
93 | */
94 | var specFilter = new jasmine.HtmlSpecFilter({
95 | filterString: function() { return queryString.getParam("spec"); }
96 | });
97 |
98 | env.specFilter = function(spec) {
99 | return specFilter.matches(spec.getFullName());
100 | };
101 |
102 | /**
103 | * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
104 | */
105 | window.setTimeout = window.setTimeout;
106 | window.setInterval = window.setInterval;
107 | window.clearTimeout = window.clearTimeout;
108 | window.clearInterval = window.clearInterval;
109 |
110 | /**
111 | * ## Execution
112 | *
113 | * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
114 | */
115 | var currentWindowOnload = window.onload;
116 |
117 | window.onload = function() {
118 | if (currentWindowOnload) {
119 | currentWindowOnload();
120 | }
121 | htmlReporter.initialize();
122 | env.execute();
123 | };
124 |
125 | /**
126 | * Helper function for readability above.
127 | */
128 | function extend(destination, source) {
129 | for (var property in source) destination[property] = source[property];
130 | return destination;
131 | }
132 |
133 | }());
134 |
--------------------------------------------------------------------------------
/test/browse-jasmine/lib/jasmine-2.6.1/console.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008-2017 Pivotal Labs
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining
5 | a copy of this software and associated documentation files (the
6 | "Software"), to deal in the Software without restriction, including
7 | without limitation the rights to use, copy, modify, merge, publish,
8 | distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so, subject to
10 | the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 | function getJasmineRequireObj() {
24 | if (typeof module !== 'undefined' && module.exports) {
25 | return exports;
26 | } else {
27 | window.jasmineRequire = window.jasmineRequire || {};
28 | return window.jasmineRequire;
29 | }
30 | }
31 |
32 | getJasmineRequireObj().console = function(jRequire, j$) {
33 | j$.ConsoleReporter = jRequire.ConsoleReporter();
34 | };
35 |
36 | getJasmineRequireObj().ConsoleReporter = function() {
37 |
38 | var noopTimer = {
39 | start: function(){},
40 | elapsed: function(){ return 0; }
41 | };
42 |
43 | function ConsoleReporter(options) {
44 | var print = options.print,
45 | showColors = options.showColors || false,
46 | onComplete = options.onComplete || function() {},
47 | timer = options.timer || noopTimer,
48 | specCount,
49 | failureCount,
50 | failedSpecs = [],
51 | pendingCount,
52 | ansi = {
53 | green: '\x1B[32m',
54 | red: '\x1B[31m',
55 | yellow: '\x1B[33m',
56 | none: '\x1B[0m'
57 | },
58 | failedSuites = [];
59 |
60 | print('ConsoleReporter is deprecated and will be removed in a future version.');
61 |
62 | this.jasmineStarted = function() {
63 | specCount = 0;
64 | failureCount = 0;
65 | pendingCount = 0;
66 | print('Started');
67 | printNewline();
68 | timer.start();
69 | };
70 |
71 | this.jasmineDone = function() {
72 | printNewline();
73 | for (var i = 0; i < failedSpecs.length; i++) {
74 | specFailureDetails(failedSpecs[i]);
75 | }
76 |
77 | if(specCount > 0) {
78 | printNewline();
79 |
80 | var specCounts = specCount + ' ' + plural('spec', specCount) + ', ' +
81 | failureCount + ' ' + plural('failure', failureCount);
82 |
83 | if (pendingCount) {
84 | specCounts += ', ' + pendingCount + ' pending ' + plural('spec', pendingCount);
85 | }
86 |
87 | print(specCounts);
88 | } else {
89 | print('No specs found');
90 | }
91 |
92 | printNewline();
93 | var seconds = timer.elapsed() / 1000;
94 | print('Finished in ' + seconds + ' ' + plural('second', seconds));
95 | printNewline();
96 |
97 | for(i = 0; i < failedSuites.length; i++) {
98 | suiteFailureDetails(failedSuites[i]);
99 | }
100 |
101 | onComplete(failureCount === 0);
102 | };
103 |
104 | this.specDone = function(result) {
105 | specCount++;
106 |
107 | if (result.status == 'pending') {
108 | pendingCount++;
109 | print(colored('yellow', '*'));
110 | return;
111 | }
112 |
113 | if (result.status == 'passed') {
114 | print(colored('green', '.'));
115 | return;
116 | }
117 |
118 | if (result.status == 'failed') {
119 | failureCount++;
120 | failedSpecs.push(result);
121 | print(colored('red', 'F'));
122 | }
123 | };
124 |
125 | this.suiteDone = function(result) {
126 | if (result.failedExpectations && result.failedExpectations.length > 0) {
127 | failureCount++;
128 | failedSuites.push(result);
129 | }
130 | };
131 |
132 | return this;
133 |
134 | function printNewline() {
135 | print('\n');
136 | }
137 |
138 | function colored(color, str) {
139 | return showColors ? (ansi[color] + str + ansi.none) : str;
140 | }
141 |
142 | function plural(str, count) {
143 | return count == 1 ? str : str + 's';
144 | }
145 |
146 | function repeat(thing, times) {
147 | var arr = [];
148 | for (var i = 0; i < times; i++) {
149 | arr.push(thing);
150 | }
151 | return arr;
152 | }
153 |
154 | function indent(str, spaces) {
155 | var lines = (str || '').split('\n');
156 | var newArr = [];
157 | for (var i = 0; i < lines.length; i++) {
158 | newArr.push(repeat(' ', spaces).join('') + lines[i]);
159 | }
160 | return newArr.join('\n');
161 | }
162 |
163 | function specFailureDetails(result) {
164 | printNewline();
165 | print(result.fullName);
166 |
167 | for (var i = 0; i < result.failedExpectations.length; i++) {
168 | var failedExpectation = result.failedExpectations[i];
169 | printNewline();
170 | print(indent(failedExpectation.message, 2));
171 | print(indent(failedExpectation.stack, 2));
172 | }
173 |
174 | printNewline();
175 | }
176 |
177 | function suiteFailureDetails(result) {
178 | for (var i = 0; i < result.failedExpectations.length; i++) {
179 | printNewline();
180 | print(colored('red', 'An error was thrown in an afterAll'));
181 | printNewline();
182 | print(colored('red', 'AfterAll ' + result.failedExpectations[i].message));
183 |
184 | }
185 | printNewline();
186 | }
187 | }
188 |
189 | return ConsoleReporter;
190 | };
191 |
--------------------------------------------------------------------------------
/test/browse-jasmine/lib/jasmine-2.6.1/jasmine_favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nashwaan/xml-js/f0376f265c4f299100fb4766828ebf066a0edeec/test/browse-jasmine/lib/jasmine-2.6.1/jasmine_favicon.png
--------------------------------------------------------------------------------
/test/cli-helper.spec.js:
--------------------------------------------------------------------------------
1 | var helper = require('../bin/cli-helper');
2 |
3 | /*global describe,it,expect*/
4 |
5 | describe('Testing cli.js:', function () {
6 |
7 | describe('Getting help and parse arguments:', function () {
8 |
9 | describe('Command line help:', function () {
10 |
11 | it('Return help content', function () {
12 | var requiredArgs = [{arg: 'src', type: 'any', option: 'src', desc: 'Input file that need to be converted.'}];
13 | var possibleArgs = [{arg: 'help', alias: 'h', type: 'flag', option: 'help', desc: 'Display help content.'}];
14 | var help =
15 | 'Usage: foo [options]\n' +
16 | ' Input file that need to be converted.\n' +
17 | '\nOptions:\n' +
18 | ' --help Display help content.\n';
19 | expect(helper.getCommandLineHelp('foo', requiredArgs, possibleArgs)).toEqual(help);
20 | });
21 |
22 | });
23 |
24 | describe('Map command line argument:', function () {
25 |
26 | if (typeof jasmineRequire === 'undefined') {
27 |
28 | it('Flag argument, alias', function () {
29 | var possibleArgs = [{arg: 'version', alias: 'v', type: 'flag', option: 'version', desc: 'Display version.'}];
30 | process.argv.push('-v');
31 | expect(helper.mapCommandLineArgs({}, possibleArgs)).toEqual({version: true});
32 | process.argv.pop();
33 | });
34 |
35 | it('Number argument, long form', function () {
36 | var possibleArgs = [{arg: 'spaces', type: 'number', option: 'spaces', desc: 'Specify spaces.'}];
37 | process.argv.push('--spaces'); process.argv.push('5');
38 | expect(helper.mapCommandLineArgs({}, possibleArgs)).toEqual({spaces: 5});
39 | process.argv.pop(); process.argv.pop();
40 | });
41 |
42 | it('String argument, long form', function () {
43 | var possibleArgs = [{arg: 'name', type: 'string', option: 'name', desc: 'Specify name.'}];
44 | process.argv.push('--name'); process.argv.push('Foo');
45 | expect(helper.mapCommandLineArgs({}, possibleArgs)).toEqual({name: 'Foo'});
46 | process.argv.pop(); process.argv.pop();
47 | });
48 |
49 | it('File argument, long form', function () {
50 | var possibleArgs = [{arg: 'input', type: 'file', option: 'input', desc: 'Specify file.'}];
51 | process.argv.push('--input'); process.argv.push('test.txt');
52 | expect(helper.mapCommandLineArgs({}, possibleArgs)).toEqual({input: 'test.txt'});
53 | process.argv.pop(); process.argv.pop();
54 | });
55 |
56 | it('Argument not proceeded with dash', function () {
57 | var possibleArgs = [{arg: 'version', alias: 'v', type: 'flag', option: 'version', desc: 'Display version.'}];
58 | process.argv.push('v');
59 | expect(helper.mapCommandLineArgs({}, possibleArgs)).not.toEqual({version: true});
60 | process.argv.pop();
61 | });
62 |
63 | it('Incomplete compound argument, long form', function () {
64 | var possibleArgs = [{arg: 'input', type: 'file', option: 'input', desc: 'Specify file.'}];
65 | process.argv.push('--input');
66 | expect(helper.mapCommandLineArgs({}, possibleArgs)).toEqual({});
67 | process.argv.pop();
68 | });
69 |
70 | }
71 |
72 | });
73 |
74 | });
75 |
76 | });
77 |
--------------------------------------------------------------------------------
/test/cli.spec.js:
--------------------------------------------------------------------------------
1 | if (typeof jasmineRequire === 'undefined') {
2 |
3 | var path = require('path');
4 | var exec = require('child_process').exec;
5 | var packageInfo = require('../package.json');
6 |
7 | var command = 'node ' + path.join(__dirname, '../bin/cli');
8 |
9 | /*exec('node ./bin/cli.js --version', function (error, stdout, stderr) {
10 | console.log(stdout, stderr);
11 | });*/
12 | //console.log(exec('node ./bin/cli.js --version'), {encoding: 'utf8'});
13 |
14 | /*global describe,it,expect*/
15 |
16 | describe('Testing cli.js:', function () {
17 |
18 | describe('Getting version and help on usage:', function () {
19 |
20 | it('Get version --version', function (done) {
21 | exec(command + ' --version', function (error, stdout, stderr) {
22 | expect(stdout).toEqual(packageInfo.version + '\n');
23 | done();
24 | });
25 | });
26 |
27 | it('Get version -v', function (done) {
28 | exec(command + ' -v', function (error, stdout, stderr) {
29 | expect(stdout).toEqual(packageInfo.version + '\n');
30 | done();
31 | });
32 | });
33 |
34 | it('Get help --help', function (done) {
35 | exec(command + ' --help', function (error, stdout, stderr) {
36 | expect(stdout.substr(0, 13)).toEqual('Usage: xml-js');
37 | done();
38 | });
39 | });
40 |
41 | it('Get help -h', function (done) {
42 | exec(command + ' -h', function (error, stdout, stderr) {
43 | expect(stdout.substr(0, 13)).toEqual('Usage: xml-js');
44 | done();
45 | });
46 | });
47 |
48 | it('Get help when no arguments supplied', function (done) {
49 | exec(command, function (error, stdout, stderr) {
50 | expect(stdout.substr(0, 13)).toEqual('Usage: xml-js');
51 | done();
52 | });
53 | });
54 |
55 | });
56 |
57 | describe('Convert XML:', function () {
58 |
59 | it('should convert xml file', function (done) {
60 | exec(command + ' ' + path.join(__dirname, '../bin/test.xml'), function (error, stdout, stderr) {
61 | expect(stdout).toEqual('{"elements":[{"type":"element","name":"a","attributes":{"x":"1"},"elements":[{"type":"element","name":"b","elements":[{"type":"text","text":"bye!"}]}]}]}' + '\n');
62 | done();
63 | });
64 | });
65 |
66 | it('should convert xml file, --compact', function (done) {
67 | exec(command + ' ' + path.join(__dirname, '../bin/test.xml') + ' --compact', function (error, stdout, stderr) {
68 | expect(stdout).toEqual('{"a":{"_attributes":{"x":"1"},"b":{"_text":"bye!"}}}' + '\n');
69 | done();
70 | });
71 | });
72 |
73 | });
74 |
75 | });
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/test/convert-fixtures.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var convertor = require('..');
3 |
4 | function getFixtureFiles(type) {
5 | return fs.readdirSync('fixtures/')
6 | .filter(function (file) {
7 | return file.slice(-4) === type;})
8 | .map(function (file) {
9 | return 'fixtures/' + file;})
10 | .filter(function (file) {
11 | return fs.statSync(file).isFile();});
12 | }
13 |
14 | getFixtureFiles('.xml').map(function (file) {
15 | console.log('converting %s to %s', file, file.replace('.xml','1.json'));
16 | var options = {compact: true, spaces: 4};
17 | fs.writeFileSync(file.replace('.xml','1.json'), convertor.xml2json(fs.readFileSync(file, 'utf8'), options), 'utf8');
18 | });
19 |
20 | getFixtureFiles('.xml').map(function (file) {
21 | console.log('converting %s to %s', file, file.replace('.xml','2.json'));
22 | var options = {compact: false, spaces: 4};
23 | fs.writeFileSync(file.replace('.xml','2.json'), convertor.xml2json(fs.readFileSync(file, 'utf8'), options), 'utf8');
24 | });
25 |
--------------------------------------------------------------------------------
/test/coverage-jest/base.css:
--------------------------------------------------------------------------------
1 | body, html {
2 | margin:0; padding: 0;
3 | height: 100%;
4 | }
5 | body {
6 | font-family: Helvetica Neue, Helvetica, Arial;
7 | font-size: 14px;
8 | color:#333;
9 | }
10 | .small { font-size: 12px; }
11 | *, *:after, *:before {
12 | -webkit-box-sizing:border-box;
13 | -moz-box-sizing:border-box;
14 | box-sizing:border-box;
15 | }
16 | h1 { font-size: 20px; margin: 0;}
17 | h2 { font-size: 14px; }
18 | pre {
19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
20 | margin: 0;
21 | padding: 0;
22 | -moz-tab-size: 2;
23 | -o-tab-size: 2;
24 | tab-size: 2;
25 | }
26 | a { color:#0074D9; text-decoration:none; }
27 | a:hover { text-decoration:underline; }
28 | .strong { font-weight: bold; }
29 | .space-top1 { padding: 10px 0 0 0; }
30 | .pad2y { padding: 20px 0; }
31 | .pad1y { padding: 10px 0; }
32 | .pad2x { padding: 0 20px; }
33 | .pad2 { padding: 20px; }
34 | .pad1 { padding: 10px; }
35 | .space-left2 { padding-left:55px; }
36 | .space-right2 { padding-right:20px; }
37 | .center { text-align:center; }
38 | .clearfix { display:block; }
39 | .clearfix:after {
40 | content:'';
41 | display:block;
42 | height:0;
43 | clear:both;
44 | visibility:hidden;
45 | }
46 | .fl { float: left; }
47 | @media only screen and (max-width:640px) {
48 | .col3 { width:100%; max-width:100%; }
49 | .hide-mobile { display:none!important; }
50 | }
51 |
52 | .quiet {
53 | color: #7f7f7f;
54 | color: rgba(0,0,0,0.5);
55 | }
56 | .quiet a { opacity: 0.7; }
57 |
58 | .fraction {
59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
60 | font-size: 10px;
61 | color: #555;
62 | background: #E8E8E8;
63 | padding: 4px 5px;
64 | border-radius: 3px;
65 | vertical-align: middle;
66 | }
67 |
68 | div.path a:link, div.path a:visited { color: #333; }
69 | table.coverage {
70 | border-collapse: collapse;
71 | margin: 10px 0 0 0;
72 | padding: 0;
73 | }
74 |
75 | table.coverage td {
76 | margin: 0;
77 | padding: 0;
78 | vertical-align: top;
79 | }
80 | table.coverage td.line-count {
81 | text-align: right;
82 | padding: 0 5px 0 20px;
83 | }
84 | table.coverage td.line-coverage {
85 | text-align: right;
86 | padding-right: 10px;
87 | min-width:20px;
88 | }
89 |
90 | table.coverage td span.cline-any {
91 | display: inline-block;
92 | padding: 0 5px;
93 | width: 100%;
94 | }
95 | .missing-if-branch {
96 | display: inline-block;
97 | margin-right: 5px;
98 | border-radius: 3px;
99 | position: relative;
100 | padding: 0 4px;
101 | background: #333;
102 | color: yellow;
103 | }
104 |
105 | .skip-if-branch {
106 | display: none;
107 | margin-right: 10px;
108 | position: relative;
109 | padding: 0 4px;
110 | background: #ccc;
111 | color: white;
112 | }
113 | .missing-if-branch .typ, .skip-if-branch .typ {
114 | color: inherit !important;
115 | }
116 | .coverage-summary {
117 | border-collapse: collapse;
118 | width: 100%;
119 | }
120 | .coverage-summary tr { border-bottom: 1px solid #bbb; }
121 | .keyline-all { border: 1px solid #ddd; }
122 | .coverage-summary td, .coverage-summary th { padding: 10px; }
123 | .coverage-summary tbody { border: 1px solid #bbb; }
124 | .coverage-summary td { border-right: 1px solid #bbb; }
125 | .coverage-summary td:last-child { border-right: none; }
126 | .coverage-summary th {
127 | text-align: left;
128 | font-weight: normal;
129 | white-space: nowrap;
130 | }
131 | .coverage-summary th.file { border-right: none !important; }
132 | .coverage-summary th.pct { }
133 | .coverage-summary th.pic,
134 | .coverage-summary th.abs,
135 | .coverage-summary td.pct,
136 | .coverage-summary td.abs { text-align: right; }
137 | .coverage-summary td.file { white-space: nowrap; }
138 | .coverage-summary td.pic { min-width: 120px !important; }
139 | .coverage-summary tfoot td { }
140 |
141 | .coverage-summary .sorter {
142 | height: 10px;
143 | width: 7px;
144 | display: inline-block;
145 | margin-left: 0.5em;
146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
147 | }
148 | .coverage-summary .sorted .sorter {
149 | background-position: 0 -20px;
150 | }
151 | .coverage-summary .sorted-desc .sorter {
152 | background-position: 0 -10px;
153 | }
154 | .status-line { height: 10px; }
155 | /* dark red */
156 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
157 | .low .chart { border:1px solid #C21F39 }
158 | /* medium red */
159 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
160 | /* light red */
161 | .low, .cline-no { background:#FCE1E5 }
162 | /* light green */
163 | .high, .cline-yes { background:rgb(230,245,208) }
164 | /* medium green */
165 | .cstat-yes { background:rgb(161,215,106) }
166 | /* dark green */
167 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) }
168 | .high .chart { border:1px solid rgb(77,146,33) }
169 |
170 |
171 | .medium .chart { border:1px solid #666; }
172 | .medium .cover-fill { background: #666; }
173 |
174 | .cbranch-no { background: yellow !important; color: #111; }
175 |
176 | .cstat-skip { background: #ddd; color: #111; }
177 | .fstat-skip { background: #ddd; color: #111 !important; }
178 | .cbranch-skip { background: #ddd !important; color: #111; }
179 |
180 | span.cline-neutral { background: #eaeaea; }
181 | .medium { background: #eaeaea; }
182 |
183 | .cover-fill, .cover-empty {
184 | display:inline-block;
185 | height: 12px;
186 | }
187 | .chart {
188 | line-height: 0;
189 | }
190 | .cover-empty {
191 | background: white;
192 | }
193 | .cover-full {
194 | border-right: none !important;
195 | }
196 | pre.prettyprint {
197 | border: none !important;
198 | padding: 0 !important;
199 | margin: 0 !important;
200 | }
201 | .com { color: #999 !important; }
202 | .ignore-none { color: #999; font-weight: normal; }
203 |
204 | .wrapper {
205 | min-height: 100%;
206 | height: auto !important;
207 | height: 100%;
208 | margin: 0 auto -48px;
209 | }
210 | .footer, .push {
211 | height: 48px;
212 | }
213 |
--------------------------------------------------------------------------------
/test/coverage-jest/coverage-final.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/test/coverage-jest/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Code coverage report for All files
5 |
6 |
7 |
8 |
9 |
14 |
15 |
16 |
17 |
18 |
19 | All files
20 |
21 |
22 |
23 | Unknown%
24 | Statements
25 | 0/0
26 |
27 |
28 | Unknown%
29 | Branches
30 | 0/0
31 |
32 |
33 | Unknown%
34 | Functions
35 | 0/0
36 |
37 |
38 | Unknown%
39 | Lines
40 | 0/0
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | File |
50 | |
51 | Statements |
52 | |
53 | Branches |
54 | |
55 | Functions |
56 | |
57 | Lines |
58 | |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
69 |
70 |
71 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/test/coverage-jest/lcov-report/base.css:
--------------------------------------------------------------------------------
1 | body, html {
2 | margin:0; padding: 0;
3 | height: 100%;
4 | }
5 | body {
6 | font-family: Helvetica Neue, Helvetica, Arial;
7 | font-size: 14px;
8 | color:#333;
9 | }
10 | .small { font-size: 12px; }
11 | *, *:after, *:before {
12 | -webkit-box-sizing:border-box;
13 | -moz-box-sizing:border-box;
14 | box-sizing:border-box;
15 | }
16 | h1 { font-size: 20px; margin: 0;}
17 | h2 { font-size: 14px; }
18 | pre {
19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
20 | margin: 0;
21 | padding: 0;
22 | -moz-tab-size: 2;
23 | -o-tab-size: 2;
24 | tab-size: 2;
25 | }
26 | a { color:#0074D9; text-decoration:none; }
27 | a:hover { text-decoration:underline; }
28 | .strong { font-weight: bold; }
29 | .space-top1 { padding: 10px 0 0 0; }
30 | .pad2y { padding: 20px 0; }
31 | .pad1y { padding: 10px 0; }
32 | .pad2x { padding: 0 20px; }
33 | .pad2 { padding: 20px; }
34 | .pad1 { padding: 10px; }
35 | .space-left2 { padding-left:55px; }
36 | .space-right2 { padding-right:20px; }
37 | .center { text-align:center; }
38 | .clearfix { display:block; }
39 | .clearfix:after {
40 | content:'';
41 | display:block;
42 | height:0;
43 | clear:both;
44 | visibility:hidden;
45 | }
46 | .fl { float: left; }
47 | @media only screen and (max-width:640px) {
48 | .col3 { width:100%; max-width:100%; }
49 | .hide-mobile { display:none!important; }
50 | }
51 |
52 | .quiet {
53 | color: #7f7f7f;
54 | color: rgba(0,0,0,0.5);
55 | }
56 | .quiet a { opacity: 0.7; }
57 |
58 | .fraction {
59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
60 | font-size: 10px;
61 | color: #555;
62 | background: #E8E8E8;
63 | padding: 4px 5px;
64 | border-radius: 3px;
65 | vertical-align: middle;
66 | }
67 |
68 | div.path a:link, div.path a:visited { color: #333; }
69 | table.coverage {
70 | border-collapse: collapse;
71 | margin: 10px 0 0 0;
72 | padding: 0;
73 | }
74 |
75 | table.coverage td {
76 | margin: 0;
77 | padding: 0;
78 | vertical-align: top;
79 | }
80 | table.coverage td.line-count {
81 | text-align: right;
82 | padding: 0 5px 0 20px;
83 | }
84 | table.coverage td.line-coverage {
85 | text-align: right;
86 | padding-right: 10px;
87 | min-width:20px;
88 | }
89 |
90 | table.coverage td span.cline-any {
91 | display: inline-block;
92 | padding: 0 5px;
93 | width: 100%;
94 | }
95 | .missing-if-branch {
96 | display: inline-block;
97 | margin-right: 5px;
98 | border-radius: 3px;
99 | position: relative;
100 | padding: 0 4px;
101 | background: #333;
102 | color: yellow;
103 | }
104 |
105 | .skip-if-branch {
106 | display: none;
107 | margin-right: 10px;
108 | position: relative;
109 | padding: 0 4px;
110 | background: #ccc;
111 | color: white;
112 | }
113 | .missing-if-branch .typ, .skip-if-branch .typ {
114 | color: inherit !important;
115 | }
116 | .coverage-summary {
117 | border-collapse: collapse;
118 | width: 100%;
119 | }
120 | .coverage-summary tr { border-bottom: 1px solid #bbb; }
121 | .keyline-all { border: 1px solid #ddd; }
122 | .coverage-summary td, .coverage-summary th { padding: 10px; }
123 | .coverage-summary tbody { border: 1px solid #bbb; }
124 | .coverage-summary td { border-right: 1px solid #bbb; }
125 | .coverage-summary td:last-child { border-right: none; }
126 | .coverage-summary th {
127 | text-align: left;
128 | font-weight: normal;
129 | white-space: nowrap;
130 | }
131 | .coverage-summary th.file { border-right: none !important; }
132 | .coverage-summary th.pct { }
133 | .coverage-summary th.pic,
134 | .coverage-summary th.abs,
135 | .coverage-summary td.pct,
136 | .coverage-summary td.abs { text-align: right; }
137 | .coverage-summary td.file { white-space: nowrap; }
138 | .coverage-summary td.pic { min-width: 120px !important; }
139 | .coverage-summary tfoot td { }
140 |
141 | .coverage-summary .sorter {
142 | height: 10px;
143 | width: 7px;
144 | display: inline-block;
145 | margin-left: 0.5em;
146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
147 | }
148 | .coverage-summary .sorted .sorter {
149 | background-position: 0 -20px;
150 | }
151 | .coverage-summary .sorted-desc .sorter {
152 | background-position: 0 -10px;
153 | }
154 | .status-line { height: 10px; }
155 | /* dark red */
156 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
157 | .low .chart { border:1px solid #C21F39 }
158 | /* medium red */
159 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
160 | /* light red */
161 | .low, .cline-no { background:#FCE1E5 }
162 | /* light green */
163 | .high, .cline-yes { background:rgb(230,245,208) }
164 | /* medium green */
165 | .cstat-yes { background:rgb(161,215,106) }
166 | /* dark green */
167 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) }
168 | .high .chart { border:1px solid rgb(77,146,33) }
169 |
170 |
171 | .medium .chart { border:1px solid #666; }
172 | .medium .cover-fill { background: #666; }
173 |
174 | .cbranch-no { background: yellow !important; color: #111; }
175 |
176 | .cstat-skip { background: #ddd; color: #111; }
177 | .fstat-skip { background: #ddd; color: #111 !important; }
178 | .cbranch-skip { background: #ddd !important; color: #111; }
179 |
180 | span.cline-neutral { background: #eaeaea; }
181 | .medium { background: #eaeaea; }
182 |
183 | .cover-fill, .cover-empty {
184 | display:inline-block;
185 | height: 12px;
186 | }
187 | .chart {
188 | line-height: 0;
189 | }
190 | .cover-empty {
191 | background: white;
192 | }
193 | .cover-full {
194 | border-right: none !important;
195 | }
196 | pre.prettyprint {
197 | border: none !important;
198 | padding: 0 !important;
199 | margin: 0 !important;
200 | }
201 | .com { color: #999 !important; }
202 | .ignore-none { color: #999; font-weight: normal; }
203 |
204 | .wrapper {
205 | min-height: 100%;
206 | height: auto !important;
207 | height: 100%;
208 | margin: 0 auto -48px;
209 | }
210 | .footer, .push {
211 | height: 48px;
212 | }
213 |
--------------------------------------------------------------------------------
/test/coverage-jest/lcov-report/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Code coverage report for All files
5 |
6 |
7 |
8 |
9 |
14 |
15 |
16 |
17 |
18 |
19 | All files
20 |
21 |
22 |
23 | Unknown%
24 | Statements
25 | 0/0
26 |
27 |
28 | Unknown%
29 | Branches
30 | 0/0
31 |
32 |
33 | Unknown%
34 | Functions
35 | 0/0
36 |
37 |
38 | Unknown%
39 | Lines
40 | 0/0
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | File |
50 | |
51 | Statements |
52 | |
53 | Branches |
54 | |
55 | Functions |
56 | |
57 | Lines |
58 | |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
69 |
70 |
71 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/test/coverage-jest/lcov-report/prettify.css:
--------------------------------------------------------------------------------
1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
2 |
--------------------------------------------------------------------------------
/test/coverage-jest/lcov-report/sort-arrow-sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nashwaan/xml-js/f0376f265c4f299100fb4766828ebf066a0edeec/test/coverage-jest/lcov-report/sort-arrow-sprite.png
--------------------------------------------------------------------------------
/test/coverage-jest/lcov-report/sorter.js:
--------------------------------------------------------------------------------
1 | var addSorting = (function () {
2 | "use strict";
3 | var cols,
4 | currentSort = {
5 | index: 0,
6 | desc: false
7 | };
8 |
9 | // returns the summary table element
10 | function getTable() { return document.querySelector('.coverage-summary'); }
11 | // returns the thead element of the summary table
12 | function getTableHeader() { return getTable().querySelector('thead tr'); }
13 | // returns the tbody element of the summary table
14 | function getTableBody() { return getTable().querySelector('tbody'); }
15 | // returns the th element for nth column
16 | function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; }
17 |
18 | // loads all columns
19 | function loadColumns() {
20 | var colNodes = getTableHeader().querySelectorAll('th'),
21 | colNode,
22 | cols = [],
23 | col,
24 | i;
25 |
26 | for (i = 0; i < colNodes.length; i += 1) {
27 | colNode = colNodes[i];
28 | col = {
29 | key: colNode.getAttribute('data-col'),
30 | sortable: !colNode.getAttribute('data-nosort'),
31 | type: colNode.getAttribute('data-type') || 'string'
32 | };
33 | cols.push(col);
34 | if (col.sortable) {
35 | col.defaultDescSort = col.type === 'number';
36 | colNode.innerHTML = colNode.innerHTML + '';
37 | }
38 | }
39 | return cols;
40 | }
41 | // attaches a data attribute to every tr element with an object
42 | // of data values keyed by column name
43 | function loadRowData(tableRow) {
44 | var tableCols = tableRow.querySelectorAll('td'),
45 | colNode,
46 | col,
47 | data = {},
48 | i,
49 | val;
50 | for (i = 0; i < tableCols.length; i += 1) {
51 | colNode = tableCols[i];
52 | col = cols[i];
53 | val = colNode.getAttribute('data-value');
54 | if (col.type === 'number') {
55 | val = Number(val);
56 | }
57 | data[col.key] = val;
58 | }
59 | return data;
60 | }
61 | // loads all row data
62 | function loadData() {
63 | var rows = getTableBody().querySelectorAll('tr'),
64 | i;
65 |
66 | for (i = 0; i < rows.length; i += 1) {
67 | rows[i].data = loadRowData(rows[i]);
68 | }
69 | }
70 | // sorts the table using the data for the ith column
71 | function sortByIndex(index, desc) {
72 | var key = cols[index].key,
73 | sorter = function (a, b) {
74 | a = a.data[key];
75 | b = b.data[key];
76 | return a < b ? -1 : a > b ? 1 : 0;
77 | },
78 | finalSorter = sorter,
79 | tableBody = document.querySelector('.coverage-summary tbody'),
80 | rowNodes = tableBody.querySelectorAll('tr'),
81 | rows = [],
82 | i;
83 |
84 | if (desc) {
85 | finalSorter = function (a, b) {
86 | return -1 * sorter(a, b);
87 | };
88 | }
89 |
90 | for (i = 0; i < rowNodes.length; i += 1) {
91 | rows.push(rowNodes[i]);
92 | tableBody.removeChild(rowNodes[i]);
93 | }
94 |
95 | rows.sort(finalSorter);
96 |
97 | for (i = 0; i < rows.length; i += 1) {
98 | tableBody.appendChild(rows[i]);
99 | }
100 | }
101 | // removes sort indicators for current column being sorted
102 | function removeSortIndicators() {
103 | var col = getNthColumn(currentSort.index),
104 | cls = col.className;
105 |
106 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
107 | col.className = cls;
108 | }
109 | // adds sort indicators for current column being sorted
110 | function addSortIndicators() {
111 | getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted';
112 | }
113 | // adds event listeners for all sorter widgets
114 | function enableUI() {
115 | var i,
116 | el,
117 | ithSorter = function ithSorter(i) {
118 | var col = cols[i];
119 |
120 | return function () {
121 | var desc = col.defaultDescSort;
122 |
123 | if (currentSort.index === i) {
124 | desc = !currentSort.desc;
125 | }
126 | sortByIndex(i, desc);
127 | removeSortIndicators();
128 | currentSort.index = i;
129 | currentSort.desc = desc;
130 | addSortIndicators();
131 | };
132 | };
133 | for (i =0 ; i < cols.length; i += 1) {
134 | if (cols[i].sortable) {
135 | // add the click event handler on the th so users
136 | // dont have to click on those tiny arrows
137 | el = getNthColumn(i).querySelector('.sorter').parentElement;
138 | if (el.addEventListener) {
139 | el.addEventListener('click', ithSorter(i));
140 | } else {
141 | el.attachEvent('onclick', ithSorter(i));
142 | }
143 | }
144 | }
145 | }
146 | // adds sorting functionality to the UI
147 | return function () {
148 | if (!getTable()) {
149 | return;
150 | }
151 | cols = loadColumns();
152 | loadData(cols);
153 | addSortIndicators();
154 | enableUI();
155 | };
156 | })();
157 |
158 | window.addEventListener('load', addSorting);
159 |
--------------------------------------------------------------------------------
/test/coverage-jest/lcov.info:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nashwaan/xml-js/f0376f265c4f299100fb4766828ebf066a0edeec/test/coverage-jest/lcov.info
--------------------------------------------------------------------------------
/test/coverage-jest/prettify.css:
--------------------------------------------------------------------------------
1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
2 |
--------------------------------------------------------------------------------
/test/coverage-jest/sort-arrow-sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nashwaan/xml-js/f0376f265c4f299100fb4766828ebf066a0edeec/test/coverage-jest/sort-arrow-sprite.png
--------------------------------------------------------------------------------
/test/coverage-jest/sorter.js:
--------------------------------------------------------------------------------
1 | var addSorting = (function () {
2 | "use strict";
3 | var cols,
4 | currentSort = {
5 | index: 0,
6 | desc: false
7 | };
8 |
9 | // returns the summary table element
10 | function getTable() { return document.querySelector('.coverage-summary'); }
11 | // returns the thead element of the summary table
12 | function getTableHeader() { return getTable().querySelector('thead tr'); }
13 | // returns the tbody element of the summary table
14 | function getTableBody() { return getTable().querySelector('tbody'); }
15 | // returns the th element for nth column
16 | function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; }
17 |
18 | // loads all columns
19 | function loadColumns() {
20 | var colNodes = getTableHeader().querySelectorAll('th'),
21 | colNode,
22 | cols = [],
23 | col,
24 | i;
25 |
26 | for (i = 0; i < colNodes.length; i += 1) {
27 | colNode = colNodes[i];
28 | col = {
29 | key: colNode.getAttribute('data-col'),
30 | sortable: !colNode.getAttribute('data-nosort'),
31 | type: colNode.getAttribute('data-type') || 'string'
32 | };
33 | cols.push(col);
34 | if (col.sortable) {
35 | col.defaultDescSort = col.type === 'number';
36 | colNode.innerHTML = colNode.innerHTML + '';
37 | }
38 | }
39 | return cols;
40 | }
41 | // attaches a data attribute to every tr element with an object
42 | // of data values keyed by column name
43 | function loadRowData(tableRow) {
44 | var tableCols = tableRow.querySelectorAll('td'),
45 | colNode,
46 | col,
47 | data = {},
48 | i,
49 | val;
50 | for (i = 0; i < tableCols.length; i += 1) {
51 | colNode = tableCols[i];
52 | col = cols[i];
53 | val = colNode.getAttribute('data-value');
54 | if (col.type === 'number') {
55 | val = Number(val);
56 | }
57 | data[col.key] = val;
58 | }
59 | return data;
60 | }
61 | // loads all row data
62 | function loadData() {
63 | var rows = getTableBody().querySelectorAll('tr'),
64 | i;
65 |
66 | for (i = 0; i < rows.length; i += 1) {
67 | rows[i].data = loadRowData(rows[i]);
68 | }
69 | }
70 | // sorts the table using the data for the ith column
71 | function sortByIndex(index, desc) {
72 | var key = cols[index].key,
73 | sorter = function (a, b) {
74 | a = a.data[key];
75 | b = b.data[key];
76 | return a < b ? -1 : a > b ? 1 : 0;
77 | },
78 | finalSorter = sorter,
79 | tableBody = document.querySelector('.coverage-summary tbody'),
80 | rowNodes = tableBody.querySelectorAll('tr'),
81 | rows = [],
82 | i;
83 |
84 | if (desc) {
85 | finalSorter = function (a, b) {
86 | return -1 * sorter(a, b);
87 | };
88 | }
89 |
90 | for (i = 0; i < rowNodes.length; i += 1) {
91 | rows.push(rowNodes[i]);
92 | tableBody.removeChild(rowNodes[i]);
93 | }
94 |
95 | rows.sort(finalSorter);
96 |
97 | for (i = 0; i < rows.length; i += 1) {
98 | tableBody.appendChild(rows[i]);
99 | }
100 | }
101 | // removes sort indicators for current column being sorted
102 | function removeSortIndicators() {
103 | var col = getNthColumn(currentSort.index),
104 | cls = col.className;
105 |
106 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
107 | col.className = cls;
108 | }
109 | // adds sort indicators for current column being sorted
110 | function addSortIndicators() {
111 | getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted';
112 | }
113 | // adds event listeners for all sorter widgets
114 | function enableUI() {
115 | var i,
116 | el,
117 | ithSorter = function ithSorter(i) {
118 | var col = cols[i];
119 |
120 | return function () {
121 | var desc = col.defaultDescSort;
122 |
123 | if (currentSort.index === i) {
124 | desc = !currentSort.desc;
125 | }
126 | sortByIndex(i, desc);
127 | removeSortIndicators();
128 | currentSort.index = i;
129 | currentSort.desc = desc;
130 | addSortIndicators();
131 | };
132 | };
133 | for (i =0 ; i < cols.length; i += 1) {
134 | if (cols[i].sortable) {
135 | // add the click event handler on the th so users
136 | // dont have to click on those tiny arrows
137 | el = getNthColumn(i).querySelector('.sorter').parentElement;
138 | if (el.addEventListener) {
139 | el.addEventListener('click', ithSorter(i));
140 | } else {
141 | el.attachEvent('onclick', ithSorter(i));
142 | }
143 | }
144 | }
145 | }
146 | // adds sorting functionality to the UI
147 | return function () {
148 | if (!getTable()) {
149 | return;
150 | }
151 | cols = loadColumns();
152 | loadData(cols);
153 | addSortIndicators();
154 | enableUI();
155 | };
156 | })();
157 |
158 | window.addEventListener('load', addSorting);
159 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var jasmine = new (require('jasmine'))();
3 | var config = require(__dirname + '/jasmine.json');
4 |
5 | if ('spec_dir' in config) {
6 | config.spec_dir = path.join(path.relative(process.cwd(), __dirname), '..', config.spec_dir);
7 | }
8 |
9 | jasmine.loadConfig(config);
10 |
11 | jasmine.onComplete(function (passed) {
12 | if (passed) {
13 | console.log('All specs have passed');
14 | } else {
15 | console.log('At least one spec has failed');
16 | }
17 | });
18 |
19 | jasmine.execute();
20 |
--------------------------------------------------------------------------------
/test/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": "./test",
3 | "spec_files": [
4 | "./**/*.[Ss]pec.js"
5 | ],
6 | "helpers": [
7 | ],
8 | "stopSpecOnExpectationFailure": false,
9 | "random": false
10 | }
11 |
--------------------------------------------------------------------------------
/test/jest.conf.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 |
5 | rootDir: path.dirname(__dirname),
6 |
7 | modulePaths: [
8 | '/lib',
9 | '/node_modules'
10 | ],
11 |
12 | moduleFileExtensions: ['js'],
13 |
14 | // setupFiles: ['/test/pretest-jest.js'], // don't use this, expect.extend() will fail
15 | setupTestFrameworkScriptFile: '/test/pretest-jest.js',
16 |
17 | testEnvironment: 'node',
18 |
19 | testMatch: ['**/*.spec.(ts|js)?(x)'],
20 |
21 | collectCoverage: true,
22 |
23 | collectCoverageFrom: [
24 | 'src-js/**/*.{js,ts}',
25 | '!**/*.spec.{js,ts}',
26 | '!**/node_modules/**',
27 | '!**/test/**'
28 | ],
29 |
30 | coverageDirectory: '/test/coverage-jest',
31 |
32 | coverageReporters: ['json', 'lcov', 'text', 'html']
33 |
34 | };
35 |
--------------------------------------------------------------------------------
/test/js2xml-callbacks.spec.js:
--------------------------------------------------------------------------------
1 | var convert = require('../lib');
2 |
3 | /*global describe,it,expect*/
4 |
5 | var args;
6 |
7 | function manipulate(val) {
8 | args = arguments;
9 | return val.toUpperCase();
10 | }
11 |
12 | function manipulateAttribute(obj) {
13 | args = arguments;
14 | var key, temp;
15 | for (key in obj) {
16 | temp = obj[key];
17 | delete obj[key];
18 | obj[key.toUpperCase()] = temp.toUpperCase();
19 | }
20 | return obj;
21 | }
22 |
23 | function fullTag(name) {
24 | args = arguments;
25 | return name === 'b';
26 | }
27 |
28 | describe('Testing js2xml.js:', function () {
29 |
30 | describe('Adding function callbacks, options = {compact: false}', function () {
31 |
32 | describe('options = {doctypeFn: manipulate}', function () {
33 |
34 | var js = {"elements":[{"type":"doctype","doctype":"note [\n]"}]};
35 | var xml = ']') + '>';
36 | it(']>', function () {
37 | expect(convert.js2xml(js, {compact: false, doctypeFn: manipulate})).toEqual(xml);
38 | });
39 | it('should provide correct arguments', function () {
40 | expect(args).toContain('note [\n]', '_root_', js);
41 | });
42 |
43 | });
44 |
45 | describe('options = {instructionFn: manipulate}', function () {
46 |
47 | var js = {"elements":[{"type":"instruction","name":"go","instruction":"there"}]};
48 | var xml = '';
49 | it('', function () {
50 | expect(convert.js2xml(js, {compact: false, instructionFn: manipulate})).toEqual(xml);
51 | });
52 | it('should provide correct arguments', function () {
53 | expect(args).toContain('there', 'go', '_root_', js);
54 | });
55 |
56 | });
57 |
58 | describe('options = {cdataFn: manipulate}', function () {
59 |
60 | var js = {"elements":[{"type":"cdata","cdata":" \t \t "}]};
61 | var xml = ' \t ') + ']]>';
62 | it(' \t ]]>', function () {
63 | expect(convert.js2xml(js, {compact: false, cdataFn: manipulate})).toEqual(xml);
64 | });
65 | it('should provide correct arguments', function () {
66 | expect(args).toContain(' \t \t ', '_root_', js);
67 | // console.log(JSON.stringify(args));
68 | });
69 |
70 | });
71 |
72 | describe('options = {commentFn: manipulate}', function () {
73 |
74 | var js = {"elements":[{"type":"comment","comment":" \t Hello, World! \t "}]};
75 | var xml = '';
76 | it('', function () {
77 | expect(convert.js2xml(js, {compact: false, commentFn: manipulate})).toEqual(xml);
78 | });
79 | it('should provide correct arguments', function () {
80 | expect(args).toContain(' \t Hello, World! \t ', '_root_', js);
81 | });
82 |
83 | });
84 |
85 | describe('options = {textFn: manipulate}', function () {
86 |
87 | var js = {"elements":[{"type":"element","name":"a","elements":[{"type":"text","text":" \t Hi \t "}]}]};
88 | var xml = '' + manipulate(' \t Hi \t ') + '';
89 | it(' \t Hi \t ', function () {
90 | expect(convert.js2xml(js, {compact: false, textFn: manipulate})).toEqual(xml);
91 | });
92 | it('should provide correct arguments', function () {
93 | expect(args).toContain(' \t Hi \t ', 'a', js.elements[0]);
94 | });
95 |
96 | });
97 |
98 | describe('options = {instructionNameFn: manipulate}', function () {
99 |
100 | var js = {"elements":[{"type":"instruction","name":"go","instruction":"there"}]};
101 | var xml = '' + manipulate('go') + ' there?>';
102 | it('', function () {
103 | expect(convert.js2xml(js, {compact: false, instructionNameFn: manipulate})).toEqual(xml);
104 | });
105 | it('should provide correct arguments', function () {
106 | expect(args).toContain('go', '_root_', js);
107 | });
108 |
109 | });
110 |
111 | describe('options = {elementNameFn: manipulate}', function () {
112 |
113 | var js = {"elements":[{"type":"element","name":"a","attributes":{"x":"hello"}}]};
114 | var xml = '<' + manipulate('a') + ' x="hello"/>';
115 | it('', function () {
116 | expect(convert.js2xml(js, {compact: false, elementNameFn: manipulate})).toEqual(xml);
117 | });
118 | it('should provide correct arguments', function () {
119 | expect(args).toContain('a', js.elements[0]);
120 | });
121 |
122 | });
123 |
124 | describe('options = {attributeNameFn: manipulate}', function () {
125 |
126 | var js = {"elements":[{"type":"element","name":"a","attributes":{"x":"1.234","y":"It\'s"}}]};
127 | var xml = '';
128 | it('', function () {
129 | expect(convert.js2xml(js, {compact: false, attributeNameFn: manipulate})).toEqual(xml);
130 | });
131 | it('should provide correct arguments', function () {
132 | expect(args).toContain('y', 'It\'s', 'a', js.elements[0]);
133 | });
134 |
135 | });
136 |
137 | describe('options = {attributeValueFn: manipulate}', function () {
138 |
139 | var js = {"elements":[{"type":"element","name":"a","attributes":{"x":"1.234","y":"It\'s"}}]};
140 | var xml = '';
141 | it('', function () {
142 | expect(convert.js2xml(js, {compact: false, attributeValueFn: manipulate})).toEqual(xml);
143 | });
144 | it('should provide correct arguments', function () {
145 | expect(args).toContain('It\'s', 'y', 'a', js.elements[0]);
146 | });
147 |
148 | });
149 |
150 | describe('options = {attributesFn: manipulateAttribute}', function () {
151 |
152 | var js = {"elements":[{"type":"element","name":"a","attributes":{"x":"1.234","y":"It\'s"}}]};
153 | var xml = '';
154 | it('', function () {
155 | expect(convert.js2xml(js, {compact: false, attributesFn: manipulateAttribute})).toEqual(xml);
156 | });
157 | it('should provide correct arguments', function () {
158 | expect(args).toContain({"X":"1.234","Y":"IT\'S"}, 'a', js.elements[0]);
159 | });
160 |
161 | });
162 |
163 | });
164 |
165 | describe('Adding function callbacks, options = {compact: true}', function () {
166 |
167 | describe('options = {doctypeFn: manipulate}', function () {
168 |
169 | var js = {"_doctype":"note [\n]"};
170 | var xml = ']') + '>';
171 | it(']>', function () {
172 | expect(convert.js2xml(js, {compact: true, doctypeFn: manipulate})).toEqual(xml);
173 | });
174 | it('should provide correct arguments', function () {
175 | expect(args).toContain('note [\n]', '_root_', js);
176 | });
177 |
178 | });
179 |
180 | describe('options = {instructionFn: manipulate}', function () {
181 |
182 | var js = {"_instruction":{"go": "there"}};
183 | var xml = '';
184 | it('', function () {
185 | expect(convert.js2xml(js, {compact: true, instructionFn: manipulate})).toEqual(xml);
186 | });
187 | it('should provide correct arguments', function () {
188 | expect(args).toContain('there', 'go', '_root_', js);
189 | });
190 |
191 | });
192 |
193 | describe('options = {cdataFn: manipulate}', function () {
194 |
195 | var js = {"_cdata":" \t \t "};
196 | var xml = ' \t ') + ']]>';
197 | it(' \t ]]>', function () {
198 | expect(convert.js2xml(js, {compact: true, cdataFn: manipulate})).toEqual(xml);
199 | });
200 | it('should provide correct arguments', function () {
201 | expect(args).toContain(' \t \t ', '_root_', js);
202 | });
203 |
204 | });
205 |
206 | describe('options = {commentFn: manipulate}', function () {
207 |
208 | var js = {"_comment":" \t Hello, World! \t "};
209 | var xml = '';
210 | it('', function () {
211 | expect(convert.js2xml(js, {compact: true, commentFn: manipulate})).toEqual(xml);
212 | });
213 | it('should provide correct arguments', function () {
214 | expect(args).toContain(' \t Hello, World! \t ', '_root_', js);
215 | });
216 |
217 | });
218 |
219 | describe('options = {textFn: manipulate}', function () {
220 |
221 | var js = {"a":{"_text":" \t Hi \t "}};
222 | var xml = '' + manipulate(' \t Hi \t ') + '';
223 | it(' \t Hi \t ', function () {
224 | expect(convert.js2xml(js, {compact: true, textFn: manipulate})).toEqual(xml);
225 | });
226 | it('should provide correct arguments', function () {
227 | expect(args).toContain(' \t Hi \t ', 'a', js.a);
228 | });
229 |
230 | });
231 |
232 | describe('options = {instructionNameFn: manipulate}', function () {
233 |
234 | var js = {"_instruction":{"go": "there"}};
235 | var xml = '' + manipulate('go') + ' there?>';
236 | it('', function () {
237 | expect(convert.js2xml(js, {compact: true, instructionNameFn: manipulate})).toEqual(xml);
238 | });
239 | it('should provide correct arguments', function () {
240 | expect(args).toContain('go', 'there', '_root_', js);
241 | });
242 |
243 | });
244 |
245 | describe('options = {elementNameFn: manipulate}', function () {
246 |
247 | var js = {"a":{_attributes:{"x":"hello"}}};
248 | var xml = '<' + manipulate('a') + ' x="hello"/>';
249 | it('', function () {
250 | expect(convert.js2xml(js, {compact: true, elementNameFn: manipulate})).toEqual(xml);
251 | });
252 | it('should provide correct arguments', function () {
253 | expect(args).toContain('a', js.a);
254 | });
255 |
256 | });
257 |
258 | describe('options = {attributeNameFn: manipulate}', function () {
259 |
260 | var js = {"a":{_attributes:{"x":"1.234","y":"It\'s"}}};
261 | var xml = '';
262 | it('', function () {
263 | expect(convert.js2xml(js, {compact: true, attributeNameFn: manipulate})).toEqual(xml);
264 | });
265 | it('should provide correct arguments', function () {
266 | expect(args).toContain('y', 'It\'s', 'a', js.a);
267 | });
268 |
269 | });
270 |
271 | describe('options = {attributeValueFn: manipulate}', function () {
272 |
273 | var js = {"a":{_attributes:{"x":"1.234","y":"It\'s"}}};
274 | var xml = '';
275 | it('', function () {
276 | expect(convert.js2xml(js, {compact: true, attributeValueFn: manipulate})).toEqual(xml);
277 | });
278 | it('should provide correct arguments', function () {
279 | expect(args).toContain('It\'s', 'y', 'a', js.a);
280 | });
281 |
282 | });
283 |
284 | describe('options = {attributesFn: manipulateAttribute}', function () {
285 |
286 | var js = {"a":{_attributes:{"x":"1.234","y":"It\'s"}}};
287 | var xml = '';
288 | it('', function () {
289 | expect(convert.js2xml(js, {compact: true, attributesFn: manipulateAttribute})).toEqual(xml);
290 | });
291 | it('should provide correct arguments', function () {
292 | expect(args).toContain({"X":"1.234","Y":"IT\'S"}, 'a', js.a);
293 | });
294 |
295 | });
296 |
297 | });
298 |
299 | describe('options = {fullTagEmptyElementFn: fullTag}', function () {
300 |
301 | describe('options = {compact: false}', function () {
302 |
303 | var js = {"elements":[{"type":"element","name":"a"},{"type":"element","name":"b"}]};
304 | var xml = '';
305 | it('', function () {
306 | expect(convert.js2xml(js, {compact: false, fullTagEmptyElementFn: fullTag})).toEqual(xml);
307 | });
308 | it('should provide correct arguments', function () {
309 | expect(args).toContain('b', js.elements[1]);
310 | });
311 |
312 | });
313 |
314 | describe('options = {compact: true}', function () {
315 |
316 | var js = {"a":{},"b":{}};
317 | var xml = '';
318 | it('', function () {
319 | expect(convert.js2xml(js, {compact: true, fullTagEmptyElementFn: fullTag})).toEqual(xml);
320 | });
321 | it('should provide correct arguments', function () {
322 | expect(args).toContain('b', js.b);
323 | });
324 |
325 | });
326 |
327 | });
328 |
329 | });
330 |
--------------------------------------------------------------------------------
/test/js2xml-issues.spec.js:
--------------------------------------------------------------------------------
1 | var convert = require('../lib');
2 | var Script = require('vm').Script;
3 |
4 | /*global describe,it,expect*/
5 |
6 | describe('Testing js2xml.js:', function () {
7 |
8 | describe('User reported issues:', function () {
9 |
10 | describe('case by Jan T. Sott', function () {
11 | // see https://github.com/nashwaan/xml-js/issues/2
12 | var js = {
13 | _comment: ' Released under The MIT License ',
14 | snippet: {
15 | content: {
16 | _cdata: 'console.log($1)'
17 | },
18 | tabTrigger: {
19 | _text: 'log'
20 | },
21 | scope: {
22 | _text: 'source.js'
23 | }
24 | }
25 | };
26 | var xml =
27 | '\n' +
28 | '\n' +
29 | '\v\n' +
30 | '\vlog\n' +
31 | '\vsource.js\n' +
32 | '';
33 |
34 | it('should output cdata and text unformatted', function () {
35 | expect(convert.js2xml(js, {compact: true})).toEqual(xml.replace(/\v|\n/g, ''));
36 | });
37 |
38 | it('should output cdata and text formatted', function () {
39 | expect(convert.js2xml(js, {compact: true, spaces: 4})).toEqual(xml.replace(/\v/g, ' '));
40 | });
41 |
42 | });
43 |
44 | describe('case 1 by Denis Carriere ', function () {
45 | // see https://github.com/nashwaan/xml-js/issues/5
46 | var js1 = {
47 | a: {
48 | b: {
49 | _text: 'foo bar'
50 | }
51 | }
52 | };
53 | var js2 = {
54 | elements: [{
55 | type: 'element',
56 | name: 'a',
57 | elements: [{
58 | type: 'element',
59 | name: 'b',
60 | elements: [{
61 | type: 'text',
62 | text: 'foo bar'
63 | }]
64 | }]
65 | }]
66 | };
67 | var xml = '\n' +
68 | '\vfoo bar\n' +
69 | '';
70 |
71 | it('should output xml of compact js input', function () {
72 | expect(convert.js2xml(js1, {compact: true, spaces: 4})).toEqual(xml.replace(/\v/g, ' '));
73 | });
74 |
75 | it('should output xml of extended js input', function () {
76 | expect(convert.js2xml(js2, {compact: false, spaces: 4})).toEqual(xml.replace(/\v/g, ' '));
77 | });
78 |
79 | });
80 |
81 | describe('case 2 by Denis Carriere', function () {
82 | // see https://github.com/nashwaan/xml-js/issues/13
83 | var json = {
84 | "_declaration": {
85 | "_attributes": {
86 | "version": "1.0",
87 | "encoding": "utf-8"
88 | }
89 | },
90 | "ServiceExceptionReport": {
91 | "_attributes": {
92 | "version": "1.1.1"
93 | },
94 | "_doctype": 'ServiceExceptionReport SYSTEM "http://schemas.opengis.net/wms/1.1.1/exception_1_1_1.dtd"',
95 | "ServiceException": {
96 | "_text": "foo"
97 | }
98 | }
99 | };
100 | var xml =
101 | '\n' +
102 | '\n' +
103 | ' \n' +
104 | ' foo\n' +
105 | '';
106 |
107 | it('should output as expected xml', function () {
108 | expect(convert.js2xml(json, {compact: true, spaces: 2})).toEqual(xml);
109 | });
110 |
111 | });
112 |
113 | describe('case 1 by Henning Hagmann ', function () {
114 | // see https://github.com/nashwaan/xml-js/issues/14
115 | var js = {
116 | _declaration: {
117 | _attributes: {
118 | version: '1.0'
119 | }
120 | },
121 | group: {
122 | name: {
123 | _cdata: 'An example name'
124 | }
125 | }
126 | };
127 | var xml = '\n' +
128 | '\n' +
129 | '\v\n' +
130 | '';
131 |
132 | it('should output cdata without proceeding indentation', function () {
133 | expect(convert.js2xml(js, {compact: true, spaces: 4, fullTagEmptyElement: true})).toEqual(xml.replace(/\v/g, ' '));
134 | });
135 |
136 | });
137 |
138 | describe('case 2 by Henning Hagmann ', function () {
139 | // see https://github.com/nashwaan/xml-js/issues/14
140 | var js = {
141 | declaration: {
142 | attributes: {
143 | version: '1.0'
144 | }
145 | },
146 | elements: [{
147 | type: 'element',
148 | name: 'group',
149 | elements: [{
150 | type: 'element',
151 | name: 'name',
152 | elements: [{
153 | type: 'text',
154 | text: 'The url '
155 | }, {
156 | type: 'cdata',
157 | cdata: 'http://www.test.com'
158 | }, {
159 | type: 'text',
160 | text: ' and name '
161 | }, {
162 | type: 'cdata',
163 | cdata: 'examplename'
164 | }, {
165 | type: 'text',
166 | text: ' are wrapped'
167 | }]
168 | }]
169 | }]
170 | };
171 | var xml = '\n' +
172 | '\n' +
173 | '\vThe url and name are wrapped\n' +
174 | '';
175 |
176 | it('should output cdata without proceeding indentation', function () {
177 | expect(convert.js2xml(js, {compact: false, spaces: 4})).toEqual(xml.replace(/\v/g, ' '));
178 | });
179 |
180 | });
181 |
182 | describe('case by John ', function () {
183 | // see https://github.com/nashwaan/xml-js/issues/20
184 | // var js = {
185 | // request: {
186 | // user: 'username',
187 | // pass: 'password',
188 | // numbers: {
189 | // number: 1,
190 | // number: 2
191 | // }
192 | // }
193 | // };
194 | var js = {
195 | request: {
196 | user: {
197 | _text: 'username'
198 | },
199 | pass: {
200 | _text: 'password'
201 | },
202 | numbers: {
203 | number: [
204 | {
205 | _text: 1
206 | },
207 | {
208 | _text: 2
209 | }
210 | ]
211 | }
212 | }
213 | };
214 | var xml =
215 | '\n' +
216 | '\vusername\n' +
217 | '\vpassword\n' +
218 | '\v\n' +
219 | '\v\v1\n' +
220 | '\v\v2\n' +
221 | '\v\n' +
222 | '';
223 |
224 | it('should convert javascript object to xml correctly', function () {
225 | expect(convert.js2xml(js, {spaces: 4, compact: true})).toEqual(xml.replace(/\v/g, ' '));
226 | // expect(convert.xml2js(xml, {compact: true, nativeType: true})).toEqual(js);
227 | });
228 |
229 | });
230 |
231 | describe('case by yverenoir', function () {
232 | // see https://github.com/nashwaan/xml-js/issues/21
233 | // var js = {
234 | // "vertical": {
235 | // "-display_name": "Exercise",
236 | // "html": {
237 | // "-url_name": "12345"
238 | // },
239 | // "lti_consumer": {
240 | // "-url_name": "12345",
241 | // "-xblock-family": "xblock.v1",
242 | // "-accept_grades_past_due": "false",
243 | // "-weight": "14.0",
244 | // "-has_score": "true",
245 | // "-display_name": "Exercise",
246 | // "-ask_to_send_username": "true",
247 | // "-ask_to_send_email": "true",
248 | // "-button_text": "Launch Exercise",
249 | // "-custom_parameters": "none",
250 | // "-lti_id": "id",
251 | // "-launch_target": "new_window",
252 | // "-launch_url": "url"
253 | // }
254 | // }
255 | // };
256 | var js = {
257 | "vertical": {
258 | "_attributes": {
259 | "-display_name": "Exercise"
260 | },
261 | "html": {
262 | "_attributes": {
263 | "-url_name": "12345"
264 | }
265 | },
266 | "lti_consumer": {
267 | "_attributes": {
268 | "-url_name": "12345",
269 | "-xblock-family": "xblock.v1",
270 | "-accept_grades_past_due": "false",
271 | "-weight": "14.0",
272 | "-has_score": "true",
273 | "-display_name": "Exercise",
274 | "-ask_to_send_username": "true",
275 | "-ask_to_send_email": "true",
276 | "-button_text": "Launch Exercise",
277 | "-custom_parameters": "none",
278 | "-lti_id": "id",
279 | "-launch_target": "new_window",
280 | "-launch_url": "url"
281 | }
282 | }
283 | }
284 | };
285 | var xml =
286 | '\n' +
287 | '\v\n' +
288 | '\v\n' +
289 | '';
290 |
291 | it('should convert javascript object to xml correctly', function () {
292 | expect(convert.js2xml(js, {spaces: 4, compact: true})).toEqual(xml.replace(/\v/g, ' '));
293 | });
294 |
295 | });
296 |
297 | describe('case by mariotsi ', function () {
298 | // see https://github.com/nashwaan/xml-js/issues/28
299 | var js = {
300 | a: {
301 | _attributes: {
302 | num: 123
303 | }
304 | }
305 | };
306 | var xml = '';
307 |
308 | it('should process attribute number without issue', function () {
309 | expect(convert.js2xml(js, {compact: true})).toEqual(xml);
310 | });
311 |
312 | });
313 |
314 | describe('case by zaesnet ', function () {
315 | // see https://github.com/nashwaan/xml-js/issues/30
316 | var js = {
317 | a: {_text:'Hi There'}
318 | };
319 | var xml = 'Hi There';
320 | it('should convert js object to xml', function () {
321 | expect(convert.js2xml(js, {spaces: 3, fullTagEmptyElement: true, compact: true})).toEqual(xml);
322 | });
323 |
324 | });
325 |
326 | describe('case by kolis ', function () {
327 | // see https://github.com/nashwaan/xml-js/issues/31
328 | var js = {
329 | parent: {
330 | _attributes: {
331 | bar: 1,
332 | baz: 'hello'
333 | },
334 | child: {
335 | _attributes: {
336 | attr1: 'a',
337 | attr2: 'b'
338 | }
339 | }
340 | }
341 | };
342 | var xml =
343 | '\n' +
347 | '\v\n' +
351 | '';
352 | it('should be able to indent attributes', function () {
353 | expect(convert.js2xml(js, {indentAttributes: true, spaces: 2, compact: true})).toEqual(xml.replace(/\v/g, ' ').replace('=1', '="1"'));
354 | });
355 | it('should be able to indent attributes and no quotes for native attributes', function () {
356 | expect(convert.js2xml(js, {indentAttributes: true, spaces: 2, compact: true, noQuotesForNativeAttributes: true})).toEqual(xml.replace(/\v/g, ' '));
357 | });
358 |
359 | });
360 |
361 | describe('case by techborn ', function () {
362 | // see https://github.com/nashwaan/xml-js/pull/32
363 | // var js = {
364 | // example: {
365 | // _text: 'value'
366 | // }
367 | // };
368 | var js = {
369 | example: 'value'
370 | };
371 | var xml = 'value';
372 | it('should convert element text without _text property', function () {
373 | expect(convert.js2xml(js, {compact: true})).toEqual(xml);
374 | });
375 |
376 | });
377 |
378 | describe('case by silentgert', function() {
379 | // see https://github.com/nashwaan/xml-js/issues/42
380 | var context = {
381 | convert: convert,
382 | output: undefined,
383 | };
384 | var scriptCode =
385 | '(function() {\n' +
386 | ' const obj = {\n' +
387 | ' customers : {\n' +
388 | ' customer: [\n' +
389 | ' {\n' +
390 | ' _text: \'John Doe\',\n' +
391 | ' _attributes: {\n' +
392 | ' status: \'silver\'\n' +
393 | ' }\n' +
394 | ' },\n' +
395 | ' {\n' +
396 | ' _text: \'Alice Allgood\',\n' +
397 | ' _attributes: {\n' +
398 | ' status: \'gold\'\n' +
399 | ' }\n' +
400 | ' }\n' +
401 | ' ]\n' +
402 | ' }\n' +
403 | ' };\n' +
404 | ' output = convert.js2xml(obj, { compact: true });\n' +
405 | '})()\n';
406 |
407 | var executableScript = new Script(scriptCode, {
408 | displayErrors: true,
409 | });
410 |
411 | it ('should convert Arrays in a different context', function() {
412 | executableScript.runInNewContext(context);
413 | expect(context.output).toEqual('John DoeAlice Allgood');
414 | });
415 | });
416 |
417 | describe('case by Cy-Tek', function() {
418 | // see https://github.com/nashwaan/xml-js/issues/59
419 | var js = {
420 | textless: {
421 | calling_offer_code: '',
422 | mailing_code: '',
423 | vcpi: '' },
424 | };
425 | var xml =
426 | '\n' +
427 | ' \n' +
428 | ' \n' +
429 | ' \n' +
430 | '';
431 | it ('should not create full tag for empty elements', function() {
432 | expect(convert.js2xml(js, {compact: true, spaces: 2, fullTagEmptyElement: false})).toEqual(xml);
433 | });
434 | });
435 |
436 | describe('case by Nathan Perry', function() {
437 | // see n/a
438 | var js = {
439 | container: {
440 | cdata_section: {
441 | _cdata: 'cccc]]>
',
442 | },
443 | },
444 | };
445 | var xml =
446 | '\n' +
447 | ' cccc]]]]>
]]>\n' +
448 | '';
449 | it ('should handle nested CDATA sections', function() {
450 | expect(convert.js2xml(js, {compact: true, spaces: 2, fullTagEmptyElement: false})).toEqual(xml);
451 | });
452 | });
453 |
454 | });
455 |
456 | });
457 |
--------------------------------------------------------------------------------
/test/js2xml-options.spec.js:
--------------------------------------------------------------------------------
1 | var convert = require('../lib');
2 | var testItems = require('./test-items');
3 |
4 | /*global describe,it,expect*/
5 |
6 | describe('Testing js2xml.js:', function () {
7 |
8 | describe('No options supplied (fallback to defaults):', function () {
9 |
10 | var options = {};
11 | testItems('js2xml', options).forEach(function (test) {
12 | it(test.desc, function () {
13 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
14 | });
15 | });
16 |
17 | });
18 |
19 | describe('options = {compact: false}', function () {
20 |
21 | describe('Options set to default values explicitly:', function () {
22 |
23 | var options = {compact: false, spaces: 0, ignoreText: false, ignoreComment: false, ignoreCdata: false, fullTagEmptyElement: false};
24 | testItems('js2xml', options).forEach(function (test) {
25 | it(test.desc, function () {
26 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
27 | });
28 | });
29 |
30 | });
31 |
32 | describe('options = {spaces: 4}', function () {
33 |
34 | var options = {spaces: 4, onlyItem: 8};
35 | testItems('js2xml', options).forEach(function (test) {
36 | it(test.desc, function () {
37 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
38 | });
39 | });
40 |
41 | });
42 |
43 | describe('options = {spaces: 0}', function () {
44 |
45 | var options = {spaces: 0};
46 | testItems('js2xml', options).forEach(function (test) {
47 | it(test.desc, function () {
48 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
49 | });
50 | });
51 |
52 | });
53 |
54 | describe('options = {spaces: 0, ignoreText: true}', function () {
55 |
56 | var options = {spaces: 0, ignoreText: true};
57 | testItems('js2xml', options).forEach(function (test) {
58 | it(test.desc, function () {
59 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
60 | });
61 | });
62 |
63 | });
64 |
65 | describe('options = {spaces: 0, ignoreComment: true}', function () {
66 |
67 | var options = {spaces: 0, ignoreComment: true};
68 | testItems('js2xml', options).forEach(function (test) {
69 | it(test.desc, function () {
70 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
71 | });
72 | });
73 |
74 | });
75 |
76 | describe('options = {spaces: 0, ignoreCdata: true}', function () {
77 |
78 | var options = {spaces: 0, ignoreCdata: true};
79 | testItems('js2xml', options).forEach(function (test) {
80 | it(test.desc, function () {
81 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
82 | });
83 | });
84 |
85 | });
86 |
87 | describe('options = {spaces: 0, ignoreDoctype: true}', function () {
88 |
89 | var options = {spaces: 0, ignoreDoctype: true};
90 | testItems('js2xml', options).forEach(function (test) {
91 | it(test.desc, function () {
92 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
93 | });
94 | });
95 |
96 | });
97 |
98 | describe('options = {spaces: 0, ignoreDeclaration: true}', function () {
99 |
100 | var options = {spaces: 0, ignoreDeclaration: true};
101 | testItems('js2xml', options).forEach(function (test) {
102 | it(test.desc, function () {
103 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
104 | });
105 | });
106 |
107 | });
108 |
109 | describe('options = {spaces: 0, ignoreInstruction: true}', function () {
110 |
111 | var options = {spaces: 0, ignoreInstruction: true};
112 | testItems('js2xml', options).forEach(function (test) {
113 | it(test.desc, function () {
114 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
115 | });
116 | });
117 |
118 | });
119 |
120 | describe('options = {spaces: 0, fullTagEmptyElement: true}', function () {
121 |
122 | var options = {spaces: 0, fullTagEmptyElement: true};
123 | testItems('js2xml', options).forEach(function (test) {
124 | it(test.desc, function () {
125 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
126 | });
127 | });
128 |
129 | });
130 |
131 | });
132 |
133 | describe('options = {compact: true}', function () {
134 |
135 | describe('Options set to default values explicitly:', function () {
136 |
137 | var options = {compact: true, spaces: 0, ignoreText: false, ignoreComment: false, ignoreCdata: false, fullTagEmptyElement: false};
138 | testItems('js2xml', options).forEach(function (test) {
139 | it(test.desc, function () {
140 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
141 | });
142 | });
143 |
144 | });
145 |
146 | describe('options = {spaces: 4}', function () {
147 |
148 | var options = {compact: true, spaces: 4};
149 | testItems('js2xml', options).forEach(function (test) {
150 | it(test.desc, function () {
151 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
152 | });
153 | });
154 |
155 | });
156 |
157 | describe('options = {spaces: 0}', function () {
158 |
159 | var options = {compact: true, spaces: 0};
160 | testItems('js2xml', options).forEach(function (test) {
161 | it(test.desc, function () {
162 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
163 | });
164 | });
165 |
166 | });
167 |
168 | describe('options = {spaces: 0, ignoreText: true}', function () {
169 |
170 | var options = {compact: true, spaces: 0, ignoreText: true};
171 | testItems('js2xml', options).forEach(function (test) {
172 | it(test.desc, function () {
173 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
174 | });
175 | });
176 |
177 | });
178 |
179 | describe('options = {spaces: 0, ignoreComment: true}', function () {
180 |
181 | var options = {compact: true, spaces: 0, ignoreComment: true};
182 | testItems('js2xml', options).forEach(function (test) {
183 | it(test.desc, function () {
184 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
185 | });
186 | });
187 |
188 | });
189 |
190 | describe('options = {spaces: 0, ignoreCdata: true}', function () {
191 |
192 | var options = {compact: true, spaces: 0, ignoreCdata: true};
193 | testItems('js2xml', options).forEach(function (test) {
194 | it(test.desc, function () {
195 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
196 | });
197 | });
198 |
199 | });
200 |
201 | describe('options = {spaces: 0, ignoreDoctype: true}', function () {
202 |
203 | var options = {compact: true, spaces: 0, ignoreDoctype: true};
204 | testItems('js2xml', options).forEach(function (test) {
205 | it(test.desc, function () {
206 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
207 | });
208 | });
209 |
210 | });
211 |
212 | describe('options = {spaces: 0, ignoreDeclaration: true}', function () {
213 |
214 | var options = {compact: true, spaces: 0, ignoreDeclaration: true};
215 | testItems('js2xml', options).forEach(function (test) {
216 | it(test.desc, function () {
217 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
218 | });
219 | });
220 |
221 | });
222 |
223 | describe('options = {spaces: 0, ignoreInstruction: true}', function () {
224 |
225 | var options = {compact: true, spaces: 0, ignoreInstruction: true};
226 | testItems('js2xml', options).forEach(function (test) {
227 | it(test.desc, function () {
228 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
229 | });
230 | });
231 |
232 | });
233 |
234 | describe('options = {spaces: 0, fullTagEmptyElement: true}', function () {
235 |
236 | var options = {compact: true, spaces: 0, fullTagEmptyElement: true};
237 | testItems('js2xml', options).forEach(function (test) {
238 | it(test.desc, function () {
239 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
240 | });
241 | });
242 |
243 | });
244 |
245 | });
246 |
247 | describe('Varying spaces', function () {
248 |
249 | describe('options = {}', function () {
250 |
251 | var options = {};
252 | testItems('js2xml', options).forEach(function (test) {
253 | it(test.desc, function () {
254 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
255 | });
256 | });
257 |
258 | });
259 |
260 | describe('options = {spaces: true}', function () {
261 |
262 | var options = {spaces: true};
263 | testItems('js2xml', options).forEach(function (test) {
264 | it(test.desc, function () {
265 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
266 | });
267 | });
268 |
269 | });
270 |
271 | describe('options = {spaces: 2}', function () {
272 |
273 | var options = {spaces: 2};
274 | testItems('js2xml', options).forEach(function (test) {
275 | it(test.desc, function () {
276 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
277 | });
278 | });
279 |
280 | });
281 |
282 | describe('options = {spaces: 4}', function () {
283 |
284 | var options = {spaces: 4};
285 | testItems('js2xml', options).forEach(function (test) {
286 | it(test.desc, function () {
287 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
288 | });
289 | });
290 |
291 | });
292 |
293 | describe('options = {spaces: \' \'}', function () {
294 |
295 | var options = {spaces: ' '};
296 | testItems('js2xml', options).forEach(function (test) {
297 | it(test.desc, function () {
298 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
299 | });
300 | });
301 |
302 | });
303 |
304 | describe('options = {spaces: \\t}', function () {
305 |
306 | var options = {spaces: '\t'};
307 | testItems('js2xml', options).forEach(function (test) {
308 | it(test.desc, function () {
309 | expect(convert.js2xml(test.js, options)).toEqual(test.xml);
310 | });
311 | });
312 |
313 | });
314 |
315 | });
316 |
317 | describe('json2xml:', function () {
318 |
319 | describe('using default options', function () {
320 |
321 | var options = {};
322 | testItems('js2xml', options).forEach(function (test) {
323 | it(test.desc, function () {
324 | expect(convert.json2xml(JSON.stringify(test.js), options)).toEqual(test.xml);
325 | });
326 | });
327 |
328 | });
329 |
330 | describe('submitting json as javascript object', function () {
331 |
332 | var options = {};
333 | testItems('js2xml', options).forEach(function (test) {
334 | it(test.desc, function () {
335 | expect(convert.json2xml(test.js, options)).toEqual(test.xml);
336 | });
337 | });
338 |
339 | });
340 |
341 | describe('using buffer', function () {
342 |
343 | var options = {};
344 | testItems('js2xml', options).forEach(function (test) {
345 | it(test.desc, function () {
346 | expect(convert.json2xml(new Buffer.from(JSON.stringify(test.js)), options)).toEqual(test.xml);
347 | });
348 | });
349 |
350 | });
351 |
352 | describe('improper json', function () {
353 |
354 | try {
355 | convert.json2xml('{a:', {});
356 | } catch (e) {
357 | e.note = 'ignore me';
358 | }
359 |
360 | });
361 |
362 | });
363 |
364 | describe('Various options:', function () {
365 |
366 | describe('options = {instructionHasAttributes: true}', function () {
367 |
368 | it('Write processing instruction attributes, {compact: true}', function () {
369 | expect(convert.js2xml({"_instruction":{"go":{"_attributes":{"to":"there"}}}}, {compact: true})).toEqual('');
370 | });
371 |
372 | it('Write processing instruction attributes, {compact: false}', function () {
373 | expect(convert.js2xml({"elements":[{"type":"instruction","name":"go","attributes":{"to":"there"}}]})).toEqual('');
374 | });
375 |
376 | });
377 |
378 | });
379 |
380 | });
381 |
--------------------------------------------------------------------------------
/test/options-helper.spec.js:
--------------------------------------------------------------------------------
1 | var helper = require('../lib/options-helper');
2 |
3 | /*global describe,it,expect*/
4 |
5 | describe('Testing options.js:', function () {
6 |
7 | describe('Helpers:', function () {
8 |
9 | describe('Copy options:', function () {
10 |
11 | it('Copy unprovided options', function () {
12 | expect(helper.copyOptions()).toEqual({});
13 | });
14 |
15 | it('Copy provided options', function () {
16 | var options = {ignoreText: true, textKey: true};
17 | expect(helper.copyOptions(options)).toEqual(options);
18 | });
19 |
20 | });
21 |
22 | describe('Ensure flag existance:', function () {
23 |
24 | it('New flag', function () {
25 | var options = {};
26 | helper.ensureFlagExists('foo', options);
27 | expect(options).toEqual({foo: false});
28 | });
29 |
30 | it('Existing flag, not boolean', function () {
31 | var options = {foo: 123};
32 | helper.ensureFlagExists('foo', options);
33 | expect(options).toEqual({foo: false});
34 | });
35 |
36 | it('Existing flag', function () {
37 | var options = {foo: true};
38 | helper.ensureFlagExists('foo', options);
39 | expect(options).toEqual({foo: true});
40 | });
41 |
42 | });
43 |
44 | describe('Ensure key existance:', function () {
45 |
46 | it('New key', function () {
47 | var options = {};
48 | helper.ensureKeyExists('foo', options);
49 | expect(options).toEqual({fooKey: 'foo'});
50 | });
51 |
52 | it('Existing key, not string', function () {
53 | var options = {fooKey: 123};
54 | helper.ensureKeyExists('foo', options);
55 | expect(options).toEqual({fooKey: 'foo'});
56 | });
57 |
58 | it('Existing key, string', function () {
59 | var options = {fooKey: 'baa'};
60 | helper.ensureKeyExists('foo', options);
61 | expect(options).toEqual({fooKey: 'baa'});
62 | });
63 |
64 | });
65 |
66 | });
67 |
68 | });
69 |
--------------------------------------------------------------------------------
/test/pretest-jest.js:
--------------------------------------------------------------------------------
1 | expect.extend({
2 | toContain: (collection, value) => require('jest-matchers/build/matchers.js').toContainEqual(collection, value)
3 | });
4 |
--------------------------------------------------------------------------------
/test/test-items.js:
--------------------------------------------------------------------------------
1 | var isArray = require('../lib/array-helper').isArray;
2 |
3 | var cases = [
4 | {
5 | desc: 'declaration ',
6 | xml: '',
7 | js1: {"_declaration":{}},
8 | js2: {"declaration":{}}
9 | }, {
10 | desc: 'declaration with attributes',
11 | xml: '',
12 | js1: {"_declaration":{"_attributes":{"version":"1.0","encoding":"utf-8"}}},
13 | js2: {"declaration":{"attributes":{"version":"1.0","encoding":"utf-8"}}}
14 | }, {
15 | desc: 'declaration and element',
16 | xml: '\n',
17 | js1: {"_declaration":{},"a":{}},
18 | js2: {"declaration":{},"elements":[{"type":"element","name":"a"}]}
19 | }, {
20 | desc: 'declaration and elements',
21 | xml: '\n\n\v\n',
22 | js1: {"_declaration":{},"a":{"b":{}}},
23 | js2: {"declaration":{},"elements":[{"type":"element","name":"a","elements":[{"type":"element","name":"b"}]}]}
24 | }, {
25 | desc: 'processing instruction ',
26 | xml: '',
27 | js1: {"_instruction":{"go": "there"}},
28 | js2: {"elements":[{"type":"instruction","name":"go","instruction":"there"}]}
29 | }, {
30 | desc: '2 processing instructions ',
31 | xml: '',
32 | js1: {"_instruction":[{"go": "there"},{"come": "here"}]},
33 | js2: {"elements":[{"type":"instruction","name":"go","instruction":"there"},{"type":"instruction","name":"come","instruction":"here"}]}
34 | }, {
35 | desc: 'should convert comment',
36 | xml: '',
37 | js1: {"_comment":" \t Hello, World! \t "},
38 | js2: {"elements":[{"type":"comment","comment":" \t Hello, World! \t "}]}
39 | }, {
40 | desc: 'should convert 2 comments',
41 | xml: '\n',
42 | js1: {"_comment":[" \t Hello \t "," \t World \t "]},
43 | js2: {"elements":[{"type":"comment","comment":" \t Hello \t "},{"type":"comment","comment":" \t World \t "}]}
44 | }, {
45 | desc: 'should convert cdata',
46 | xml: ' \t ]]>',
47 | js1: {"_cdata":" \t \t "},
48 | js2: {"elements":[{"type":"cdata","cdata":" \t \t "}]}
49 | }, {
50 | desc: 'should convert 2 cdata',
51 | xml: ' " and & \t ]]>',
52 | js1: {"_cdata":[" \t data", "< > \" and & \t "]},
53 | js2: {"elements":[{"type":"cdata","cdata":" \t data"},{"type":"cdata","cdata":"< > \" and & \t "}]}
54 | }, {
55 | desc: 'should convert doctype',
56 | xml: ']>',
57 | js1: {"_doctype":"note [\n]"},
58 | js2: {"elements":[{"type":"doctype","doctype":"note [\n]"}]}
59 | }, {
60 | desc: 'should convert element',
61 | xml: '',
62 | js1: {"a":{}},
63 | js2: {"elements":[{"type":"element","name":"a"}]}
64 | }, {
65 | desc: 'should convert 2 same elements',
66 | xml: '\n',
67 | js1: {"a":[{},{}]},
68 | js2: {"elements":[{"type":"element","name":"a"},{"type":"element","name":"a"}]}
69 | }, {
70 | desc: 'should convert 2 different elements',
71 | xml: '\n',
72 | js1: {"a":{},"b":{}},
73 | js2: {"elements":[{"type":"element","name":"a"},{"type":"element","name":"b"}]}
74 | }, {
75 | desc: 'should convert attribute',
76 | xml: '',
77 | js1: {"a":{_attributes:{"x":"hello"}}},
78 | js2: {"elements":[{"type":"element","name":"a","attributes":{"x":"hello"}}]}
79 | }, {
80 | desc: 'should convert 2 attributes',
81 | xml: '',
82 | js1: {"a":{_attributes:{"x":"1.234","y":"It\'s"}}},
83 | js2: {"elements":[{"type":"element","name":"a","attributes":{"x":"1.234","y":"It\'s"}}]}
84 | }, {
85 | desc: 'should convert text in element',
86 | xml: ' \t Hi \t ',
87 | js1: {"a":{"_text":" \t Hi \t "}},
88 | js2: {"elements":[{"type":"element","name":"a","elements":[{"type":"text","text":" \t Hi \t "}]}]}
89 | }, {
90 | desc: 'should convert multi-line text',
91 | xml: ' Hi \n There \t ',
92 | js1: {"a":{"_text":" Hi \n There \t "}},
93 | js2: {"elements":[{"type":"element","name":"a","elements":[{"type":"text","text":" Hi \n There \t "}]}]}
94 | }, {
95 | desc: 'should convert nested elements',
96 | xml: '\n\v\n',
97 | js1: {"a":{"b":{}}},
98 | js2: {"elements":[{"type":"element","name":"a","elements":[{"type":"element","name":"b"}]}]}
99 | }, {
100 | desc: 'should convert 3 nested elements',
101 | xml: '\n\v\n\v\v\n\v\n',
102 | js1: {"a":{"b":{"c":{}}}},
103 | js2: {"elements":[{"type":"element","name":"a","elements":[{"type":"element","name":"b","elements":[{"type":"element","name":"c"}]}]}]}
104 | }
105 |
106 | // todo alwaysArray array case
107 | ];
108 |
109 | module.exports = function (direction, options) {
110 | var i, tests = [];
111 | options = options || {};
112 | function applyOptions (obj, pathKey) {
113 | var key, fullKey;
114 | pathKey = pathKey || '';
115 | if (obj instanceof Array) {
116 | obj = obj.filter(function (el) {
117 | return !(options.ignoreText && el.type === 'text' || options.ignoreComment && el.type === 'comment' || options.ignoreCdata && el.type === 'cdata'
118 | || options.ignoreDoctype && el.type === 'doctype' || options.ignoreDeclaration && el.type === 'declaration' || options.ignoreInstruction && el.type === 'instruction');
119 | }).map(function (el) {
120 | return manipulate(el, pathKey);
121 | });
122 | } else if (typeof obj === 'object') {
123 | for (key in obj) {
124 | fullKey = (pathKey ? pathKey + '.' : '') + key;
125 | if (
126 | options.compact &&
127 | (isArray(options.alwaysArray) ? options.alwaysArray.indexOf(key) !== -1 : options.alwaysArray) &&
128 | !(obj[key] instanceof Array) &&
129 | key !== '_declaration' &&
130 | (key === '_instruction' || fullKey.indexOf('_instruction') < 0) &&
131 | fullKey.indexOf('_attributes') < 0
132 | ) {
133 | obj[key] = [obj[key]];
134 | }
135 | key = applyNameCallbacks(obj, key, pathKey.split('.').pop());
136 | key = applyAttributesCallback(obj, key, pathKey.split('.').pop());
137 | if (key.indexOf('_') === 0 && obj[key] instanceof Array) {
138 | obj[key] = obj[key].map(function (el) {
139 | return manipulate(el, fullKey);
140 | });
141 | } else {
142 | if (key !== 'parent' && key !== '_parent') {
143 | obj[key] = manipulate(obj[key], fullKey);
144 | if (obj[key] instanceof Array && obj[key].length === 0) {
145 | delete obj[key];
146 | }
147 | }
148 | }
149 | if (options.addParent /*&& key.indexOf('declaration') === -1*/ && key.indexOf('attributes') === -1 && key.indexOf('instruction') === -1) {
150 | if (obj[key] instanceof Array) {
151 | obj[key].forEach(function (el) {
152 | if (options.compact) { if (typeof el === 'object') el._parent = obj; } else { el.parent = obj; }
153 | });
154 | } else if (typeof obj[key] === 'object') {
155 | if (options.compact) { if (typeof obj[key] === 'object') obj[key]._parent = obj; } else { obj[key].parent = obj; }
156 | }
157 | }
158 | if (options.ignoreText && key === '_text' || options.ignoreComment && key === '_comment' || options.ignoreCdata && key === '_cdata'
159 | || options.ignoreDoctype && key === '_doctype' || options.ignoreDeclaration && (key === '_declaration' || key === 'declaration') || options.ignoreInstruction && key === '_instruction') {
160 | delete obj[key];
161 | }
162 | }
163 | if (!options.compact && options.addParent && obj.elements) {
164 | obj.elements.forEach(function (el) {
165 | el.parent = obj;
166 | });
167 | }
168 | if (!options.compact && options.alwaysChildren && obj.type === 'element' && !obj.elements) {
169 | obj.elements = [];
170 | }
171 | // if (!options.compact && options.trim && obj.type in obj) {
172 | // obj[obj.type] = obj[obj.type].trim();
173 | // }
174 | }
175 | return obj;
176 | function manipulate(x, fullKey) {
177 | if (x instanceof Array) {
178 | return applyOptions(x, fullKey);
179 | } if (typeof x === 'object') {
180 | return applyOptions(x, fullKey);
181 | } else if (typeof x === 'string') {
182 | x = applyValueCallbacks(x, fullKey.split('.').pop(), fullKey.split('.')[fullKey.split('.').length - 2] || '');
183 | return options.trim? x.trim() : x;
184 | } else if (typeof x === 'number' || typeof x === 'boolean') {
185 | return options.nativeType? x.toString() : x;
186 | } else {
187 | return x;
188 | }
189 | }
190 | }
191 | function applyKeyNames(js) {
192 | var key;
193 | for (key in options) {
194 | if (key.match(/Key$/)) {
195 | var keyName = (options.compact ? '_' : '') + key.replace('Key', '');
196 | js = JSON.parse(JSON.stringify(js).replace(new RegExp('"' + keyName + '":', 'g'), '"' + options[key] + '":'));
197 | }
198 | }
199 | return js;
200 | }
201 | function applyNameCallbacks(obj, key, parentKey) {
202 | if ('instructionNameFn' in options && (options.compact && parentKey === '_instruction' || !options.compact && obj.type === 'instruction')
203 | || 'elementNameFn' in options && (options.compact && key.indexOf('_') < 0 && parentKey !== '_attributes' && parentKey !== '_instruction' || !options.compact && obj.type === 'element')) {
204 | if (options.compact) {
205 | var temp = obj[key];
206 | delete obj[key];
207 | key = 'elementNameFn' in options ? options.elementNameFn(key) : options.instructionNameFn(key);
208 | obj[key] = temp;
209 | } else {
210 | obj.name = 'elementNameFn' in options ? options.elementNameFn(obj.name) : options.instructionNameFn(obj.name);
211 | }
212 | }
213 | return key;
214 | }
215 | function applyAttributesCallback(obj, key, parentKey) {
216 | if (options.nativeTypeAttributes) {
217 | var parsedNumber = Number(obj[key]);
218 | if (!Number.isNaN(parsedNumber)) {
219 | obj[key] = parsedNumber;
220 | }
221 | }
222 | if (('attributeNameFn' in options || 'attributeValueFn' in options) && (parentKey === '_attributes' || parentKey === 'attributes')) {
223 | if ('attributeNameFn' in options) {
224 | var temp = obj[key];
225 | delete obj[key];
226 | key = options.attributeNameFn(key);
227 | obj[key] = temp;
228 | }
229 | if ('attributeValueFn' in options) {
230 | obj[key] = options.attributeValueFn(obj[key]);
231 | }
232 | }
233 | if ('attributesFn' in options && (key === '_attributes' || key === 'attributes')) {
234 | obj[key] = options.attributesFn(obj[key]);
235 | }
236 | return key;
237 | }
238 | function applyValueCallbacks(value, key, parentKey) {
239 | var fn;
240 | for (fn in options) {
241 | if (fn.match(/Fn$/) && !fn.match(/NameFn$/)) {
242 | var callbackName = (options.compact ? '_' : '') + fn.replace('Fn', '');
243 | if (key === callbackName || parentKey === callbackName) {
244 | value = options[fn](value);
245 | }
246 | }
247 | }
248 | return value;
249 | }
250 | for (i = 0; i < cases.length; ++i) {
251 | tests.push({desc: cases[i].desc, xml: null, js: null});
252 | tests[i].js = options.compact ? cases[i].js1 : cases[i].js2;
253 | tests[i].xml = cases[i].xml;
254 | if (direction === 'xml2js') {
255 | tests[i].js = applyOptions(JSON.parse(JSON.stringify(tests[i].js)));
256 | tests[i].js = applyKeyNames(tests[i].js);
257 | } else if (direction === 'js2xml') {
258 | if (!('spaces' in options) || options.spaces === 0 || typeof options.spaces === 'boolean') { tests[i].xml = tests[i].xml.replace(/>\n\v*/gm, '>'); }
259 | if ('spaces' in options && options.spaces !== 0 && typeof options.spaces === 'number') { tests[i].xml = tests[i].xml.replace(/\v/g, Array(options.spaces + 1).join(' ')); }
260 | if ('spaces' in options && typeof options.spaces === 'string') { tests[i].xml = tests[i].xml.replace(/\v/g, options.spaces); }
261 | if (options.ignoreText) { tests[i].xml = tests[i].xml.replace(/>([\s\S]*?)<'); }
262 | if (options.ignoreComment) { tests[i].xml = tests[i].xml.replace(//gm, ''); }
263 | if (options.ignoreCdata) { tests[i].xml = tests[i].xml.replace(//gm, ''); }
264 | if (options.ignoreDoctype) { tests[i].xml = tests[i].xml.replace(//gm, ''); }
265 | if (options.ignoreDeclaration) { tests[i].xml = tests[i].xml.replace(/<\?xml[\s\S]*\?>/gm, ''); }
266 | if (options.ignoreInstruction) { tests[i].xml = tests[i].xml.replace(/<\?(?!xml)[\s\S]*\?>/gm, ''); }
267 | if (options.fullTagEmptyElement) { tests[i].xml = tests[i].xml.replace('', '').replace('', '').replace('', '').replace('/>', '>'); }
268 | }
269 | }
270 | if ('onlyItem' in options) {
271 | tests = [tests[options.onlyItem]];
272 | }
273 | return tests;
274 | };
275 |
--------------------------------------------------------------------------------
/test/usage-example.js:
--------------------------------------------------------------------------------
1 | var convert = require('..');
2 | var xml =
3 | '' + '\n' +
4 | '' + '\n' +
5 | ' Happy' + '\n' +
6 | ' Work' + '\n' +
7 | ' Play' + '\n' +
8 | '';
9 | var result1 = convert.xml2json(xml, {compact: true});
10 | var result2 = convert.xml2json(xml, {compact: false});
11 | console.log(result1, '\n', result2);
12 |
--------------------------------------------------------------------------------
/test/xml2js-callbacks.spec.js:
--------------------------------------------------------------------------------
1 | var convert = require('../lib');
2 | var testItems = require('./test-items');
3 |
4 | /*global describe,it,expect*/
5 |
6 | var args;
7 |
8 | function manipulate(val) {
9 | args = arguments;
10 | args[0] = val.toUpperCase();
11 | return val.toUpperCase();
12 | }
13 |
14 | function manipulateAttribute(obj) {
15 | args = arguments;
16 | var key, temp;
17 | for (key in obj) {
18 | try {
19 | temp = obj[key];
20 | delete obj[key];
21 | obj[key.toUpperCase()] = temp.toUpperCase();
22 | } catch (e) {}
23 | }
24 | return obj;
25 | }
26 |
27 | describe('Testing xml2js.js:', function () {
28 |
29 | describe('Adding function callbacks, options = {compact: false}', function () {
30 |
31 | describe('options = {doctypeFn: manipulate}', function () {
32 |
33 | var options = {compact: false, doctypeFn: manipulate};
34 | testItems('xml2js', options).forEach(function (test) {
35 | it(test.desc, function () {
36 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
37 | });
38 | if (test.js.elements && test.js.elements[0].doctype) {
39 | it('should provide correct arguments', function () {
40 | expect(args).toContain(test.js.elements[test.js.elements.length-1].doctype, test.js);
41 | });
42 | }
43 | });
44 |
45 | });
46 |
47 | describe('options = {instructionFn: manipulate}', function () {
48 |
49 | var options = {compact: false, instructionFn: manipulate};
50 | testItems('xml2js', options).forEach(function (test) {
51 | it(test.desc, function () {
52 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
53 | // console.log(JSON.stringify(convert.xml2js(test.xml, options)));
54 | });
55 | if (test.js.elements && test.js.elements[0].instruction) {
56 | it('should provide correct arguments', function () {
57 | expect(args).toContain(test.js.elements[test.js.elements.length-1].instruction, test.js);
58 | // console.log(JSON.stringify(args), '---------', test.js.elements[0].instruction);
59 | });
60 | }
61 | });
62 |
63 | });
64 |
65 | describe('options = {cdataFn: manipulate}', function () {
66 |
67 | var options = {compact: false, cdataFn: manipulate};
68 | testItems('xml2js', options).forEach(function (test) {
69 | it(test.desc, function () {
70 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
71 | });
72 | if (test.js.elements && test.js.elements[0].cdata) {
73 | it('should provide correct arguments', function () {
74 | expect(args).toContain(test.js.elements[test.js.elements.length-1].cdata, test.js);
75 | });
76 | }
77 | });
78 |
79 | });
80 |
81 | describe('options = {commentFn: manipulate}', function () {
82 |
83 | var options = {compact: false, commentFn: manipulate};
84 | testItems('xml2js', options).forEach(function (test) {
85 | it(test.desc, function () {
86 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
87 | });
88 | if (test.js.elements && test.js.elements[0].comment) {
89 | it('should provide correct arguments', function () {
90 | expect(args).toContain(test.js.elements[test.js.elements.length-1].comment, test.js);
91 | });
92 | }
93 | });
94 |
95 | });
96 |
97 | describe('options = {textFn: manipulate}', function () {
98 |
99 | var options = {compact: false, textFn: manipulate};
100 | testItems('xml2js', options).forEach(function (test) {
101 | it(test.desc, function () {
102 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
103 | });
104 | if (test.js.elements && test.js.elements[0].text) {
105 | it('should provide correct arguments', function () {
106 | expect(args).toContain(test.js.elements[test.js.elements.length-1].text, test.js);
107 | });
108 | }
109 | });
110 |
111 | });
112 |
113 | describe('options = {instructionNameFn: manipulate}', function () {
114 |
115 | var options = {compact: false, instructionNameFn: manipulate};
116 | testItems('xml2js', options).forEach(function (test) {
117 | it(test.desc, function () {
118 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
119 | });
120 | if (test.js.elements && test.js.elements[0].instruction) {
121 | it('should provide correct arguments', function () {
122 | expect(args).toContain(test.js.elements[test.js.elements.length-1].name, test.js);
123 | });
124 | }
125 | });
126 |
127 | });
128 |
129 | describe('options = {elementNameFn: manipulate}', function () {
130 |
131 | var options = {compact: false, elementNameFn: manipulate};
132 | testItems('xml2js', options).forEach(function (test) {
133 | it(test.desc, function () {
134 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
135 | });
136 | if (test.js.elements && test.js.elements[test.js.elements.length-1].type === 'element' && !test.js.elements[test.js.elements.length-1].elements) {
137 | it('should provide correct arguments', function () {
138 | expect(args).toContain(test.js.elements[test.js.elements.length-1].name, test.js);
139 | });
140 | }
141 | });
142 |
143 | });
144 |
145 | describe('options = {attributeNameFn: manipulate}', function () {
146 |
147 | var options = {compact: false, attributeNameFn: manipulate};
148 | testItems('xml2js', options).forEach(function (test) {
149 | it(test.desc, function () {
150 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
151 | });
152 | });
153 |
154 | });
155 |
156 | describe('options = {attributeValueFn: manipulate}', function () {
157 |
158 | var options = {compact: false, attributeValueFn: manipulate};
159 | testItems('xml2js', options).forEach(function (test) {
160 | it(test.desc, function () {
161 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
162 | });
163 | });
164 |
165 | });
166 |
167 | describe('options = {attributesFn: manipulateAttribute}', function () {
168 |
169 | var options = {compact: false, attributesFn: manipulateAttribute};
170 | testItems('xml2js', options).forEach(function (test) {
171 | it(test.desc, function () {
172 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
173 | });
174 | if (test.js.elements && test.js.elements[test.js.elements.length-1].attributes) {
175 | it('should provide correct arguments', function () {
176 | expect(args).toContain(test.js.elements[test.js.elements.length-1].attributes, test.js);
177 | });
178 | }
179 | });
180 |
181 | });
182 |
183 | describe('options = {doctypeFn: manipulate, instructionFn: manipulate, cdataFn: manipulate, commentFn: manipulate, textFn: manipulate}', function () {
184 |
185 | var options = {compact: false, doctypeFn: manipulate, instructionFn: manipulate, cdataFn: manipulate, commentFn: manipulate, textFn: manipulate};
186 | testItems('xml2js', options).forEach(function (test) {
187 | it(test.desc, function () {
188 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
189 | });
190 | });
191 |
192 | });
193 |
194 | describe('options = {instructionNameFn: manipulate, elementNameFn: manipulate, attributeNameFn: manipulate, attributeValueFn: manipulate}', function () {
195 |
196 | var options = {compact: false, instructionNameFn: manipulate, elementNameFn: manipulate, attributeNameFn: manipulate, attributeValueFn: manipulate};
197 | testItems('xml2js', options).forEach(function (test) {
198 | it(test.desc, function () {
199 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
200 | });
201 | });
202 |
203 | });
204 |
205 | });
206 |
207 | describe('Adding function callbacks, options = {compact: true}', function () {
208 |
209 | describe('options = {doctypeFn: manipulate}', function () {
210 |
211 | var options = {compact: true, doctypeFn: manipulate};
212 | testItems('xml2js', options).forEach(function (test) {
213 | it(test.desc, function () {
214 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
215 | });
216 | if (test.js._doctype) {
217 | it('should provide correct arguments', function () {
218 | expect(args).toContain(test.js._doctype instanceof Array ? test.js._doctype[1] : test.js._doctype, test.js);
219 | });
220 | }
221 | });
222 |
223 | });
224 |
225 | describe('options = {instructionFn: manipulate}', function () {
226 |
227 | var options = {compact: true, instructionFn: manipulate};
228 | testItems('xml2js', options).forEach(function (test) {
229 | it(test.desc, function () {
230 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
231 | });
232 | });
233 |
234 | });
235 |
236 | describe('options = {cdataFn: manipulate}', function () {
237 |
238 | var options = {compact: true, cdataFn: manipulate};
239 | testItems('xml2js', options).forEach(function (test) {
240 | it(test.desc, function () {
241 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
242 | });
243 | if (test.js._cdata) {
244 | it('should provide correct arguments', function () {
245 | expect(args).toContain(test.js._cdata instanceof Array ? test.js._cdata[1] : test.js._cdata, test.js);
246 | });
247 | }
248 | });
249 |
250 | });
251 |
252 | describe('options = {commentFn: manipulate}', function () {
253 |
254 | var options = {compact: true, commentFn: manipulate};
255 | testItems('xml2js', options).forEach(function (test) {
256 | it(test.desc, function () {
257 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
258 | });
259 | if (test.js._comment) {
260 | it('should provide correct arguments', function () {
261 | expect(args).toContain(test.js._comment instanceof Array ? test.js._comment[1] : test.js._comment, test.js);
262 | });
263 | }
264 | });
265 |
266 | });
267 |
268 | describe('options = {textFn: manipulate}', function () {
269 |
270 | var options = {compact: true, textFn: manipulate};
271 | testItems('xml2js', options).forEach(function (test) {
272 | it(test.desc, function () {
273 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
274 | });
275 | if (test.js.a && test.js.a._text) {
276 | it('should provide correct arguments', function () {
277 | expect(args).toContain(test.js.a._text, test.js.a);
278 | });
279 | }
280 | });
281 |
282 | });
283 |
284 | describe('options = {instructionNameFn: manipulate}', function () {
285 |
286 | var options = {compact: true, instructionNameFn: manipulate};
287 | testItems('xml2js', options).forEach(function (test) {
288 | it(test.desc, function () {
289 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
290 | });
291 | });
292 |
293 | });
294 |
295 | describe('options = {elementNameFn: manipulate}', function () {
296 |
297 | var options = {compact: true, elementNameFn: manipulate};
298 | testItems('xml2js', options).forEach(function (test) {
299 | it(test.desc, function () {
300 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
301 | });
302 | });
303 |
304 | });
305 |
306 | describe('options = {attributeNameFn: manipulate}', function () {
307 |
308 | var options = {compact: true, attributeNameFn: manipulate};
309 | testItems('xml2js', options).forEach(function (test) {
310 | it(test.desc, function () {
311 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
312 | });
313 | });
314 |
315 | });
316 |
317 | describe('options = {attributeValueFn: manipulate}', function () {
318 |
319 | var options = {compact: true, attributeValueFn: manipulate};
320 | testItems('xml2js', options).forEach(function (test) {
321 | it(test.desc, function () {
322 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
323 | });
324 | });
325 |
326 | });
327 |
328 | describe('options = {attributesFn: manipulateAttribute}', function () {
329 |
330 | var options = {compact: true, attributesFn: manipulateAttribute};
331 | testItems('xml2js', options).forEach(function (test) {
332 | it(test.desc, function () {
333 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
334 | });
335 | if (test.js.a && test.js.a._attributes) {
336 | it('should provide correct arguments', function () {
337 | expect(args).toContain(test.js.a._attributes, test.js);
338 | });
339 | }
340 | });
341 |
342 | });
343 |
344 | describe('options = {doctypeFn: manipulate, instructionFn: manipulate, cdataFn: manipulate, commentFn: manipulate, textFn: manipulate}', function () {
345 |
346 | var options = {compact: true, doctypeFn: manipulate, instructionFn: manipulate, cdataFn: manipulate, commentFn: manipulate, textFn: manipulate};
347 | testItems('xml2js', options).forEach(function (test) {
348 | it(test.desc, function () {
349 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
350 | });
351 | });
352 |
353 | });
354 |
355 | describe('options = {instructionNameFn: manipulate, elementNameFn: manipulate, attributeNameFn: manipulate, attributeValueFn: manipulate}', function () {
356 |
357 | var options = {compact: true, instructionNameFn: manipulate, elementNameFn: manipulate, attributeNameFn: manipulate, attributeValueFn: manipulate};
358 | testItems('xml2js', options).forEach(function (test) {
359 | it(test.desc, function () {
360 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
361 | });
362 | });
363 |
364 | });
365 |
366 | });
367 |
368 | });
369 |
--------------------------------------------------------------------------------
/test/xml2js-issues.spec.js:
--------------------------------------------------------------------------------
1 | var convert = require('../lib');
2 |
3 | /*eslint quotes: 0*/ // --> turn off error of strings surrounded by double quotes
4 | /*global describe,xdescribe,it,expect*/
5 |
6 | describe('Testing xml2js.js:', function () {
7 |
8 | describe('User reported issues on github:', function () {
9 |
10 | describe('case by Mark Pareja', function () {
11 | // see https://github.com/nashwaan/xml-js/issues/3
12 | var xml =
13 | '\n' +
14 | '\n' +
15 | ' \n' +
16 | ' \n' +
17 | ' \n' +
18 | ' \n' +
19 | ' \n' +
20 | '';
21 | var json = {
22 | "_declaration": {
23 | "_attributes": {
24 | "version": "1.0",
25 | "encoding": "utf-8"
26 | }
27 | },
28 | "dp:ListServicesReply": {
29 | "_attributes": {
30 | "ReturnCode": "0",
31 | "xmlns:dp": "http://www.cisco.com/vtg/diagnosticportal"
32 | },
33 | "dp:Schema": {
34 | "_attributes": {
35 | "Version": "1.0"
36 | }
37 | },
38 | "dp:ServiceList": {
39 | "dp:Service": [
40 | {
41 | "_attributes": {
42 | "Name": "Cisco ICM usgd1 LoggerA",
43 | "Description": "Provides Call Logging services for Instance usgd1",
44 | "Status": "Running",
45 | "StartupType": "Auto",
46 | "LogOnAs": "****"
47 | }
48 | },
49 | {
50 | "_attributes": {
51 | "Name": "Cisco ICM Diagnostic Framework",
52 | "Description": "Provides a web-based diagnostic service for Cisco Unified ICM, Contact Center Enterprise application.",
53 | "Status": "Running",
54 | "StartupType": "Auto",
55 | "LogOnAs": "LocalSystem"
56 | }
57 | }
58 | ]
59 | }
60 | }
61 | };
62 |
63 | it('should output as expected json', function () {
64 | expect(convert.xml2json(xml, {compact: true})).toEqual(JSON.stringify(json));
65 | });
66 |
67 | });
68 |
69 | describe('case by Félix Dion Robidoux', function () {
70 | // see https://github.com/nashwaan/xml-js/issues/6
71 | var xml =
72 | '\n' +
73 | ' \n' +
74 | ' \n' +
75 | ' \n' +
76 | ' \n' +
83 | ' \n' +
90 | ' \n' +
91 | ' \n' +
92 | ' \n' +
93 | ' \n' +
94 | ' \n' +
95 | ' \n' +
96 | '';
97 |
98 | var json = convert.xml2json(xml, {compact: true, spaces: 4});
99 |
100 | it('should output json and reverse it back to xml', function () {
101 | expect(convert.json2xml(json, {compact: true, spaces: 4, fullTagEmptyElement: true})).toEqual(xml);
102 | });
103 |
104 | });
105 |
106 | describe('case by misitoth', function () {
107 | // see https://github.com/nashwaan/xml-js/issues/13
108 | var xml = '%extension;]>';
109 | var json = {"_doctype" : "svc_init SYSTEM \"MLP_SVC_INIT_300.DTD\" [%extension;]"};
110 |
111 | it('should output as expected json', function () {
112 | expect(convert.xml2js(xml, {compact: true})).toEqual(json);
113 | });
114 |
115 | });
116 |
117 | describe('case by adamgcraig', function () {
118 | // see https://github.com/nashwaan/xml-js/issues/26
119 | var xml =
120 | '\n' +
121 | '\n' +
122 | '\vxml-js\n' +
123 | '\vACraig\n' +
124 | '\vMin Example\n' +
125 | '\vHere are some characters that get sanitized: " \'\n' +
126 | '';
127 | var js = {
128 | "_declaration": {
129 | "_attributes": {
130 | "version": "1.0",
131 | "encoding": "UTF-8"
132 | }
133 | },
134 | "note": {
135 | "to": {
136 | "_text": "xml-js"
137 | },
138 | "from": {
139 | "_text": "ACraig"
140 | },
141 | "heading": {
142 | "_text": "Min Example"
143 | },
144 | "body": {
145 | "_text": "Here are some characters that get sanitized: \" '"
146 | }
147 | }
148 | };
149 |
150 | it('should convert xml object to js and back to xml correctly', function () {
151 | xml = xml.replace(/\v/g, ' ');
152 | var js_ = convert.xml2js(xml, {compact: true});
153 | expect(js_).toEqual(js);
154 | expect(convert.js2xml(js_, {spaces: 2, compact: true})).toEqual(xml);
155 | });
156 |
157 | });
158 |
159 | describe('case by bidiu', function () {
160 | // see https://github.com/nashwaan/xml-js/issues/26
161 | var xml = 'Support & resistance';
162 | var js = {
163 | elements: [{
164 | type: 'element',
165 | name: 'title',
166 | elements: [{
167 | type: 'text',
168 | text: 'Support & resistance'
169 | }]
170 | }]
171 | };
172 |
173 | it('should convert xml object to js and back to xml correctly', function () {
174 | var js_ = convert.xml2js(xml);
175 | expect(js_).toEqual(js);
176 | expect(convert.js2xml(js_)).toEqual(xml);
177 | });
178 |
179 | });
180 |
181 | describe('case by Daniel \'yngwi\'', function () {
182 | // see https://github.com/nashwaan/xml-js/issues/29
183 | var xml = ' This is some Text ';
184 | var js = {
185 | elements: [{
186 | type: 'element',
187 | name: 'outer',
188 | elements: [{
189 | type: 'text',
190 | text: ' This is '
191 | }, {
192 | type: 'element',
193 | name: 'inner',
194 | elements: [{
195 | type: 'text',
196 | text: ' some'
197 | }]
198 | }, {
199 | type: 'text',
200 | text: ' '
201 | }, {
202 | type: 'element',
203 | name: 'inner',
204 | elements: [{
205 | type: 'text',
206 | text: 'Text '
207 | }]
208 | }, {
209 | type: 'text',
210 | text: ' '
211 | }]
212 | }]
213 | };
214 |
215 | it('should convert xml object to js and back to xml correctly', function () {
216 | var js_ = convert.xml2js(xml, {captureSpacesBetweenElements: true});
217 | expect(js_).toEqual(js);
218 | expect(convert.js2xml(js_)).toEqual(xml);
219 | });
220 |
221 | });
222 |
223 | describe('case by Nuno Martins', function () {
224 | // see https://github.com/nashwaan/xml-js/issues/34
225 | var xml = '';
226 | var js = {
227 | declaration: {
228 | attributes: {
229 | version: '1.0',
230 | encoding: 'UTF-8'
231 | }
232 | }
233 | };
234 |
235 | it('should accept XML declarations that use single quotes', function () {
236 | expect(convert.xml2js(xml)).toEqual(js);
237 | });
238 |
239 | });
240 |
241 | xdescribe('case by \'ultimate-tester\'', function () {
242 | // see https://github.com/nashwaan/xml-js/issues/41
243 | var xml1 =
244 | '\n' +
245 | ' \n' +
246 | ' /\n' +
247 | ' \n' +
248 | ' \n' +
249 | ' \n' +
250 | ' /principals/users/johndoe/\n' +
251 | ' \n' +
252 | ' \n' +
253 | ' HTTP/1.1 200 OK\n' +
254 | ' \n' +
255 | ' \n' +
256 | '';
257 | var xml2 =
258 | '\n' +
259 | ' \n' +
260 | ' /\n' +
261 | ' \n' +
262 | ' \n' +
263 | ' \n' +
264 | ' /principals/users/johndoe/\n' +
265 | ' \n' +
266 | ' \n' +
267 | ' HTTP/1.1 200 OK\n' +
268 | ' \n' +
269 | ' \n' +
270 | '';
271 | var js1 = {
272 | "d:multistatus": {
273 | "_attributes": {
274 | "xmlns": "DAV:"
275 | },
276 | "response": {
277 | "href": {
278 | "_text": "/"
279 | },
280 | "propstat": {
281 | "prop": {
282 | "current-user-principal": {
283 | "href": {
284 | "_text": "/principals/users/johndoe/"
285 | }
286 | }
287 | },
288 | "status": {
289 | "_text": "HTTP/1.1 200 OK"
290 | }
291 | }
292 | }
293 | }
294 | };
295 | var js2 = {
296 | "d:multistatus": {
297 | "_attributes": {
298 | "xmlns:d": "DAV:"
299 | },
300 | "d:response": {
301 | "d:href": {
302 | "_text": "/"
303 | },
304 | "d:propstat": {
305 | "d:prop": {
306 | "d:current-user-principal": {
307 | "d:href": {
308 | "_text": "/principals/users/johndoe/"
309 | }
310 | }
311 | },
312 | "d:status": {
313 | "_text": "HTTP/1.1 200 OK"
314 | }
315 | }
316 | }
317 | }
318 | };
319 | var js = {
320 | "d:multistatus": {
321 | "_attributes": {
322 | "xmlns:d": "DAV:"
323 | },
324 | "DAV:response": {
325 | "DAV:href": {
326 | "_text": "/"
327 | },
328 | "DAV:propstat": {
329 | "DAV:prop": {
330 | "DAV:current-user-principal": {
331 | "DAV:href": {
332 | "_text": "/principals/users/johndoe/"
333 | }
334 | }
335 | },
336 | "DAV:status": {
337 | "_text": "HTTP/1.1 200 OK"
338 | }
339 | }
340 | }
341 | }
342 | };
343 |
344 | it('should convert without resolving namespace', function () {
345 | expect(convert.xml2js(xml1, {compact: true, resolveNamespace: false})).toEqual(js1);
346 | expect(convert.xml2js(xml2, {compact: true, resolveNamespace: false})).toEqual(js2);
347 | });
348 |
349 | it('should convert and resolve namespace', function () {
350 | expect(convert.xml2js(xml1, {compact: true, resolveNamespace: true})).toEqual(js);
351 | });
352 |
353 | });
354 |
355 | describe('case by austin-laney', function () {
356 | // see https://github.com/nashwaan/xml-js/issues/26
357 | var xml = '';
358 | var js = {
359 | parser: {
360 | _attributes: {
361 | start: '^\\s*?regex$'
362 | }
363 | }
364 | };
365 |
366 | it('should xml to json and back to xml', function () {
367 | expect(convert.xml2js(xml, {compact: true})).toEqual(js);
368 | expect(convert.js2xml(js, {compact: true, attributeValueFn: function(value) {
369 | return value.replace(//g, '>');
370 | }})).toEqual(xml);
371 | });
372 |
373 | });
374 |
375 | describe('case by SergeyAlexsandrovich', function () {
376 | // see https://github.com/nashwaan/xml-js/issues/44
377 | var xml = '';
378 | var js = {
379 | "material": [{
380 | "font": {
381 | "_attributes": {"size":"14"}
382 | }
383 | }, {
384 | "font": {
385 | "_attributes": {"size":"14"}
386 | }
387 | }]
388 | };
389 | it('should json to xml and back to json', function () {
390 | // console.log(convert.xml2json(xml, {compact: true}));
391 | // expect(convert.js2xml(js, {compact: true})).toEqual(xml);
392 | expect(convert.xml2json(xml, {compact: true})).toEqual(JSON.stringify(js));
393 | });
394 |
395 | });
396 |
397 | });
398 |
399 | });
400 |
--------------------------------------------------------------------------------
/test/xml2js-keys.spec.js:
--------------------------------------------------------------------------------
1 | var convert = require('../lib');
2 | var testItems = require('./test-items');
3 |
4 | /*global describe,it,expect*/
5 |
6 | describe('Testing xml2js.js:', function () {
7 |
8 | describe('Changing default key names, options = {compact: false}', function () {
9 |
10 | describe('Changing options.declarationKey', function () {
11 |
12 | var options = {compact: false, declarationKey: 'declaration'.slice(0,3)};
13 | testItems('xml2js', options).forEach(function (test) {
14 | it(test.desc, function () {
15 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
16 | });
17 | });
18 |
19 | });
20 |
21 | describe('Changing options.instructionKey', function () {
22 |
23 | var options = {compact: false, instructionKey: 'instruction'.slice(0,3)};
24 | testItems('xml2js', options).forEach(function (test) {
25 | it(test.desc, function () {
26 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
27 | });
28 | });
29 |
30 | });
31 |
32 | describe('Changing options.attributesKey', function () {
33 |
34 | var options = {compact: false, attributesKey: 'attributes'.slice(0,3)};
35 | testItems('xml2js', options).forEach(function (test) {
36 | it(test.desc, function () {
37 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
38 | });
39 | });
40 |
41 | });
42 |
43 | describe('Changing options.textKey', function () {
44 |
45 | var options = {compact: false, textKey: 'text'.slice(0,3)};
46 | testItems('xml2js', options).forEach(function (test) {
47 | it(test.desc, function () {
48 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
49 | });
50 | });
51 |
52 | });
53 |
54 | describe('Changing options.cdataKey', function () {
55 |
56 | var options = {compact: false, cdataKey: 'cdata'.slice(0,3)};
57 | testItems('xml2js', options).forEach(function (test) {
58 | it(test.desc, function () {
59 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
60 | });
61 | });
62 |
63 | });
64 |
65 | describe('Changing options.doctypeKey', function () {
66 |
67 | var options = {compact: false, doctypeKey: 'doctype'.slice(0,3)};
68 | testItems('xml2js', options).forEach(function (test) {
69 | it(test.desc, function () {
70 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
71 | });
72 | });
73 |
74 | });
75 |
76 | describe('Changing options.commentKey', function () {
77 |
78 | var options = {compact: false, commentKey: 'comment'.slice(0,3)};
79 | testItems('xml2js', options).forEach(function (test) {
80 | it(test.desc, function () {
81 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
82 | });
83 | });
84 |
85 | });
86 |
87 | describe('Changing options.parentKey', function () {
88 |
89 | var options = {compact: false, parentKey: 'parent'.slice(0,3)};
90 | testItems('xml2js', options).forEach(function (test) {
91 | it(test.desc, function () {
92 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
93 | });
94 | });
95 |
96 | });
97 |
98 | describe('Changing options.typeKey', function () {
99 |
100 | var options = {compact: false, typeKey: 'type'.slice(0,3)};
101 | testItems('xml2js', options).forEach(function (test) {
102 | it(test.desc, function () {
103 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
104 | });
105 | });
106 |
107 | });
108 |
109 | describe('Changing options.nameKey', function () {
110 |
111 | var options = {compact: false, nameKey: 'name'.slice(0,3)};
112 | testItems('xml2js', options).forEach(function (test) {
113 | it(test.desc, function () {
114 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
115 | });
116 | });
117 |
118 | });
119 |
120 | describe('Changing options.elementsKey', function () {
121 |
122 | var options = {compact: false, elementsKey: 'elements'.slice(0,3)};
123 | testItems('xml2js', options).forEach(function (test) {
124 | it(test.desc, function () {
125 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
126 | });
127 | });
128 |
129 | });
130 |
131 | });
132 |
133 | describe('Changing default key names, options = {compact: true}', function () {
134 |
135 | describe('Changing options.declarationKey', function () {
136 |
137 | var options = {compact: true, declarationKey: 'declaration'.slice(0,3)};
138 | testItems('xml2js', options).forEach(function (test) {
139 | it(test.desc, function () {
140 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
141 | });
142 | });
143 |
144 | });
145 |
146 | describe('Changing options.instructionKey', function () {
147 |
148 | var options = {compact: true, instructionKey: 'instruction'.slice(0,3)};
149 | testItems('xml2js', options).forEach(function (test) {
150 | it(test.desc, function () {
151 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
152 | });
153 | });
154 |
155 | });
156 |
157 | describe('Changing options.attributesKey', function () {
158 |
159 | var options = {compact: true, attributesKey: 'attributes'.slice(0,3)};
160 | testItems('xml2js', options).forEach(function (test) {
161 | it(test.desc, function () {
162 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
163 | });
164 | });
165 |
166 | });
167 |
168 | describe('Changing options.textKey', function () {
169 |
170 | var options = {compact: true, textKey: 'text'.slice(0,3)};
171 | testItems('xml2js', options).forEach(function (test) {
172 | it(test.desc, function () {
173 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
174 | });
175 | });
176 |
177 | });
178 |
179 | describe('Changing options.cdataKey', function () {
180 |
181 | var options = {compact: true, cdataKey: 'cdata'.slice(0,3)};
182 | testItems('xml2js', options).forEach(function (test) {
183 | it(test.desc, function () {
184 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
185 | });
186 | });
187 |
188 | });
189 |
190 | describe('Changing options.doctypeKey', function () {
191 |
192 | var options = {compact: true, doctypeKey: 'doctype'.slice(0,3)};
193 | testItems('xml2js', options).forEach(function (test) {
194 | it(test.desc, function () {
195 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
196 | });
197 | });
198 |
199 | });
200 |
201 | describe('Changing options.commentKey', function () {
202 |
203 | var options = {compact: true, commentKey: 'comment'.slice(0,3)};
204 | testItems('xml2js', options).forEach(function (test) {
205 | it(test.desc, function () {
206 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
207 | });
208 | });
209 |
210 | });
211 |
212 | describe('Changing options.parentKey', function () {
213 |
214 | var options = {compact: true, parentKey: 'parent'.slice(0,3)};
215 | testItems('xml2js', options).forEach(function (test) {
216 | it(test.desc, function () {
217 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
218 | });
219 | });
220 |
221 | });
222 |
223 | describe('Changing options.typeKey', function () {
224 |
225 | var options = {compact: true, typeKey: 'type'.slice(0,3)};
226 | testItems('xml2js', options).forEach(function (test) {
227 | it(test.desc, function () {
228 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
229 | });
230 | });
231 |
232 | });
233 |
234 | describe('Changing options.nameKey', function () {
235 |
236 | var options = {compact: true, nameKey: 'name'.slice(0,3)};
237 | testItems('xml2js', options).forEach(function (test) {
238 | it(test.desc, function () {
239 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
240 | });
241 | });
242 |
243 | });
244 |
245 | describe('Changing options.elementsKey', function () {
246 |
247 | var options = {compact: true, elementsKey: 'elements'.slice(0,3)};
248 | testItems('xml2js', options).forEach(function (test) {
249 | it(test.desc, function () {
250 | expect(convert.xml2js(test.xml, options)).toEqual(test.js);
251 | });
252 | });
253 |
254 | });
255 |
256 | });
257 |
258 | });
259 |
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | export interface Attributes {
2 | [key: string]: string | number | undefined
3 | }
4 |
5 | export interface DeclarationAttributes {
6 | version?: string | number
7 | encoding?: 'utf-8' | string
8 | standalone?: 'yes' | 'no'
9 | }
10 |
11 | export interface ElementCompact {
12 | [key: string]: any
13 | _declaration?: {
14 | _attributes?: DeclarationAttributes
15 | }
16 | _instruction?: {
17 | [key: string]: string
18 | }
19 | _attributes?: Attributes
20 | _cdata?: string
21 | _doctype?: string
22 | _comment?: string
23 | _text?: string | number
24 | }
25 |
26 | export interface Element {
27 | declaration?: {
28 | attributes?: DeclarationAttributes
29 | }
30 | instruction?: string
31 | attributes?: Attributes
32 | cdata?: string
33 | doctype?: string
34 | comment?: string
35 | text?: string | number | boolean
36 | type?: string
37 | name?: string
38 | elements?: Array
39 | }
40 |
41 | declare namespace Options {
42 | interface XML2JSON extends XML2JS {
43 | spaces?: number | string
44 | }
45 |
46 | interface XML2JS extends ChangingKeyNames, IgnoreOptions {
47 | compact?: boolean
48 | trim?: boolean
49 | sanitize?: boolean
50 | nativeType?: boolean
51 | addParent?: boolean
52 | alwaysArray?: boolean | Array
53 | alwaysChildren?: boolean
54 | instructionHasAttributes?: boolean
55 | captureSpacesBetweenElements?: boolean
56 | doctypeFn?: (value: string, parentElement: object) => void;
57 | instructionFn?: (
58 | instructionValue: string,
59 | instructionName: string,
60 | parentElement: string
61 | ) => void;
62 | cdataFn?: (value: string, parentElement: object) => void;
63 | commentFn?: (value: string, parentElement: object) => void;
64 | textFn?: (value: string, parentElement: object) => void;
65 | instructionNameFn?: (
66 | instructionName: string,
67 | instructionValue: string,
68 | parentElement: string
69 | ) => void;
70 | elementNameFn?: (value: string, parentElement: object) => void;
71 | attributeNameFn?: (
72 | attributeName: string,
73 | attributeValue: string,
74 | parentElement: string
75 | ) => void;
76 | attributeValueFn?: (
77 | attributeValue: string,
78 | attributeName: string,
79 | parentElement: string
80 | ) => void;
81 | attributesFn?: (value: string, parentElement: string) => void;
82 | }
83 |
84 | interface JS2XML extends ChangingKeyNames, IgnoreOptions {
85 | spaces?: number | string
86 | compact?: boolean
87 | indentText?: boolean
88 | indentCdata?: boolean
89 | indentAttributes?: boolean
90 | indentInstruction?: boolean
91 | fullTagEmptyElement?: boolean
92 | noQuotesForNativeAttributes?: boolean
93 | doctypeFn?: (value: string, currentElementName: string, currentElementObj: object) => void;
94 | instructionFn?: (
95 | instructionValue: string,
96 | instructionName: string,
97 | currentElementName: string,
98 | currentElementObj: object
99 | ) => void;
100 | cdataFn?: (value: string, currentElementName: string, currentElementObj: object) => void;
101 | commentFn?: (value: string, currentElementName: string, currentElementObj: object) => void;
102 | textFn?: (value: string, currentElementName: string, currentElementObj: object) => void;
103 | instructionNameFn?: (
104 | instructionName: string,
105 | instructionValue: string,
106 | currentElementName: string,
107 | currentElementObj: object
108 | ) => void;
109 | elementNameFn?: (value: string, currentElementName: string, currentElementObj: object) => void;
110 | attributeNameFn?: (
111 | attributeName: string,
112 | attributeValue: string,
113 | currentElementName: string,
114 | currentElementObj: object
115 | ) => void;
116 | attributeValueFn?: (
117 | attributeValue: string,
118 | attributeName: string,
119 | currentElementName: string,
120 | currentElementObj: object
121 | ) => void;
122 | attributesFn?: (value: string, currentElementName: string, currentElementObj: object) => void;
123 | fullTagEmptyElementFn?: (currentElementName: string, currentElementObj: object) => void;
124 | }
125 |
126 | interface IgnoreOptions {
127 | ignoreDeclaration?: boolean
128 | ignoreInstruction?: boolean
129 | ignoreAttributes?: boolean
130 | ignoreComment?: boolean
131 | ignoreCdata?: boolean
132 | ignoreDoctype?: boolean
133 | ignoreText?: boolean
134 | }
135 |
136 | interface ChangingKeyNames {
137 | declarationKey?: string
138 | instructionKey?: string
139 | attributesKey?: string
140 | textKey?: string
141 | cdataKey?: string
142 | doctypeKey?: string
143 | commentKey?: string
144 | parentKey?: string
145 | typeKey?: string
146 | nameKey?: string
147 | elementsKey?: string
148 | }
149 | }
150 |
151 | export function js2xml(obj: Element | ElementCompact, options?: Options.JS2XML): string;
152 | export function json2xml(json: string, options?: Options.JS2XML): string;
153 | export function xml2json(xml: string, options?: Options.XML2JSON): string;
154 | export function xml2js(xml: string, options?: Options.XML2JS): Element | ElementCompact;
155 |
--------------------------------------------------------------------------------
/types/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "noImplicitAny": true,
6 | "strictNullChecks": true,
7 | "noEmit": true
8 | },
9 | "files": [
10 | "./index.d.ts",
11 | "./xml-js-tests.ts"
12 | ],
13 | "compileOnSave": false
14 | }
--------------------------------------------------------------------------------
/types/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "xml-js",
3 | "main": "index.d.ts"
4 | }
--------------------------------------------------------------------------------
/types/xml-js-tests.ts:
--------------------------------------------------------------------------------
1 | import { Element, ElementCompact } from './index'
2 | import * as convert from './index'
3 |
4 | // Declaration
5 | const declarationCompact1: ElementCompact = { _declaration: { _attributes: { version: 2 } }};
6 | const declarationCompact2: ElementCompact = { _declaration: { _attributes: { version: '1.0', encoding: 'utf-8', standalone: 'yes' }}};
7 | const declaration1: Element = { declaration: { }};
8 | const declaration2: Element = { declaration: { attributes: { version: '1.0', encoding: 'utf-8', standalone: 'yes', }}};
9 |
10 | // Processing Instruction
11 | const instructionCompact: ElementCompact = { _instruction: { go: 'there' }};
12 | const instruction: Element = { elements:[{ type: 'instruction', name: 'go', instruction: 'there' }]};
13 |
14 | // Comment
15 | const commentCompact: ElementCompact = { _comment : 'Hello, World!' };
16 | const comment: Element = { elements: [{ type: 'comment', comment: 'Hello, World!' }]};
17 |
18 | // CDATA
19 | const cdataCompact: ElementCompact = { _cdata: '' };
20 | const cdata: Element = { elements : [{ type: 'cdata', cdata: '' }]};
21 |
22 | // Element
23 | const elementCompact1: ElementCompact = { a: {} };
24 | const element1: Element = { elements:[{ type: 'element', name: 'a' }]};
25 |
26 | const elementCompact2: ElementCompact = { a: { _attributes: { x: '1.234', y:'It\'s', z: undefined }}};
27 | const element2: Element = { elements: [{ type: 'element', name: 'a', attributes: { x: '1.234', y: 'It\'s', z: undefined }}]};
28 |
29 | const elementCompact3: ElementCompact = { a: { _text: ' Hi ' }};
30 | const element3: Element = { elements:[{ type: 'element', name: 'a', elements: [{ type: 'text', text: ' Hi ' }]}]};
31 |
32 | const elementCompact4: ElementCompact = { a: {}, b: {} };
33 | const element4: Element = { elements:[{ type: 'element', name: 'a' }, { type: 'element', name: 'b' }]};
34 |
35 | const elementCompact5: ElementCompact = { a: { b: {} }};
36 | const element5: Element = { elements: [{ type: 'element', name: 'a', elements: [{ type: 'element', name: 'b' }]}]};
37 |
38 | const xml = `
39 |
40 |
41 | Happy
42 | Work
43 | Play
44 | `;
45 |
46 | // xml2js
47 | let jsResult1: any = convert.xml2js(xml, {compact:true});
48 | let jsResult2: any = convert.xml2js(xml, {compact:false});
49 |
50 | // xml2json
51 | let jsonResult1: string = convert.xml2json(xml, {compact:true, spaces:4});
52 | let jsonResult2: string = convert.xml2json(xml, {compact:false});
53 |
54 | // js2xml
55 | let xmlResult1: string = convert.js2xml({a:{}}, { compact:true, spaces:4});
56 | let xmlResult2: string = convert.js2xml({elements:[{type:'element', name:'a'}]}, {compact:false});
57 |
58 | // json2xml
59 | let xmlResult3: string = convert.json2xml('{"a":{}}', { compact:true, spaces:4});
60 | let xmlResult4: string = convert.json2xml('{"elements":[{"type":"element","name":"a"}]}', {compact:false});
61 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 | const UnminifiedWebpackPlugin = require('unminified-webpack-plugin');
4 |
5 | module.exports = {
6 | entry: {
7 | 'dist': './lib/index.js',
8 | 'doc': './lib/index.js'
9 | },
10 | output: {
11 | path: path.resolve(__dirname, '.'),
12 | filename: '[name]/xml-js.min.js',
13 | libraryTarget: 'window',
14 | // library: 'xmljs' // don't specify this
15 | },
16 | // module: {
17 | // rules: [
18 | // {
19 | // test: /\.(js)$/,
20 | // use: 'babel-loader'
21 | // }
22 | // ]
23 | // },
24 | plugins: [
25 | new webpack.optimize.UglifyJsPlugin(),
26 | new UnminifiedWebpackPlugin()
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------