新增调试信息

This commit is contained in:
2025-10-27 22:15:25 +08:00
parent ae62457d8c
commit 04642cb2f0
5479 changed files with 683397 additions and 3450 deletions
+133
View File
@@ -0,0 +1,133 @@
## 4.0.2
- Update dependencies
- Export options interfaces in main module
- Update example to include root attribute
## 4.0.1
- Update dependencies
- Use ESLint instead of TSLint
- Use npm instead of gulp
## 4.0.0
- Do not indent multi-line strings
- Use self-closing tags, unless otherwise specified
- Add option to automatically replace invalid characters with U+FFFD
- Add option to suppress certain values from output
- Add support for adding to existing xmlcreate object
- Remove certain unnecessary validation rules
- Bug fixes
- Correct errors in documentation
## 3.0.0
- Bug fixes
- Add null and undefined in type declarations
- Remove explicit engines requirement
## 2.0.2
- Bug fixes
## 2.0.1
- Remove unnecessary development dependencies from npm shrinkwrap
## 2.0.0
- Re-write in TypeScript
- Re-write to use xmlcreate (greatly simplifies module source)
- Added support for the ECMAScript 2015 Map and Set objects
- New method of calling module:
```javascript
var js2xmlparser = require("js2xmlparser");
var root = "root";
var data = {hello: "world"};
var options = {};
// old method (no longer works):
// js2xmlparser(root, data, options);
// new method:
js2xmlparser.parse(root, data, options);
```
- New options and changes to functionality of some existing options:
- `declaration` contains additional options
- `attributeString` has additional functionality
- `valueString` has additional functionality
- The functionality provided by `prettyPrinting` is now provided by the new
`format` option, which contains additional options
- `arrayMap` is now `wrapHandlers` to reflect the fact that wrapping is
provided for both arrays and ES2015 sets
- `convertMap` is now `typeHandlers` to match the name change to `arrayMap`
- The functionality provided by `useCDATA` is now provided by the new
`cdataInvalidChars` and `cdataKeys` options, which also provide additional
functionality
- Added support for document type definitions using the `dtd` option
## 1.0.0
- First stable release
- Add arrayMap feature
- Switch to semantic versioning
- Switch to Apache 2.0 license
## 0.1.9
- Fix error in example.js
## 0.1.8
- Reconcile readme and tests with examples
## 0.1.7
- Added .gitattributes to .gitignore file
- Minor tweaks to examples
## 0.1.6
- Addition of alias string option
- Minor changes to examples
- Minor fixes to tests
## 0.1.5
- Bug fixes
- Minor changes to examples
## 0.1.4
- Removed callFunctions option (functionality already provided by convertMap option)
- Removed wrapArray option (functionality already provided by existing array functionality)
- Escape numbers when at tbe beginning of an element name
- Edits to documentation
- Added tests
- Added copyright headers to individual JS files
## 0.1.3
- Fixed crash when undefined objects are converted to strings
- Added callFunctions option
- Added wrapArray option
- Added useCDATA option
- Added convertMap option
- Added copyright year and "and other contributors" to license
## 0.1.2
- Fixed crash when null objects are converted to strings
## 0.1.1
- Fixed accidental truncation of XML when pretty-printing is disabled
- Removed copyright year from license
## 0.1.0
- Initial release
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+10
View File
@@ -0,0 +1,10 @@
js2xmlparser
Copyright (C) 2016-2021 Michael Kourlas
The following components are provided under the Apache License, version 2.0
(https://www.apache.org/licenses/LICENSE-2.0):
xmlcreate
Copyright (C) 2016-2021 Michael Kourlas
The text of the Apache License 2.0 can be found in the LICENSE file.
+155
View File
@@ -0,0 +1,155 @@
# js2xmlparser
[![Node.js CI](https://github.com/michaelkourlas/node-js2xmlparser/actions/workflows/node.js.yml/badge.svg)](https://github.com/michaelkourlas/node-js2xmlparser/actions/workflows/node.js.yml)
[![npm version](https://badge.fury.io/js/js2xmlparser.svg)](https://badge.fury.io/js/js2xmlparser)
## Overview
js2xmlparser is a Node.js module that parses JavaScript objects into XML.
## Features
Since XML is a data-interchange format, js2xmlparser is designed primarily for
JSON-type objects, arrays and primitive data types, like many of the other
JavaScript to XML parsers currently available for Node.js.
However, js2xmlparser is capable of parsing any object, including native
JavaScript objects such as `Date` and `RegExp`, by taking advantage of each
object's `toString` function or, if this function does not exist, the `String`
constructor.
js2xmlparser also has support for the `Map` and `Set` objects introduced in
ECMAScript 2015, treating them as JSON-type objects and arrays respectively.
Support for `Map`s is necessary to generate XML with elements in a specific
order, since JSON-type objects do not guarantee insertion order. `Map` keys are
always converted to strings using the method described above.
js2xmlparser also supports a number of constructs unique to XML:
- attributes (through an attribute property in objects)
- mixed content (through value properties in objects)
- multiple elements with the same name (through arrays)
js2xmlparser can also pretty-print the XML it outputs.
## Installation
The easiest way to install js2xmlparser is using npm:
```
npm install js2xmlparser
```
You can also build js2xmlparser from source using npm:
```
git clone https://github.com/michaelkourlas/node-js2xmlparser.git
npm install
npm run-script build
```
The `build` script will build the production variant of js2xmlparser, run all
tests, and build the documentation.
You can build the production variant without running tests using the script
`prod`. You can also build the development version using the script `dev`.
The only difference between the two is that the development version includes
source maps.
## Usage
The documentation for the current version is available [here](http://www.kourlas.com/node-js2xmlparser/docs/4.0.2/).
You can also build the documentation using npm:
```
npm run-script docs
```
## Examples
The following example illustrates the basic usage of js2xmlparser:
```javascript
var js2xmlparser = require("js2xmlparser");
var obj = {
"@": {
type: "natural",
},
firstName: "John",
lastName: "Smith",
dateOfBirth: new Date(1964, 7, 26),
address: {
"@": {
type: "home",
},
streetAddress: "3212 22nd St",
city: "Chicago",
state: "Illinois",
zip: 10000,
},
phone: [
{
"@": {
type: "home",
},
"#": "123-555-4567",
},
{
"@": {
type: "cell",
},
"#": "890-555-1234",
},
{
"@": {
type: "work",
},
"#": "567-555-8901",
},
],
email: "john@smith.com",
};
console.log(js2xmlparser.parse("person", obj));
```
This example produces the following XML:
```xml
<?xml version='1.0'?>
<person type='natural'>
<firstName>John</firstName>
<lastName>Smith</lastName>
<dateOfBirth>Wed Aug 26 1964 00:00:00 GMT-0400 (Eastern Summer Time)</dateOfBirth>
<address type='home'>
<streetAddress>3212 22nd St</streetAddress>
<city>Chicago</city>
<state>Illinois</state>
<zip>10000</zip>
</address>
<phone type='home'>123-555-4567</phone>
<phone type='cell'>890-555-1234</phone>
<phone type='work'>567-555-8901</phone>
<email>john@smith.com</email>
</person>
```
Additional examples can be found in the examples directory.
## Tests
js2xmlparser includes a set of tests to verify core functionality. You can run
the tests using npm:
```
npm run-script test-prod
```
The only difference between the `test-prod` and `test-dev` scripts is that the
development version includes source maps.
## License
js2xmlparser is licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).
+49
View File
@@ -0,0 +1,49 @@
/**
* Copyright (C) 2016-2020 Michael Kourlas
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { XmlElement } from "xmlcreate";
import { IOptions } from "./options";
export { IOptions, IDeclarationOptions, IDtdOptions, IFormatOptions, ITypeHandlers, IWrapHandlers, } from "./options";
/**
* Indicates that an object of a particular type should be suppressed from the
* XML output.
*
* See the `typeHandlers` property in {@link IOptions} for more details.
*/
export declare class Absent {
private static _instance;
private constructor();
/**
* Returns the sole instance of Absent.
*/
static get instance(): Absent;
}
/**
* Converts the specified object to XML and adds the XML representation to the
* specified XmlElement object using the specified options.
*
* This function does not add a root element. In addition, it does not add an
* XML declaration or DTD, and the associated options in {@link IOptions} are
* ignored. If desired, these must be added manually.
*/
export declare function parseToExistingElement(element: XmlElement<unknown>, object: unknown, options?: IOptions): void;
/**
* Returns a XML string representation of the specified object using the
* specified options.
*
* `root` is the name of the root XML element. When the object is converted
* to XML, it will be a child of this root element.
*/
export declare function parse(root: string, object: unknown, options?: IOptions): string;
+282
View File
@@ -0,0 +1,282 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parse = exports.parseToExistingElement = exports.Absent = void 0;
/**
* Copyright (C) 2016-2020 Michael Kourlas
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var xmlcreate_1 = require("xmlcreate");
var options_1 = require("./options");
var utils_1 = require("./utils");
/**
* Indicates that an object of a particular type should be suppressed from the
* XML output.
*
* See the `typeHandlers` property in {@link IOptions} for more details.
*/
var Absent = /** @class */ (function () {
function Absent() {
}
Object.defineProperty(Absent, "instance", {
/**
* Returns the sole instance of Absent.
*/
get: function () {
return Absent._instance;
},
enumerable: false,
configurable: true
});
Absent._instance = new Absent();
return Absent;
}());
exports.Absent = Absent;
/**
* Gets the type handler associated with a value.
*/
function getHandler(value, options) {
var type = Object.prototype.toString.call(value);
var handler;
if (Object.prototype.hasOwnProperty.call(options.typeHandlers, "*")) {
handler = options.typeHandlers["*"];
}
if (Object.prototype.hasOwnProperty.call(options.typeHandlers, type)) {
handler = options.typeHandlers[type];
}
return handler;
}
/**
* Parses a string into XML and adds it to the parent element or attribute.
*/
function parseString(str, parentElement, options) {
var requiresCdata = function (s) {
return ((options.cdataInvalidChars &&
(s.indexOf("<") !== -1 || s.indexOf("&") !== -1)) ||
options.cdataKeys.indexOf(parentElement.name) !== -1 ||
options.cdataKeys.indexOf("*") !== -1);
};
if (parentElement instanceof xmlcreate_1.XmlElement) {
if (requiresCdata(str)) {
var cdataStrs = str.split("]]>");
for (var i = 0; i < cdataStrs.length; i++) {
if (requiresCdata(cdataStrs[i])) {
parentElement.cdata({
charData: cdataStrs[i],
replaceInvalidCharsInCharData: options.replaceInvalidChars,
});
}
else {
parentElement.charData({
charData: cdataStrs[i],
replaceInvalidCharsInCharData: options.replaceInvalidChars,
});
}
if (i < cdataStrs.length - 1) {
parentElement.charData({
charData: "]]>",
replaceInvalidCharsInCharData: options.replaceInvalidChars,
});
}
}
}
else {
parentElement.charData({
charData: str,
replaceInvalidCharsInCharData: options.replaceInvalidChars,
});
}
}
else {
parentElement.text({
charData: str,
replaceInvalidCharsInCharData: options.replaceInvalidChars,
});
}
}
/**
* Parses an attribute into XML and adds it to the parent element.
*/
function parseAttribute(name, value, parentElement, options) {
var attribute = parentElement.attribute({
name: name,
replaceInvalidCharsInName: options.replaceInvalidChars,
});
parseString((0, utils_1.stringify)(value), attribute, options);
}
/**
* Parses an object or Map entry into XML and adds it to the parent element.
*/
function parseObjectOrMapEntry(key, value, parentElement, options) {
// Alias key
if (key === options.aliasString) {
parentElement.name = (0, utils_1.stringify)(value);
return;
}
// Attributes key
if (key.indexOf(options.attributeString) === 0 && (0, utils_1.isObject)(value)) {
for (var _i = 0, _a = Object.keys(value); _i < _a.length; _i++) {
var subkey = _a[_i];
parseAttribute(subkey, (0, utils_1.stringify)(value[subkey]), parentElement, options);
}
return;
}
// Value key
if (key.indexOf(options.valueString) === 0) {
parseValue(key, (0, utils_1.stringify)(value), parentElement, options);
return;
}
// Standard handling (create new element for entry)
var element = parentElement;
if (!(0, utils_1.isArray)(value) && !(0, utils_1.isSet)(value)) {
// If handler for value returns absent, then do not add element
var handler = getHandler(value, options);
if (!(0, utils_1.isUndefined)(handler)) {
if (handler(value) === Absent.instance) {
return;
}
}
element = parentElement.element({
name: key,
replaceInvalidCharsInName: options.replaceInvalidChars,
useSelfClosingTagIfEmpty: options.useSelfClosingTagIfEmpty,
});
}
parseValue(key, value, element, options);
}
/**
* Parses an Object or Map into XML and adds it to the parent element.
*/
function parseObjectOrMap(objectOrMap, parentElement, options) {
if ((0, utils_1.isMap)(objectOrMap)) {
objectOrMap.forEach(function (value, key) {
parseObjectOrMapEntry((0, utils_1.stringify)(key), value, parentElement, options);
});
}
else {
for (var _i = 0, _a = Object.keys(objectOrMap); _i < _a.length; _i++) {
var key = _a[_i];
parseObjectOrMapEntry(key, objectOrMap[key], parentElement, options);
}
}
}
/**
* Parses an array or Set into XML and adds it to the parent element.
*/
function parseArrayOrSet(key, arrayOrSet, parentElement, options) {
var arrayNameFunc;
if (Object.prototype.hasOwnProperty.call(options.wrapHandlers, "*")) {
arrayNameFunc = options.wrapHandlers["*"];
}
if (Object.prototype.hasOwnProperty.call(options.wrapHandlers, key)) {
arrayNameFunc = options.wrapHandlers[key];
}
var arrayKey = key;
var arrayElement = parentElement;
if (!(0, utils_1.isUndefined)(arrayNameFunc)) {
var arrayNameFuncKey = arrayNameFunc(arrayKey, arrayOrSet);
if (!(0, utils_1.isNull)(arrayNameFuncKey)) {
arrayKey = arrayNameFuncKey;
arrayElement = parentElement.element({
name: key,
replaceInvalidCharsInName: options.replaceInvalidChars,
useSelfClosingTagIfEmpty: options.useSelfClosingTagIfEmpty,
});
}
}
arrayOrSet.forEach(function (item) {
var element = arrayElement;
if (!(0, utils_1.isArray)(item) && !(0, utils_1.isSet)(item)) {
// If handler for value returns absent, then do not add element
var handler = getHandler(item, options);
if (!(0, utils_1.isUndefined)(handler)) {
if (handler(item) === Absent.instance) {
return;
}
}
element = arrayElement.element({
name: arrayKey,
replaceInvalidCharsInName: options.replaceInvalidChars,
useSelfClosingTagIfEmpty: options.useSelfClosingTagIfEmpty,
});
}
parseValue(arrayKey, item, element, options);
});
}
/**
* Parses an arbitrary JavaScript value into XML and adds it to the parent
* element.
*/
function parseValue(key, value, parentElement, options) {
// If a handler for a particular type is user-defined, use that handler
// instead of the defaults
var handler = getHandler(value, options);
if (!(0, utils_1.isUndefined)(handler)) {
value = handler(value);
}
if ((0, utils_1.isObject)(value) || (0, utils_1.isMap)(value)) {
parseObjectOrMap(value, parentElement, options);
return;
}
if ((0, utils_1.isArray)(value) || (0, utils_1.isSet)(value)) {
parseArrayOrSet(key, value, parentElement, options);
return;
}
parseString((0, utils_1.stringify)(value), parentElement, options);
}
/**
* Converts the specified object to XML and adds the XML representation to the
* specified XmlElement object using the specified options.
*
* This function does not add a root element. In addition, it does not add an
* XML declaration or DTD, and the associated options in {@link IOptions} are
* ignored. If desired, these must be added manually.
*/
function parseToExistingElement(element, object, options) {
var opts = new options_1.Options(options);
parseValue(element.name, object, element, opts);
}
exports.parseToExistingElement = parseToExistingElement;
/**
* Returns a XML string representation of the specified object using the
* specified options.
*
* `root` is the name of the root XML element. When the object is converted
* to XML, it will be a child of this root element.
*/
function parse(root, object, options) {
var opts = new options_1.Options(options);
var document = new xmlcreate_1.XmlDocument({
validation: opts.validation,
});
if (opts.declaration.include) {
document.decl(opts.declaration);
}
if (opts.dtd.include) {
document.dtd({
// Validated in options.ts
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
name: opts.dtd.name,
pubId: opts.dtd.pubId,
sysId: opts.dtd.sysId,
});
}
var rootElement = document.element({
name: root,
replaceInvalidCharsInName: opts.replaceInvalidChars,
useSelfClosingTagIfEmpty: opts.useSelfClosingTagIfEmpty,
});
parseToExistingElement(rootElement, object, options);
return document.toString(opts.format);
}
exports.parse = parse;
+477
View File
@@ -0,0 +1,477 @@
/**
* Copyright (C) 2016-2020 Michael Kourlas
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* The options associated with parsing an object and formatting the resulting
* XML.
*/
export interface IOptions {
/**
* If an object or map contains a key that, when converted to a string,
* is equal to the value of `aliasString`, then the name of the XML element
* containing the object will be replaced with the value associated with
* said key.
*
* For example, if `aliasString` is `"="`, then the following object:
* ```javascript
* {
* "abc": {
* "=": "def"
* "#": "ghi"
* }
* }
* ```
* will result in the following XML for a root element named `"root"`:
* ```xml
* <root>
* <def>ghi</def>
* </root>
* ```
*
* The default alias string is `"="`.
*/
aliasString?: string;
/**
* If an object or map contains a key that, when converted to a string,
* begins with the value of `attributeString`, then the value mapped by
* said key will be interpreted as attributes for the XML element for that
* object.
*
* The keys of the value of `attributeString` are interpreted as attribute
* names, while the values mapping to those keys are interpreted as
* attribute values.
*
* For example, if `attributeString` is `"@"`, then the following object:
* ```javascript
* {
* "abc": {
* "@1": {
* "ghi": "jkl",
* "mno": "pqr"
* },
* "stu": "vwx",
* "@2": {
* "yza": "bcd"
* },
* }
* }
* ```
* will result in the following XML for a root element named `"root"`:
* ```xml
* <root>
* <abc ghi='jkl' mno='pqr' yza='bcd'>
* <stu>vwx</stu>
* </abc>
* </root>
* ```
*
* The default attribute string is `"@"`.
*/
attributeString?: string;
/**
* Whether to enclose any text containing the characters `<` or `&`
* in CDATA sections. If this is false, these characters shall be replaced
* with XML escape characters instead.
*
* By default, this is disabled.
*/
cdataInvalidChars?: boolean;
/**
* If an object or map contains a key that, when converted to a string, is
* equal to an item in `cdataKeys`, then the value mapped by said key will
* be enclosed in a CDATA section.
*
* For example, if `cdataKeys` is:
* ```javascript
* [
* "abc"
* ]
* ```
* then the following object:
* ```javascript
* {
* "abc": "def&",
* "ghi": "jkl",
* "mno": "pqr<"
* }
* ```
* will result in the following XML for a root element named `"root"`:
* ```xml
* <root>
* <abc><![CDATA[def&]]></ghi>
* <ghi>jlk</ghi>
* <mno>pqr&lt;</mno>
* </root>
* ```
*
* If `cdataKeys` has a key named `"*"`, then that entry will match all
* keys.
*
* By default, this is an empty array.
*/
cdataKeys?: string[];
/**
* The options associated with the XML declaration.
*/
declaration?: IDeclarationOptions;
/**
* The options associated with the XML document type definition.
*/
dtd?: IDtdOptions;
/**
* The options associated with the formatting of the XML document.
*/
format?: IFormatOptions;
/**
* Whether to replace any characters that are not valid in XML in particular
* contexts with the Unicode replacement character, U+FFFD.
*
* At present this is limited to attribute names and values; element names
* and character data; CDATA sections; and comments. This may be extended
* in future.
*
* By default, this is disabled.
*/
replaceInvalidChars?: boolean;
/**
* If a value has a type (as defined by calling `Object.prototype.toString`
* on the value) equal to a key in `typeHandlers`, then said value will be
* replaced by the return value of the function mapped to by the key in
* `typeHandlers`. This function is called with the value as a parameter.
*
* If one of these functions returns the sole instance of {@link Absent},
* then the value will be suppressed from the XML output altogether.
*
* For example, if `typeHandlers` is:
* ```javascript
* {
* "[object Date]": function(value) {
* return value.getYear();
* },
* "[object Null]": function(value) {
* return Absent.instance;
* }
* }
* ```
* then the following object:
* ```javascript
* {
* "abc": new Date(2012, 10, 31),
* "def": null
* }
* ```
* will result in the following XML for a root element named `"root"`:
* ```xml
* <root>
* <abc>2012</abc>
* </root>
* ```
*
* If `typeHandlers` has a key named `"*"`, then that entry will match all
* values, unless there is a more specific entry.
*
* Note that normal parsing still occurs for the value returned by the
* function; it is not directly converted to a string.
*
* The default value is an empty object.
*/
typeHandlers?: ITypeHandlers;
/**
* Whether to use a self-closing tag for empty elements.
*
* For example, the following element will be used:
* ```xml
* <element/>
* ```
* instead of:
* ```xml
* <element></element>
* ```
*
* By default, this is enabled.
*/
useSelfClosingTagIfEmpty?: boolean;
/**
* Whether to throw an exception if basic XML validation fails while
* building the document.
*
* By default, this is enabled.
*/
validation?: boolean;
/**
* If an object or map contains a key that, when converted to a string,
* begins with the value of `valueString`, then the value mapped by said key
* will be represented as bare text within the XML element for that object.
*
* For example, if `valueString` is `"#"`, then the following object:
* ```javascript
* new Map([
* ["#1", "abc"],
* ["def", "ghi"],
* ["#2", "jkl"]
* ])
* ```
* will result in the following XML for a root element named `"root"`:
* ```xml
* <root>
* abc
* <def>ghi</def>
* jkl
* </root>
* ```
*
* The default value is `"#"`.
*/
valueString?: string;
/**
* If an object or map contains a key that, when converted to a string, is
* equal to a key in `wrapHandlers`, and the key in said object or map maps
* to an array or set, then all items in the array or set will be wrapped
* in an XML element with the same name as the key.
*
* The key in `wrapHandlers` must map to a function that is called with the
* key name, as well as the array or set, as parameters. This function must
* return a string or value that can be converted to a string, which will
* become the name for each XML element for each item in the array or set.
* Alternatively, this function may return `null` to indicate that no
* wrapping should occur.
*
* For example, if `wrapHandlers` is:
* ```javascript
* {
* "abc": function(key, value) {
* return "def";
* }
* }
* ```
* then the following object:
* ```javascript
* {
* "ghi": "jkl",
* "mno": {
* "pqr": ["s", "t"]
* },
* "uvw": {
* "abc": ["x", "y"]
* }
* }
* ```
* will result in the following XML for a root element named `"root"`:
* ```xml
* <root>
* <ghi>jkl</ghi>
* <mno>
* <pqr>s</pqr>
* <pqr>t</pqr>
* </mno>
* <uwv>
* <abc>
* <def>x</def>
* <def>y</def>
* </abc>
* </uwv>
* </root>
* ```
*
* If `wrapHandlers` has a key named `"*"`, then that entry will
* match all arrays and sets, unless there is a more specific entry.
*
* The default value is an empty object.
*/
wrapHandlers?: IWrapHandlers;
}
/**
* Implementation of the IOptions interface used to provide default values
* to fields.
*/
export declare class Options implements IOptions {
aliasString: string;
attributeString: string;
cdataInvalidChars: boolean;
cdataKeys: string[];
declaration: DeclarationOptions;
dtd: DtdOptions;
format: FormatOptions;
replaceInvalidChars: boolean;
typeHandlers: TypeHandlers;
useSelfClosingTagIfEmpty: boolean;
validation: boolean;
valueString: string;
wrapHandlers: WrapHandlers;
constructor(options?: IOptions);
}
/**
* The options associated with the XML declaration. An example of an XML
* declaration is as follows:
*
* ```xml
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* ```
*/
export interface IDeclarationOptions {
/**
* Whether to include a declaration in the generated XML. By default,
* one is included.
*/
include?: boolean;
/**
* The encoding attribute to be included in the declaration. If defined,
* this value must be a valid encoding. By default, no encoding attribute
* is included.
*/
encoding?: string;
/**
* The value of the standalone attribute to be included in the declaration.
* If defined, this value must be "yes" or "no". By default, no standalone
* attribute is included.
*/
standalone?: string;
/**
* The XML version to be included in the declaration. If defined, this
* value must be a valid XML version number. Defaults to "1.0".
*/
version?: string;
}
/**
* Implementation of the IDeclarationOptions interface used to provide default
* values to fields.
*/
export declare class DeclarationOptions implements IDeclarationOptions {
include: boolean;
encoding?: string;
standalone?: string;
version?: string;
constructor(declarationOptions?: IDeclarationOptions);
}
/**
* The options associated with the XML document type definition (DTD). An
* example of a DTD is as follows:
*
* ```xml
* <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
* "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
* ```
*/
export interface IDtdOptions {
/**
* Whether to include a DTD in the generated XML. By default, no DTD is
* included.
*/
include?: boolean;
/**
* The name of the DTD. This value cannot be left undefined if `include`
* is true.
*/
name?: string;
/**
* The system identifier of the DTD, excluding quotation marks. By default,
* no system identifier is included.
*/
sysId?: string;
/**
* The public identifier of the DTD, excluding quotation marks. If a public
* identifier is provided, a system identifier must be provided as well.
* By default, no public identifier is included.
*/
pubId?: string;
}
/**
* Implementation of the IDtdOptions interface used to provide default values
* to fields.
*/
export declare class DtdOptions implements IDtdOptions {
include: boolean;
name?: string;
sysId?: string;
pubId?: string;
constructor(validation: boolean, dtdOptions?: IDtdOptions);
}
/**
* The options associated with the formatting of the XML document.
*/
export interface IFormatOptions {
/**
* Whether double quotes or single quotes should be used in XML attributes.
* By default, single quotes are used.
*/
doubleQuotes?: boolean;
/**
* The indent string used for pretty-printing. The default indent string is
* four spaces.
*/
indent?: string;
/**
* The newline string used for pretty-printing. The default newline string
* is "\n".
*/
newline?: string;
/**
* Whether pretty-printing is enabled. By default, pretty-printing is
* enabled.
*/
pretty?: boolean;
}
/**
* Implementation of the IFormatOptions interface used to provide default values
* to fields.
*/
export declare class FormatOptions implements IFormatOptions {
doubleQuotes?: boolean;
indent?: string;
newline?: string;
pretty?: boolean;
constructor(formatOptions?: IFormatOptions);
}
/**
* Map for the `typeHandlers` property in the {@link IOptions} interface.
*/
export interface ITypeHandlers {
/**
* Mapping between the type of a value in an object to a function taking
* this value and returning a replacement value.
*/
[type: string]: (value: any) => unknown;
}
/**
* Implementation of the ITypeHandlers interface used to provide default values
* to fields.
*/
export declare class TypeHandlers implements ITypeHandlers {
[type: string]: (value: any) => unknown;
constructor(typeHandlers?: ITypeHandlers);
}
/**
* Map for the `wrapHandlers` property in the {@link IOptions} interface.
*/
export interface IWrapHandlers {
/**
* Mapping between the string version of a key in an object or map with a
* value that is an array or set to a function taking the string version
* of that key, as well as that array or set.
*
* This function returns either a string that will become the name for each
* XML element for each item in the array or set, or `null` to indicate that
* wrapping should not occur.
*/
[key: string]: (key: string, value: any) => string | null;
}
/**
* Implementation of the IWrapHandlers interface used to provide default values
* to fields.
*/
export declare class WrapHandlers implements IWrapHandlers {
[key: string]: (key: string, value: any) => string | null;
constructor(wrapHandlers?: IWrapHandlers);
}
+155
View File
@@ -0,0 +1,155 @@
"use strict";
/**
* Copyright (C) 2016-2020 Michael Kourlas
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.WrapHandlers = exports.TypeHandlers = exports.FormatOptions = exports.DtdOptions = exports.DeclarationOptions = exports.Options = void 0;
var utils_1 = require("./utils");
/**
* Implementation of the IOptions interface used to provide default values
* to fields.
*/
var Options = /** @class */ (function () {
function Options(options) {
if (options === void 0) { options = {}; }
this.aliasString = "=";
this.attributeString = "@";
this.cdataInvalidChars = false;
this.cdataKeys = [];
this.replaceInvalidChars = false;
this.useSelfClosingTagIfEmpty = true;
this.validation = true;
this.valueString = "#";
if (!(0, utils_1.isUndefined)(options.validation)) {
this.validation = options.validation;
}
if (!(0, utils_1.isUndefined)(options.aliasString)) {
this.aliasString = options.aliasString;
}
if (!(0, utils_1.isUndefined)(options.attributeString)) {
this.attributeString = options.attributeString;
}
if (!(0, utils_1.isUndefined)(options.cdataInvalidChars)) {
this.cdataInvalidChars = options.cdataInvalidChars;
}
if (!(0, utils_1.isUndefined)(options.cdataKeys)) {
this.cdataKeys = options.cdataKeys;
}
this.declaration = new DeclarationOptions(options.declaration);
this.dtd = new DtdOptions(this.validation, options.dtd);
this.format = new FormatOptions(options.format);
if (!(0, utils_1.isUndefined)(options.replaceInvalidChars)) {
this.replaceInvalidChars = options.replaceInvalidChars;
}
this.typeHandlers = new TypeHandlers(options.typeHandlers);
if (!(0, utils_1.isUndefined)(options.useSelfClosingTagIfEmpty)) {
this.useSelfClosingTagIfEmpty = options.useSelfClosingTagIfEmpty;
}
if (!(0, utils_1.isUndefined)(options.valueString)) {
this.valueString = options.valueString;
}
this.wrapHandlers = new WrapHandlers(options.wrapHandlers);
}
return Options;
}());
exports.Options = Options;
/**
* Implementation of the IDeclarationOptions interface used to provide default
* values to fields.
*/
var DeclarationOptions = /** @class */ (function () {
function DeclarationOptions(declarationOptions) {
if (declarationOptions === void 0) { declarationOptions = {}; }
this.include = true;
if (!(0, utils_1.isUndefined)(declarationOptions.include)) {
this.include = declarationOptions.include;
}
// Validation performed by xmlcreate
this.encoding = declarationOptions.encoding;
this.standalone = declarationOptions.standalone;
this.version = declarationOptions.version;
}
return DeclarationOptions;
}());
exports.DeclarationOptions = DeclarationOptions;
/**
* Implementation of the IDtdOptions interface used to provide default values
* to fields.
*/
var DtdOptions = /** @class */ (function () {
function DtdOptions(validation, dtdOptions) {
if (dtdOptions === void 0) { dtdOptions = {}; }
this.include = false;
if (!(0, utils_1.isUndefined)(dtdOptions.include)) {
this.include = dtdOptions.include;
}
if (validation && (0, utils_1.isUndefined)(dtdOptions.name) && this.include) {
throw new Error("options.dtd.name should be defined if" +
" options.dtd.include is true");
}
this.name = dtdOptions.name;
this.sysId = dtdOptions.sysId;
this.pubId = dtdOptions.pubId;
}
return DtdOptions;
}());
exports.DtdOptions = DtdOptions;
/**
* Implementation of the IFormatOptions interface used to provide default values
* to fields.
*/
var FormatOptions = /** @class */ (function () {
function FormatOptions(formatOptions) {
if (formatOptions === void 0) { formatOptions = {}; }
this.doubleQuotes = formatOptions.doubleQuotes;
this.indent = formatOptions.indent;
this.newline = formatOptions.newline;
this.pretty = formatOptions.pretty;
}
return FormatOptions;
}());
exports.FormatOptions = FormatOptions;
/**
* Implementation of the ITypeHandlers interface used to provide default values
* to fields.
*/
var TypeHandlers = /** @class */ (function () {
function TypeHandlers(typeHandlers) {
if (typeHandlers === void 0) { typeHandlers = {}; }
for (var key in typeHandlers) {
if (Object.prototype.hasOwnProperty.call(typeHandlers, key)) {
this[key] = typeHandlers[key];
}
}
}
return TypeHandlers;
}());
exports.TypeHandlers = TypeHandlers;
/**
* Implementation of the IWrapHandlers interface used to provide default values
* to fields.
*/
var WrapHandlers = /** @class */ (function () {
function WrapHandlers(wrapHandlers) {
if (wrapHandlers === void 0) { wrapHandlers = {}; }
for (var key in wrapHandlers) {
if (Object.prototype.hasOwnProperty.call(wrapHandlers, key)) {
this[key] = wrapHandlers[key];
}
}
}
return WrapHandlers;
}());
exports.WrapHandlers = WrapHandlers;
+32
View File
@@ -0,0 +1,32 @@
/**
* Copyright (C) 2016-2020 Michael Kourlas
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export declare function isUndefined(val: unknown): val is undefined;
export declare function isNull(val: unknown): val is null;
export declare function isObject(val: unknown): val is Record<string, unknown>;
export declare function isArray(val: unknown): val is unknown[];
export declare function isFunction(val: unknown): val is Function;
export declare function isSet(val: unknown): val is Set<unknown>;
export declare function isMap(val: unknown): val is Map<unknown, unknown>;
/**
* Returns a string representation of the specified value, as given by the
* value's toString() method (if it has one) or the global String() function
* (if it does not).
*
* @param value The value to convert to a string.
*
* @returns A string representation of the specified value.
*/
export declare function stringify(value: any): string;
+67
View File
@@ -0,0 +1,67 @@
"use strict";
/**
* Copyright (C) 2016-2020 Michael Kourlas
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringify = exports.isMap = exports.isSet = exports.isFunction = exports.isArray = exports.isObject = exports.isNull = exports.isUndefined = void 0;
function isUndefined(val) {
return Object.prototype.toString.call(val) === "[object Undefined]";
}
exports.isUndefined = isUndefined;
function isNull(val) {
return Object.prototype.toString.call(val) === "[object Null]";
}
exports.isNull = isNull;
function isObject(val) {
return Object.prototype.toString.call(val) === "[object Object]";
}
exports.isObject = isObject;
function isArray(val) {
return Object.prototype.toString.call(val) === "[object Array]";
}
exports.isArray = isArray;
// eslint-disable-next-line @typescript-eslint/ban-types
function isFunction(val) {
return Object.prototype.toString.call(val) === "[object Function]";
}
exports.isFunction = isFunction;
function isSet(val) {
return Object.prototype.toString.call(val) === "[object Set]";
}
exports.isSet = isSet;
function isMap(val) {
return Object.prototype.toString.call(val) === "[object Map]";
}
exports.isMap = isMap;
/**
* Returns a string representation of the specified value, as given by the
* value's toString() method (if it has one) or the global String() function
* (if it does not).
*
* @param value The value to convert to a string.
*
* @returns A string representation of the specified value.
*/
// eslint-disable-next-line max-len
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
function stringify(value) {
if (!isUndefined(value) && !isNull(value)) {
if (isFunction(value === null || value === void 0 ? void 0 : value.toString)) {
value = value.toString();
}
}
return String(value);
}
exports.stringify = stringify;
+65
View File
@@ -0,0 +1,65 @@
{
"name": "js2xmlparser",
"version": "4.0.2",
"description": "Parses JavaScript objects into XML",
"keywords": [
"convert",
"converter",
"javascript",
"js",
"json",
"object",
"objects",
"parse",
"parser",
"xml"
],
"license": "Apache-2.0",
"author": {
"name": "Michael Kourlas",
"email": "michael@kourlas.com"
},
"files": [
"lib",
"CHANGES.md",
"LICENSE",
"NOTICE",
"package.json",
"README.md"
],
"main": "./lib/main.js",
"typings": "./lib/main",
"repository": {
"type": "git",
"url": "git://github.com/michaelkourlas/node-js2xmlparser.git"
},
"scripts": {
"build": "npm run-script prod && npm run-script test-prod && npm run-script docs",
"clean": "rimraf lib",
"clean-docs": "rimraf docs",
"clean-test": "rimraf test/lib",
"dev": "npm run-script clean && npm run-script format && npm run-script lint && tsc -p tsconfig.json --sourceMap",
"docs": "npm run-script clean-docs && typedoc --out docs --excludePrivate src/main.ts",
"format": "prettier --write .",
"lint": "eslint . --ext .ts",
"prod": "npm run-script clean && npm run-script format && npm run-script lint && tsc -p tsconfig.json",
"test-dev": "npm run-script clean-test && tsc -p test/tsconfig.json --sourceMap && mocha --recursive test/lib",
"test-prod": "npm run-script clean-test && tsc -p test/tsconfig.json && mocha --recursive test/lib"
},
"dependencies": {
"xmlcreate": "^2.0.4"
},
"devDependencies": {
"@types/chai": "^4.2.22",
"@types/mocha": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.2.0",
"@typescript-eslint/parser": "^5.2.0",
"chai": "^4.3.4",
"eslint": "^8.1.0",
"mocha": "^9.1.3",
"prettier": "^2.4.1",
"rimraf": "^3.0.2",
"typedoc": "^0.22.7",
"typescript": "^4.4.4"
}
}