Skip to content

Commit

Permalink
feat: add tagNameProcessor and attributeNameProcessor
Browse files Browse the repository at this point in the history
  • Loading branch information
lpatiny committed Oct 20, 2021
1 parent 89563c5 commit 1ed2965
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ object = {
| cdataTagName | If specified, parser parse CDATA as nested tag instead of adding it's value to parent tag. | `false` |
| arrayMode | When `false`, a tag with single occurrence is parsed as an object but as an array in case of multiple occurences. When `true`, a tag will be parsed as an array always excluding leaf nodes. When `strict`, all the tags will be parsed as array only. When instance of `RegEx`, only tags will be parsed as array that match the regex. When `function` a tag name is passed to the callback that can be checked. | `false` |
| tagValueProcessor | Process tag value during transformation. Like HTML decoding, word capitalization, etc. Applicable in case of string only. | `(value) => decoder.decode(value).replace(/\r/g, '')` |
| attributeValueProcessor | Process attribute value during transformation. Like HTML decoding, word capitalization, etc. Applicable in case of string only. | `(value) => value` |
| attributeValueProcessor | Process attribute value during transformation. Like HTML decoding, word capitalization, etc. | `(value) => value` |
| stopNodes | an array of tag names which are not required to be parsed. They are kept as Uint8Array. | `[]` |

## [API Documentation](https://cheminfo.github.io/arraybuffer-xml-parser/)
Expand Down
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,19 @@
},
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.15.4",
"@types/jest": "^27.0.1",
"@types/jest": "^27.0.2",
"cheminfo-build": "^1.1.11",
"eslint": "^7.32.0",
"eslint-config-cheminfo": "^5.4.0",
"eslint": "^8.0.1",
"eslint-config-cheminfo": "^7.1.1",
"he": "^1.2.0",
"iobuffer": "^5.0.3",
"jest": "^27.1.0",
"iobuffer": "^5.0.4",
"jest": "^27.3.1",
"pako": "^2.0.4",
"prettier": "^2.3.2",
"rollup": "^2.56.3",
"prettier": "^2.4.1",
"rollup": "^2.58.0",
"uint8-base64": "^0.1.1"
},
"dependencies": {
"dynamic-typing": "^0.1.2"
"dynamic-typing": "^0.1.3"
}
}
32 changes: 32 additions & 0 deletions src/__tests__/tagProcessors.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable camelcase */
/* eslint-disable no-tabs */
import he from 'he';

import { parse } from '../parse';

describe('XMLParser', () => {
it('tag name processor', () => {
const xmlData = `<?xml version='1.0'?>
<any_name>
<person>
end
</person>
</any_name>`;

const result = parse(xmlData, {
tagNameProcessor: (name) => name.toUpperCase(),
});
expect(result).toStrictEqual({ ANY_NAME: { PERSON: 'end' } });
});

it('attribute name processor', () => {
const xmlData = `<?xml version='1.0'?>
<ab param1="abc" param2="def">
</ab>`;

const result = parse(xmlData, {
attributeNameProcessor: (name) => name.toUpperCase(),
});
expect(result).toStrictEqual({ ab: { $PARAM1: 'abc', $PARAM2: 'def' } });
});
});
32 changes: 17 additions & 15 deletions src/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@ import { traversableToJSON } from './traversableToJSON';

