Skip to content

Commit

Permalink
SNOW-830291, #506 XMLParser - initialisation with custom configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-pmotacki committed Jun 30, 2023
1 parent 0926a0f commit 9d5814d
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 150 deletions.
18 changes: 6 additions & 12 deletions lib/connection/result/column.js
Original file line number Diff line number Diff line change
Expand Up @@ -545,29 +545,23 @@ function convertRawTimestampHelper(
*/
function convertRawVariant(rawColumnValue, column, context)
{
var ret;
let ret;

// if the input is a non-empty string, convert it to a json object
if (Util.string.isNotNullOrEmpty(rawColumnValue))
{
try
{
if (Util.string.isNotNullOrEmpty(rawColumnValue)) {
try {
ret = GlobalConfig.jsonColumnVariantParser(rawColumnValue);
}
catch (jsonParseError)
{
try
{
catch (jsonParseError) {
try {
ret = GlobalConfig.xmlColumnVariantParser(rawColumnValue);
}
catch (xmlParseError)
{
catch (xmlParseError) {
Logger.getInstance().debug("Variant cannot be parsed neither as JSON: %s nor as XML: %s", jsonParseError.message, xmlParseError.message);
throw new Errors.VariantParseError(jsonParseError, xmlParseError);
}
}
}

return ret;
}

Expand Down
9 changes: 6 additions & 3 deletions lib/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,17 @@ function Core(options)
GlobalConfig.setJsonColumnVariantParser(jsonColumnVariantParser);
}

let xmlColumnVariantParser = options.xmlColumnVariantParser;
if (Util.exists(xmlColumnVariantParser))
{
const xmlColumnVariantParser = options.xmlColumnVariantParser;
const xmlParserConfig = options.xmlParserConfig;
if (Util.exists(xmlColumnVariantParser)) {
Errors.checkArgumentValid(Util.isFunction(xmlColumnVariantParser),
ErrorCodes.ERR_GLOBAL_CONFIGURE_INVALID_XML_PARSER);

GlobalConfig.setXmlColumnVariantParser(xmlColumnVariantParser);
}
else if (Util.exists(xmlParserConfig)) {
GlobalConfig.createXmlColumnVariantParserWithParameters(xmlParserConfig);
}
}
};

Expand Down
74 changes: 54 additions & 20 deletions lib/global_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,41 +180,75 @@ exports.jsonColumnVariantParser = rawColumnValue => vm.runInContext("(" + rawCol
*
* @param {function: (rawColumnValue: string) => any} value
*/
exports.setJsonColumnVariantParser = function (value)
{
exports.setJsonColumnVariantParser = function (value){
// validate input
Errors.assertInternal(Util.isFunction(value));

exports.jsonColumnVariantParser = value;
};

// The default XML parser
exports.xmlColumnVariantParser = rawColumnValue =>
{
// check if raw string is in XML format
// ensure each tag is enclosed and all attributes and elements are valid
// XMLValidator.validate returns true if valid, returns an error if invalid
var validateResult = XMLValidator.validate(rawColumnValue);
if (validateResult === true)
{
// use XML parser
return new XMLParser().parse(rawColumnValue);
}
else
{
throw new Error(validateResult.err.msg);
}
/**
* As a default we set parameters values identical like in fast-xml-parser lib defaults
* thus preserving backward compatibility if customer doesn't set custom configuration
*/
const defaultXmlParserConfiguration = {
ignoreAttributes: true,
alwaysCreateTextNode: false,
attributeNamePrefix: '@',
attributesGroupName: null
};

// The default XML parser
exports.xmlColumnVariantParser = getXmlColumnVariantParser(defaultXmlParserConfiguration);

/**
* Updates the value of the 'xmlColumnVariantParser' parameter.
* Return custom XmlParser configuration or default if not exists.
*
* @param {function: (rawColumnValue: string) => any} value
*/
exports.setXmlColumnVariantParser = function (value)
{
exports.setXmlColumnVariantParser = function (value){
// validate input
Errors.assertInternal(Util.isFunction(value));

exports.xmlColumnVariantParser = value;
};
/**
* Create and update the 'xmlColumnVariantParser' parameter using custom parser configuration.
*
* @param {function: (rawColumnValue: string) => any} params
*/
exports.createXmlColumnVariantParserWithParameters = function (params){
exports.xmlColumnVariantParser = getXmlColumnVariantParser(params);
};

/**
* Create XMlParser with custom configuration.
* Parametrs that you can override:
* ignoreAttributes - default true,
* attributeNamePrefix - default '@',
* attributesGroupName - default null,
* alwaysCreateTextNode - default false
*
* @param {object} config
*/
function getXmlColumnVariantParser(config) {
const parserConfiguration = {
ignoreAttributes: config && config.ignoreAttributes !== undefined && config.ignoreAttributes !== null ? config.ignoreAttributes : defaultXmlParserConfiguration.ignoreAttributes,
attributeNamePrefix: config && config.attributeNamePrefix !== undefined && config.attributeNamePrefix !== null ? config.attributeNamePrefix : defaultXmlParserConfiguration.attributeNamePrefix,
attributesGroupName: config && config.attributesGroupName !== undefined && config.attributesGroupName !== null ? config.attributesGroupName : defaultXmlParserConfiguration.attributesGroupName,
alwaysCreateTextNode: config && config.alwaysCreateTextNode !== undefined && config.alwaysCreateTextNode !== null ? config.alwaysCreateTextNode : defaultXmlParserConfiguration.alwaysCreateTextNode,
};
return rawColumnValue => {
// check if raw string is in XML format
// ensure each tag is enclosed and all attributes and elements are valid
// XMLValidator.validate returns true if valid, returns an error if invalid
const validateResult = XMLValidator.validate(rawColumnValue);
if (validateResult === true) {
// use XML parser
return new XMLParser(parserConfiguration).parse(rawColumnValue);
} else {
throw new Error(validateResult.err.msg);
}
};
}
Loading

0 comments on commit 9d5814d

Please sign in to comment.