11import '../../xml/nodes/node.dart' ;
2+ import '../../xml/utils/name.dart' ;
23import '../exceptions/evaluation_exception.dart' ;
34import '../grammars/parser.dart' ;
45import '../types/function.dart' ;
56import '../types/sequence.dart' ;
7+ import 'functions.dart' ;
68import 'namespaces.dart' ;
79
810/// Runtime execution context to evaluate XPath expressions.
911class XPathContext {
10- XPathContext (
12+ /// Creates an empty XPath context.
13+ XPathContext .empty (
1114 this .item, {
1215 this .position = 1 ,
1316 this .last = 1 ,
1417 this .variables = const {},
1518 this .functions = const {},
19+ this .namespaceUri,
20+ this .namespaceUris = const {},
1621 this .documents = const {},
17- this .namespaces = const {},
1822 this .onTraceCallback,
1923 });
2024
25+ /// Creates a canonical XPath context on [item] .
26+ XPathContext .canonical (this .item)
27+ : position = 1 ,
28+ last = 1 ,
29+ variables = const {},
30+ functions = standardFunctions,
31+ namespaceUri = xpathFnNamespace,
32+ namespaceUris = xpathNamespaceUris,
33+ documents = const {},
34+ onTraceCallback = null ;
35+
2136 /// Mutable context node.
2237 Object item;
2338
@@ -30,15 +45,18 @@ class XPathContext {
3045 /// User-defined variables.
3146 final Map <String , Object > variables;
3247
33- /// User-defined functions.
34- final Map <String , XPathFunction > functions;
48+ /// Available function definitions.
49+ final Map <XmlName , XPathFunction > functions;
50+
51+ /// Default namespace URI for function lookups.
52+ final String ? namespaceUri;
53+
54+ /// Namespace mapping from prefix to URIs.
55+ final Map <String , String > namespaceUris;
3556
3657 /// Available documents.
3758 final Map <String , XmlNode > documents;
3859
39- /// Available namespaces.
40- final Map <String , String > namespaces;
41-
4260 /// Callback to trace evaluation.
4361 final XPathTraceCallback ? onTraceCallback;
4462
@@ -50,27 +68,38 @@ class XPathContext {
5068 }
5169
5270 /// Looks up a XPath function with the given [name] .
53- XPathFunction getFunction (String name) {
54- final function = functions[name] ?? functions[ _resolveEqName (name)] ;
71+ XPathFunction getFunction (XmlName name) {
72+ final function = functions[name];
5573 if (function != null ) return function;
5674 throw XPathEvaluationException ('Unknown function: $name ' );
5775 }
5876
59- /// Creates a copy of the current context.
77+ /// Looks up a XPath function with the given [name] .
78+ XPathFunction getFunctionByString (String name) => getFunction (
79+ XmlName .parse (
80+ name,
81+ namespaceUri: namespaceUri,
82+ namespaceUris: namespaceUris,
83+ ),
84+ );
85+
86+ /// Creates a copy of this context.
6087 XPathContext copy ({
6188 Map <String , Object >? variables,
62- Map <String , XPathFunction >? functions,
89+ Map <XmlName , XPathFunction >? functions,
90+ String ? namespaceUri,
91+ Map <String , String >? namespaceUris,
6392 Map <String , XmlNode >? documents,
64- Map <String , String >? namespaces,
6593 XPathTraceCallback ? onTraceCallback,
66- }) => XPathContext (
94+ }) => XPathContext . empty (
6795 item,
6896 position: position,
6997 last: last,
70- variables: variables ?? this .variables,
71- functions: functions ?? this .functions,
72- documents: documents ?? this .documents,
73- namespaces: namespaces ?? this .namespaces,
98+ variables: _extend (this .variables, variables),
99+ functions: _extend (this .functions, functions),
100+ documents: _extend (this .documents, documents),
101+ namespaceUri: namespaceUri ?? this .namespaceUri,
102+ namespaceUris: _extend (this .namespaceUris, namespaceUris),
74103 onTraceCallback: onTraceCallback ?? this .onTraceCallback,
75104 );
76105
@@ -82,13 +111,8 @@ class XPathContext {
82111/// Function type for tracing evaluation.
83112typedef XPathTraceCallback = void Function (XPathSequence value, String ? label);
84113
85- /// Resolves a `Q{uri}local-name` EQName to its `prefix:local-name` form.
86- String ? _resolveEqName (String name) {
87- if (! name.startsWith ('Q{' )) return null ;
88- final end = name.indexOf ('}' );
89- if (end < 0 ) return null ;
90- final uri = name.substring (2 , end);
91- final localName = name.substring (end + 1 );
92- final prefix = standardNamespaces[uri];
93- return prefix != null ? '$prefix :$localName ' : null ;
114+ Map <K , V > _extend <K , V >(Map <K , V > original, Map <K , V >? other) {
115+ if (other == null || other.isEmpty) return original;
116+ if (original.isEmpty) return other;
117+ return {...original, ...other};
94118}
0 commit comments