/**
* Parse an ArrayBuffer or Uint8Array representing an XML
* @param {ArrayBuffer|Uint8Arra} xmlData
* @param {string|ArrayBuffer|Uint8Array} xmlData
* @param {object} [options={}]
* @param {string} [attributeNamePrefix='$']
* @param {boolean} [attributesNodeName=false]
* @param {string} [textNodeName='#text']
* @param {boolean} [trimValues=true] should we remove ascii < 32
* @param {boolean} [ignoreAttributes=false] skip attributes
* @param {boolean} [ignoreNameSpace=false]
* @param {boolean} [dynamicTypingAttributeValue=true] Parse attribute values that looks like number or boolean
* @param {boolean} [allowBooleanAttributes=false]
* @param {boolean} [dynamicTypingNodeValue=true] Parse tag values that looks like number or boolean
* @param {boolean} [arrayMode=false]
* @param {boolean} [cdataTagName=false]
* @param {function} [tagValueProcessor=(v, node) => decoder.decode(v)] Tag values can be modified during parsing. By default we decode the tag value (a Uint8Array) using TextDecoder
* @param {function} [attributeValueProcessor=(v) => v] Attribute values can be modified during parsing
* @param {boolean} [stopNodes=[]] prevent further parsing
* @param {string} [options.attributeNamePrefix='$']
* @param {boolean} [options.attributesNodeName=false]
* @param {string} [options.textNodeName='#text']
* @param {boolean} [options.trimValues=true] should we remove ascii < 32
* @param {boolean} [options.ignoreAttributes=false] skip attributes
* @param {boolean} [options.ignoreNameSpace=false]
* @param {boolean} [options.dynamicTypingAttributeValue=true] Parse attribute values that looks like number or boolean
* @param {boolean} [options.allowBooleanAttributes=false]
* @param {boolean} [options.dynamicTypingNodeValue=true] Parse tag values that looks like number or boolean
* @param {boolean} [options.arrayMode=false]
* @param {boolean} [options.cdataTagName=false]
* @param {function} [options.tagValueProcessor=(v, node) => decoder.decode(v)] Tag values can be modified during parsing. By default we decode the tag value (a Uint8Array) using TextDecoder
* @param {function} [options.attributeValueProcessor=(v) => v] Attribute values can be modified during parsing
* @param {function} [options.tagNameProcessor=(v) => v] Callback allowing to rename tag names
* @param {function} [options.attributeNameProcessor=(v) => v] Callback allowing to rename attribute name
* @param {boolean} [options.stopNodes=[]] prevent further parsing
*
* @returns {object}
*/
Expand Down
26 changes: 17 additions & 9 deletions src/traversableToJSON.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ import { isTagNameInArrayMode, merge, isEmptyObject } from './util';
* @returns
*/
export function traversableToJSON(node, options, parentTagName) {
const { dynamicTypingNodeValue, tagValueProcessor, arrayMode } = options;
const {
dynamicTypingNodeValue,
tagValueProcessor,
arrayMode,
tagNameProcessor,
attributeNameProcessor,
} = options;
const result = {};

if (tagValueProcessor) {
Expand Down Expand Up @@ -43,9 +49,12 @@ export function traversableToJSON(node, options, parentTagName) {
if (options.attributeNamePrefix) {
// need to rename the attributes
const renamedAttributes = {};
for (let key in node.attributes) {
renamedAttributes[options.attributeNamePrefix + key] =
node.attributes[key];
for (let attributeName in node.attributes) {
const newAttributeName = attributeNameProcessor
? attributeNameProcessor(attributeName)
: attributeName;
renamedAttributes[options.attributeNamePrefix + newAttributeName] =
node.attributes[attributeName];
}
attributes = renamedAttributes;
}
Expand All @@ -57,14 +66,13 @@ export function traversableToJSON(node, options, parentTagName) {
merge(result, attributes, arrayMode);
}

const keys = Object.keys(node.children);
for (let index = 0; index < keys.length; index++) {
const tagName = keys[index];
for (const tagName in node.children) {
const newTagName = tagNameProcessor ? tagNameProcessor(tagName) : tagName;
if (node.children[tagName] && node.children[tagName].length > 1) {
result[tagName] = [];
for (let tag in node.children[tagName]) {
if (Object.prototype.hasOwnProperty.call(node.children[tagName], tag)) {
result[tagName].push(
result[newTagName].push(
traversableToJSON(node.children[tagName][tag], options, tagName),
);
}
Expand All @@ -78,7 +86,7 @@ export function traversableToJSON(node, options, parentTagName) {
const asArray =
(arrayMode === true && typeof subResult === 'object') ||
isTagNameInArrayMode(tagName, arrayMode, parentTagName);
result[tagName] = asArray ? [subResult] : subResult;
result[newTagName] = asArray ? [subResult] : subResult;
}
}

Expand Down

0 comments on commit 1ed2965

Please sign in to comment.