Skip to content

Commit a797cfe

Browse files
- Moving back the ExprContext to xpath directory;
- Adding the `MatchResolver` class, since `Xslt` class should only work with the XSLT operations, not with XPath matches.
1 parent 624668f commit a797cfe

18 files changed

+137
-102
lines changed

src/xslt/expr-context.ts renamed to src/xpath/expr-context.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { DOM_DOCUMENT_NODE } from '../constants';
2-
import { BooleanValue } from '../xpath/values/boolean-value';
3-
import { NodeSetValue } from '../xpath/values/node-set-value';
4-
import { NumberValue } from '../xpath/values/number-value';
5-
import { StringValue } from '../xpath/values/string-value';
6-
import { TOK_NUMBER } from '../xpath/tokens';
2+
import { BooleanValue } from './values/boolean-value';
3+
import { NodeSetValue } from './values/node-set-value';
4+
import { NumberValue } from './values/number-value';
5+
import { StringValue } from './values/string-value';
6+
import { TOK_NUMBER } from './tokens';
77
import { XNode } from '../dom';
8-
import { XsltDecimalFormatSettings } from './xslt-decimal-format-settings';
8+
import { XsltDecimalFormatSettings } from '../xslt/xslt-decimal-format-settings';
99

1010
/** XPath expression evaluation context. An XPath context consists of a
1111
* DOM node, a list of DOM nodes that contains this node, a number

src/xpath/expressions/binary-expr.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { xmlValue } from "../../dom";
2-
import { ExprContext } from "../../xslt/expr-context";
2+
import { ExprContext } from "../expr-context";
33
import { BooleanValue } from "../values/boolean-value";
44
import { NumberValue } from "../values/number-value";
55
import { Expression } from "./expression";

src/xpath/expressions/function-call-expr.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ExprContext } from '../../xslt/expr-context';
1+
import { ExprContext } from '../expr-context';
22
import {
33
count,
44
generateId,

src/xpath/expressions/location-expr.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ExprContext } from "../../xslt/expr-context";
1+
import { ExprContext } from "../expr-context";
22
import { NodeSetValue } from "../values/node-set-value";
33
import { NodeTestAny } from "../node-tests/node-test-any";
44
import { xPathAxis } from "../tokens";

src/xpath/expressions/step-expr.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DOM_ATTRIBUTE_NODE } from '../../constants';
22
import { XNode } from '../../dom';
3-
import { ExprContext } from '../../xslt/expr-context';
3+
import { ExprContext } from '../expr-context';
44
import { NodeSetValue } from '../values/node-set-value';
55
import { NodeTestAny } from '../node-tests/node-test-any';
66
import { xPathAxis } from '../tokens';

src/xpath/functions/non-standard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { xmlValue } from "../../dom";
2-
import { ExprContext } from "../../xslt/expr-context";
2+
import { ExprContext } from "../expr-context";
33
import { NodeSetValue, StringValue } from "../values";
44
import { assert } from "./internal-functions";
55

src/xpath/functions/standard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { XNode, xmlValue } from "../../dom";
2-
import { ExprContext } from "../../xslt/expr-context";
2+
import { ExprContext } from "../expr-context";
33
import { XsltDecimalFormatSettings } from "../../xslt/xslt-decimal-format-settings";
44
import { BooleanValue, NodeSetValue, NumberValue, StringValue } from "../values";
55
import { assert, regExpEscape } from "./internal-functions";

src/xpath/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export * from '../xslt/expr-context';
1+
export * from './expr-context';
22
export * from './xpath';
33
export * from './xpath-token-rule';

src/xpath/match-resolver.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { XNode } from "../dom";
2+
import { ExprContext } from "./expr-context";
3+
import { LocationExpr, UnionExpr } from "./expressions";
4+
import { Expression } from "./expressions/expression";
5+
6+
/**
7+
* Class that resolves XPath expressions, returning nodes.
8+
*/
9+
export class MatchResolver {
10+
11+
/**
12+
* This class entry point.
13+
* @param expression The expression to be resolved.
14+
* @param context The Expression Context
15+
* @returns An array of nodes.
16+
*/
17+
expressionMatch(expression: Expression, context: ExprContext): XNode[] {
18+
if (expression instanceof LocationExpr) {
19+
return this.locationExpressionMatch(expression, context);
20+
}
21+
22+
if (expression instanceof UnionExpr) {
23+
return this.unionExpressionMatch(expression, context);
24+
}
25+
26+
// TODO: Other expressions
27+
return [];
28+
}
29+
30+
/**
31+
* Resolves a `LocationExpr`.
32+
* @param expression The Location Expression.
33+
* @param context The Expression Context.
34+
* @returns Either the results of a relative resolution, or the results of an
35+
* absolute resolution.
36+
*/
37+
private locationExpressionMatch(expression: LocationExpr, context: ExprContext) {
38+
if (expression === undefined || expression.steps === undefined || expression.steps.length <= 0) {
39+
throw new Error('Error resolving XSLT match: Location Expression should have steps.');
40+
}
41+
42+
if (expression.absolute) {
43+
return this.absoluteXsltMatch(expression, context);
44+
}
45+
46+
return this.relativeXsltMatch(expression, context);
47+
}
48+
49+
/**
50+
* Resolves a `UnionExpr`.
51+
* @param expression The Union Expression.
52+
* @param context The Expression Context.
53+
* @returns The concatenated result of evaluating the both sides of the expression.
54+
*/
55+
private unionExpressionMatch(expression: UnionExpr, context: ExprContext) {
56+
let expr1Nodes = this.expressionMatch(expression.expr1, context);
57+
return expr1Nodes.concat(this.expressionMatch(expression.expr2, context));
58+
}
59+
60+
/**
61+
* Finds all the nodes through absolute xPath search.
62+
* Returns only nodes that match either the context position node,
63+
* or an ancestor.
64+
* @param expression The Expression.
65+
* @param context The Expression Context.
66+
* @returns The list of found nodes.
67+
*/
68+
private absoluteXsltMatch(expression: LocationExpr, context: ExprContext): XNode[] {
69+
const clonedContext = context.clone([context.root], undefined, 0, undefined);
70+
const matchedNodes = expression.evaluate(clonedContext).nodeSetValue();
71+
const finalList = [];
72+
73+
for (let element of matchedNodes) {
74+
if (element.id === context.nodeList[context.position].id) {
75+
finalList.push(element);
76+
continue;
77+
}
78+
79+
if (element.getAncestorById(context.nodeList[context.position].id) !== undefined) {
80+
finalList.push(element);
81+
}
82+
}
83+
84+
return finalList;
85+
}
86+
87+
/**
88+
* Tries to find relative nodes from the actual context position.
89+
* If found nodes are already in the context, or if they are children of
90+
* nodes in the context, they are returned.
91+
* @param expression The expression used.
92+
* @param context The Expression Context.
93+
* @returns The list of found nodes.
94+
*/
95+
private relativeXsltMatch(expression: LocationExpr, context: ExprContext): XNode[] {
96+
// For some reason, XPath understands a default as 'child axis'.
97+
// There's no "self + siblings" axis, so what is expected at this point
98+
// is to have in the expression context the parent that should
99+
// have the nodes we are interested in.
100+
101+
const clonedContext = context.clone();
102+
let nodes = expression.evaluate(clonedContext).nodeSetValue();
103+
if (nodes.length === 1 && nodes[0].nodeName === '#document') {
104+
// As we don't work with the #document node directly, this part
105+
// returns its first sibling.
106+
// By the way, it should be *always* one sibling here.
107+
return [nodes[0].childNodes[0]];
108+
}
109+
110+
return nodes;
111+
}
112+
}

src/xpath/node-tests/node-test-comment.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { DOM_COMMENT_NODE } from "../../constants";
2-
import { ExprContext } from "../../xslt/expr-context";
2+
import { ExprContext } from "../expr-context";
33
import { NodeTest } from "./node-test";
44
import { BooleanValue } from "../values/boolean-value";
55

0 commit comments

Comments
 (0)