diff --git a/src/xpath/expr-context.ts b/src/xpath/expr-context.ts
index 60da862..d075a53 100644
--- a/src/xpath/expr-context.ts
+++ b/src/xpath/expr-context.ts
@@ -88,6 +88,7 @@ export class ExprContext {
constructor(
nodeList: XNode[],
outputNodeList: XNode[],
+ xsltVersion: '1.0' | '2.0' | '3.0' = '1.0',
opt_position?: number,
opt_outputPosition?: number,
opt_outputDepth?: number,
@@ -102,6 +103,8 @@ export class ExprContext {
) {
this.nodeList = nodeList;
this.outputNodeList = outputNodeList;
+ this.xsltVersion = xsltVersion;
+
this.position = opt_position || 0;
this.outputPosition = opt_outputPosition || 0;
@@ -158,6 +161,7 @@ export class ExprContext {
return new ExprContext(
opt_nodeList || this.nodeList,
opt_outputNodeList || this.outputNodeList,
+ this.xsltVersion,
typeof opt_position !== 'undefined' ? opt_position : this.position,
typeof opt_outputPosition !== 'undefined' ? opt_outputPosition : this.outputPosition,
this.outputDepth,
@@ -176,6 +180,7 @@ export class ExprContext {
return new ExprContext(
this.nodeList,
opt_outputNodeList || this.outputNodeList,
+ this.xsltVersion,
this.position,
typeof opt_outputPosition !== 'undefined' ? opt_outputPosition : this.outputPosition,
typeof opt_outputDepth !== 'undefined' ? opt_outputDepth : this.outputDepth,
diff --git a/src/xpath/expressions/function-call-expr.ts b/src/xpath/expressions/function-call-expr.ts
index af9505d..2690c58 100644
--- a/src/xpath/expressions/function-call-expr.ts
+++ b/src/xpath/expressions/function-call-expr.ts
@@ -35,6 +35,7 @@ import {
formatNumber
} from '../functions';
import { extCardinal, extIf, extJoin } from '../functions/non-standard';
+import { lowerCase, upperCase } from '../functions/standard-20';
import { BooleanValue } from '../values/boolean-value';
import { Expression } from './expression';
@@ -58,6 +59,7 @@ export class FunctionCallExpr extends Expression {
lang,
last,
'local-name': localName,
+ 'lower-case': lowerCase,
matches,
name: _name,
'namespace-uri': namespaceUri,
@@ -76,6 +78,7 @@ export class FunctionCallExpr extends Expression {
'string-length': stringLength,
translate,
true: _true,
+ 'upper-case': upperCase,
// TODO(mesch): The following functions are custom. There is a
// standard that defines how to add functions, which should be
diff --git a/src/xpath/functions/standard-20.ts b/src/xpath/functions/standard-20.ts
new file mode 100644
index 0000000..717c6fc
--- /dev/null
+++ b/src/xpath/functions/standard-20.ts
@@ -0,0 +1,15 @@
+import { ExprContext } from "../expr-context";
+import { StringValue } from "../values";
+import { assert } from "./internal-functions";
+
+export function upperCase(context: ExprContext) {
+ assert(['2.0', '3.0'].includes(context.xsltVersion));
+ const str: string = this.args[0].evaluate(context).stringValue();
+ return new StringValue(str.toUpperCase());
+}
+
+export function lowerCase(context: ExprContext) {
+ assert(['2.0', '3.0'].includes(context.xsltVersion));
+ const str: string = this.args[0].evaluate(context).stringValue();
+ return new StringValue(str.toLowerCase());
+}
diff --git a/src/xpath/values/boolean-value.ts b/src/xpath/values/boolean-value.ts
index d448347..0f75f48 100644
--- a/src/xpath/values/boolean-value.ts
+++ b/src/xpath/values/boolean-value.ts
@@ -9,7 +9,7 @@ export class BooleanValue implements NodeValue {
this.type = 'boolean';
}
- stringValue() {
+ stringValue(): string {
return `${this.value}`;
}
diff --git a/src/xpath/values/node-set-value.ts b/src/xpath/values/node-set-value.ts
index bde7def..2b6b631 100644
--- a/src/xpath/values/node-set-value.ts
+++ b/src/xpath/values/node-set-value.ts
@@ -10,7 +10,7 @@ export class NodeSetValue implements NodeValue {
this.type = 'node-set';
}
- stringValue() {
+ stringValue(): string {
if (this.value.length === 0) {
return '';
}
diff --git a/src/xpath/values/number-value.ts b/src/xpath/values/number-value.ts
index ef2dcad..37ea372 100644
--- a/src/xpath/values/number-value.ts
+++ b/src/xpath/values/number-value.ts
@@ -9,7 +9,7 @@ export class NumberValue implements NodeValue {
this.type = 'number';
}
- stringValue() {
+ stringValue(): string {
return `${this.value}`;
}
diff --git a/src/xpath/values/string-value.ts b/src/xpath/values/string-value.ts
index 573236d..b1f56df 100644
--- a/src/xpath/values/string-value.ts
+++ b/src/xpath/values/string-value.ts
@@ -9,8 +9,8 @@ export class StringValue implements NodeValue {
this.type = 'string';
}
- stringValue() {
- return this.value;
+ stringValue(): string {
+ return String(this.value);
}
booleanValue() {
diff --git a/tests/xpath/functions.test.tsx b/tests/xpath/functions.test.tsx
index dcd44d0..72be548 100644
--- a/tests/xpath/functions.test.tsx
+++ b/tests/xpath/functions.test.tsx
@@ -21,245 +21,268 @@ describe('XPath Functions', () => {
xmlParser = new XmlParser();
});
- it('current', () => {
- const xml = xmlParser.xmlParse(test);
- const xsltDefinition = xmlParser.xmlParse(
-
-
-
-
-
- );
-
- const xsltClass = new Xslt();
- const outXmlString = xsltClass.xsltProcess(
- xml,
- xsltDefinition
- );
-
- assert.equal(outXmlString, 'test');
- });
-
- describe('format-number', () => {
- xmlParser = new XmlParser();
- const xml = xmlParser.xmlParse();
-
- it('Trivial', () => {
+ describe('1.0', () => {
+ it('current', () => {
+ const xml = xmlParser.xmlParse(test);
const xsltDefinition = xmlParser.xmlParse(
-
+
);
const xsltClass = new Xslt();
- const outXmlString = xsltClass.xsltProcess(
- xml,
- xsltDefinition
- );
+ const outXmlString = xsltClass.xsltProcess(xml, xsltDefinition);
- assert.equal(outXmlString, '500100');
+ assert.equal(outXmlString, 'test');
});
- it('Decimal, only integer part', () => {
+ describe('format-number', () => {
+ xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse();
+
+ it('Trivial', () => {
+ const xsltDefinition = xmlParser.xmlParse(
+
+
+
+
+
+ );
+
+ const xsltClass = new Xslt();
+ const outXmlString = xsltClass.xsltProcess(xml, xsltDefinition);
+
+ assert.equal(outXmlString, '500100');
+ });
+
+ it('Decimal, only integer part', () => {
+ const xsltDefinition = xmlParser.xmlParse(
+
+
+
+
+
+ );
+
+ const xsltClass = new Xslt();
+ const outXmlString = xsltClass.xsltProcess(xml, xsltDefinition);
+
+ assert.equal(outXmlString, '500100');
+ });
+
+ it('Decimal, everything', () => {
+ const xsltDefinition = xmlParser.xmlParse(
+
+
+
+
+
+ );
+
+ const xsltClass = new Xslt();
+ const outXmlString = xsltClass.xsltProcess(xml, xsltDefinition);
+
+ assert.equal(outXmlString, '500100.2');
+ });
+
+ it('Decimal, mask with thousand separator, everything', () => {
+ const xsltDefinition = xmlParser.xmlParse(
+
+
+
+
+
+ );
+
+ const xsltClass = new Xslt();
+ const outXmlString = xsltClass.xsltProcess(xml, xsltDefinition);
+
+ assert.equal(outXmlString, '500,100.2');
+ });
+
+ it('Decimal, mask with filling zeroes', () => {
+ const xsltDefinition = xmlParser.xmlParse(
+
+
+
+
+
+ );
+
+ const xsltClass = new Xslt();
+ const outXmlString = xsltClass.xsltProcess(xml, xsltDefinition);
+
+ assert.equal(outXmlString, '500100.200');
+ });
+
+ it('NaN', () => {
+ const xsltDefinition = xmlParser.xmlParse(
+
+
+
+
+
+ );
+
+ const xsltClass = new Xslt();
+ const outXmlString = xsltClass.xsltProcess(xml, xsltDefinition);
+
+ assert.equal(outXmlString, 'NaN');
+ });
+ });
+
+ it('generate-id, trivial', () => {
+ const xml = xmlParser.xmlParse();
const xsltDefinition = xmlParser.xmlParse(
-
+
+
+
);
const xsltClass = new Xslt();
- const outXmlString = xsltClass.xsltProcess(
- xml,
- xsltDefinition
- );
- assert.equal(outXmlString, '500100');
+ const outXmlString = xsltClass.xsltProcess(xml, xsltDefinition);
+
+ assert.ok(outXmlString);
});
- it('Decimal, everything', () => {
+ it.skip('generate-id, complete', () => {
const xsltDefinition = xmlParser.xmlParse(
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
- const xsltClass = new Xslt();
- const outXmlString = xsltClass.xsltProcess(
- xml,
- xsltDefinition
+ const xml = xmlParser.xmlParse(
+
+ Then with expanded wings he steers his flight
+
+ "Incumbent on the Dusky Air"
+
+
+ Aloft, incumbent on the dusky Air
+
+ That felt unusual weight, till on dry Land
+
+ "He Lights"
+
+
+ He lights, if it were Land that ever burned
+
+ With solid, as the Lake with liquid fire
+
+ "The Lake with Liquid Fire"
+
+
+
+
+
);
- assert.equal(outXmlString, '500100.2');
+ const xsltClass = new Xslt();
+
+ const outXmlString = xsltClass.xsltProcess(xml, xsltDefinition);
+
+ // Uncomment below to see the results
+ // console.log(outXmlString);
+ assert.ok(!outXmlString);
});
- it('Decimal, mask with thousand separator, everything', () => {
- const xsltDefinition = xmlParser.xmlParse(
-
-
-
-
-
+ it('translate', () => {
+ const xmlString = (
+
+
+
+
);
- const xsltClass = new Xslt();
- const outXmlString = xsltClass.xsltProcess(
- xml,
- xsltDefinition
+ const xsltString = (
+
+
+
+
+
);
- assert.equal(outXmlString, '500,100.2');
- });
+ const xsltClass = new Xslt();
- it('Decimal, mask with filling zeroes', () => {
- const xsltDefinition = xmlParser.xmlParse(
-
-
-
-
-
- );
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
- const xsltClass = new Xslt();
- const outXmlString = xsltClass.xsltProcess(
- xml,
- xsltDefinition
- );
+ const outXmlString = xsltClass.xsltProcess(xml, xslt);
- assert.equal(outXmlString, '500100.200');
+ // Uncomment below to see the results
+ // console.log(outXmlString);
+ assert.ok(!outXmlString);
});
+ });
- it('NaN', () => {
- const xsltDefinition = xmlParser.xmlParse(
-
+ describe('2.0', () => {
+ it('upper-case', () => {
+ const xmlString = (
+
+ );
+
+ const xsltString = (
+
-
+
- );
+ )
const xsltClass = new Xslt();
- const outXmlString = xsltClass.xsltProcess(
- xml,
- xsltDefinition
- );
-
- assert.equal(outXmlString, 'NaN');
- });
- });
-
- it('generate-id, trivial', () => {
- const xml = xmlParser.xmlParse();
- const xsltDefinition = xmlParser.xmlParse(
-
-
-
-
-
-
-
- );
- const xsltClass = new Xslt();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
- const outXmlString = xsltClass.xsltProcess(
- xml,
- xsltDefinition
- );
+ const outXmlString = xsltClass.xsltProcess(xml, xslt);
- assert.ok(outXmlString);
- });
-
- it.skip('generate-id, complete', () => {
- const xsltDefinition = xmlParser.xmlParse(
-
-
+ assert.equal(outXmlString, 'LILY');
+ });
-
-
-
-
-
-
-
-
+ it('lower-case', () => {
+ const xmlString = (
+
+ );
-
-
-
-
-
+ const xsltString = (
+
+
+
+
+
+ )
-
- );
-
- const xml = xmlParser.xmlParse(
-
- Then with expanded wings he steers his flight
-
- "Incumbent on the Dusky Air"
-
-
- Aloft, incumbent on the dusky Air
-
- That felt unusual weight, till on dry Land
-
- "He Lights"
-
-
- He lights, if it were Land that ever burned
-
- With solid, as the Lake with liquid fire
-
- "The Lake with Liquid Fire"
-
-
-
-
-
- );
+ const xsltClass = new Xslt();
- const xsltClass = new Xslt();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
- const outXmlString = xsltClass.xsltProcess(
- xml,
- xsltDefinition
- );
+ const outXmlString = xsltClass.xsltProcess(xml, xslt);
- console.log(outXmlString)
- assert.ok(!outXmlString);
+ assert.equal(outXmlString, 'lily');
+ });
});
-
- it('translate', () => {
- const xmlString = (
-
-
-
-
- );
-
- const xsltString =
-
-
-
-
-
- const xsltClass = new Xslt();
-
- const xml = xmlParser.xmlParse(xmlString);
- const xslt = xmlParser.xmlParse(xsltString);
-
- const outXmlString = xsltClass.xsltProcess(
- xml,
- xslt
- );
-
- console.log(outXmlString)
- assert.ok(!outXmlString);
- })
});