fontoxpath
Version:
A minimalistic XPath 3.1 engine in JavaScript
86 lines (78 loc) • 2.7 kB
JavaScript
import Sequence from './dataTypes/Sequence';
import createAtomicValue from './dataTypes/createAtomicValue';
import ArrayValue from './dataTypes/ArrayValue';
import MapValue from './dataTypes/MapValue';
import createNodeValue from './dataTypes/createNodeValue';
import { trueBoolean, falseBoolean } from './dataTypes/createAtomicValue';
function adaptItemToXPathValue (value) {
switch (typeof value) {
case 'boolean':
return value ? trueBoolean : falseBoolean;
case 'number':
return createAtomicValue(value, 'xs:decimal');
case 'string':
return createAtomicValue(value, 'xs:string');
case 'object':
// Test if it is a node
if (value && value.nodeType) {
return createNodeValue(value);
}
if (Array.isArray(value)) {
return new ArrayValue(value.map(val => Sequence.singleton(adaptItemToXPathValue(val))));
}
// Make it a map
return new MapValue(Object.keys(value)
.map(key => ({
key: createAtomicValue(key, 'xs:string'),
value: Sequence.singleton(adaptItemToXPathValue(value[key]))
})));
}
throw new Error('Value ' + value + ' of type ' + typeof value + ' is not adaptable to an XPath value.');
}
function adaptJavaScriptValueToXPathValue (type, value) {
switch (type) {
case 'xs:boolean':
return value ? trueBoolean : falseBoolean;
case 'xs:string':
return createAtomicValue(value + '', 'xs:string');
case 'xs:double':
case 'xs:numeric':
return createAtomicValue(+value, 'xs:double');
case 'xs:decimal':
return createAtomicValue(+value, 'xs:decimal');
case 'xs:integer':
return createAtomicValue(value | 0, 'xs:integer');
case 'xs:float':
return createAtomicValue(+value, 'xs:float');
case 'node()':
throw new Error('XPath custom functions should not return a node, use traversals instead.');
case 'item()':
return adaptItemToXPathValue(value);
default:
throw new Error('Values of the type ' + type + ' is not expected to be returned from custom function.');
}
}
/**
* @param {?} value
* @param {string=} expectedType
*/
export default function adaptJavaScriptValueToXPath (value, expectedType) {
expectedType = expectedType || 'item()';
var parts = expectedType.match(/^([^+?*]*)([\+\*\?])?$/),
type = parts[1],
multiplicity = parts[2];
switch (multiplicity) {
case '?':
if (value === null) {
return Sequence.empty();
}
return Sequence.singleton(adaptJavaScriptValueToXPathValue(type, value));
case '+':
case '*': {
const convertedValues = value.map(adaptJavaScriptValueToXPathValue.bind(null, type));
return new Sequence(convertedValues);
}
default:
return Sequence.singleton(adaptJavaScriptValueToXPathValue(type, value));
}
}