Project

Profile

Help

How to connect?
Download (14.8 KB) Statistics
| Branch: | Tag: | Revision:

he / latest9.1 / bn / csource / api / Saxon.Api / XPath.cs @ e090dcb1

1
using System;
2
using System.Collections;
3
using JConfiguration = net.sf.saxon.Configuration;
4
using JXPathEvaluator = net.sf.saxon.sxpath.XPathEvaluator;
5
using JItem = net.sf.saxon.om.Item;
6
using JSequenceExtent = net.sf.saxon.value.SequenceExtent;
7
using JValueRepresentation = net.sf.saxon.om.ValueRepresentation;
8
using JValue = net.sf.saxon.value.Value;
9
using JIndependentContext = net.sf.saxon.sxpath.IndependentContext;
10
using JXPathExpression = net.sf.saxon.sxpath.XPathExpression;
11
using JExpression = net.sf.saxon.expr.Expression;
12
using JXPathContext = net.sf.saxon.expr.XPathContext;
13
using JXPathDynamicContext = net.sf.saxon.sxpath.XPathDynamicContext;
14
using JXPathVariable = net.sf.saxon.sxpath.XPathVariable;
15

    
16

    
17
namespace Saxon.Api
18
{
19

    
20
    /// <summary>
21
    /// An XPathCompiler object allows XPath queries to be compiled.
22
    /// The compiler holds information that represents the static context
23
    /// for the expression.
24
    /// </summary>
25
    /// <remarks>
26
    /// <para>To construct an XPathCompiler, use the factory method
27
    /// <c>newXPathCompiler</c> on the <c>Processor</c> object.</para>
28
    /// <para>An XPathCompiler may be used repeatedly to compile multiple
29
    /// queries. Any changes made to the XPathCompiler (that is, to the
30
    /// static context) do not affect queries that have already been compiled.
31
    /// An XPathCompiler may be used concurrently in multiple threads, but
32
    /// it should not then be modified once initialized.</para>
33
    /// </remarks>
34

    
35
    [Serializable]
36
    public class XPathCompiler
37
    {
38

    
39
        private JConfiguration config;
40
        private JIndependentContext env;
41
        private ArrayList declaredVariables = new ArrayList();
42

    
43
        // internal constructor: the public interface is a factory method
44
        // on the Processor object
45

    
46
        internal XPathCompiler(JConfiguration config)
47
        {
48
            this.config = config;
49
            this.env = new JIndependentContext(config);
50
        }
51

    
52
        /// <summary>
53
        /// Declare a namespace for use by the XPath expression.
54
        /// </summary>
55
        /// <param name="prefix">The namespace prefix to be declared. Use
56
        /// a zero-length string to declare the default namespace (that is, the
57
        /// default namespace for elements and types).</param>
58
        /// <param name="uri">The namespace URI. It is possible to specify
59
        /// a zero-length string to "undeclare" a namespace.</param>
60

    
61
        public void DeclareNamespace(String prefix, String uri)
62
        {
63
            env.declareNamespace(prefix, uri);
64
        }
65

    
66
        /// <summary>
67
        /// Import schema definitions for a specified namespace. That is, add the element and attribute declarations and type definitions
68
        /// contained in a given namespace to the static context for the XPath expression.
69
        /// </summary>
70
        /// <remarks>
71
        /// <para>This method will not cause the schema to be loaded. That must be done separately, using the
72
        /// <c>SchemaManager</c>}. This method will not fail if the schema has not been loaded (but in that case
73
        /// the set of declarations and definitions made available to the XPath expression is empty). The schema
74
        /// document for the specified namespace may be loaded before or after this method is called.
75
        /// </para>
76
        /// <para>
77
        /// This method does not bind a prefix to the namespace. That must be done separately, using the
78
        /// <c>declareNamespace</c> method.
79
        /// </para>
80
        /// </remarks>
81
        /// <param name="uri">The namespace URI whose declarations and type definitions are to
82
        /// be made available for use within the XPath expression.</param>
83
        /// 
84

    
85
        public void ImportSchemaNamespace(String uri)
86
        {
87
            env.getImportedSchemaNamespaces().add(uri);
88
        }
89

    
90
        /// <summary>
91
        /// Declare a variable for use by the XPath expression. If the expression
92
        /// refers to any variables, then they must be declared here.
93
        /// </summary>
94
        /// <param name="name">The name of the variable, as a <c>QName</c></param>
95

    
96

    
97
        public void DeclareVariable(QName name)
98
        {
99
            JXPathVariable var = env.declareVariable(name.ToQNameValue());
100
            declaredVariables.Add(var);
101
        }
102

    
103
        /// <summary>
104
        /// The base URI of the expression, which forms part of the static context
105
        /// of the expression. This is used for resolving any relative URIs appearing
106
        /// within the expression, for example in references to library modules, schema
107
        /// locations, or as an argument to the <c>doc()</c> function.
108
        /// </summary>
109

    
110
        public String BaseUri
111
        {
112
            get { return env.getBaseURI(); }
113
            set { env.setBaseURI(value); }
114
        }
115

    
116
        /// <summary>
117
        /// XPath 1.0 Backwards Compatibility Mode. If true, backwards compatibility mode
118
        /// is set. In backwards compatibility mode, more implicit type conversions are
119
        /// allowed in XPath expressions, for example it is possible to compare a number
120
        /// with a string. The default is false (backwards compatibility mode is off).
121
        /// </summary>
122

    
123

    
124
        public Boolean BackwardsCompatible
125
        {
126
            get { return env.isInBackwardsCompatibleMode(); }
127
            set { env.setBackwardsCompatibilityMode(value); }
128
        }
129

    
130

    
131
        /// <summary>
132
        /// Compile an expression supplied as a String.
133
        /// </summary>
134
        /// <example>
135
        /// <code>
136
        /// XPathExecutable q = compiler.Compile("distinct-values(//*/node-name()");
137
        /// </code>
138
        /// </example>
139
        /// <param name="source">A string containing the source text of the XPath expression</param>
140
        /// <returns>An <c>XPathExecutable</c> which represents the compiled xpath expression object.
141
        /// The XPathExecutable may be run as many times as required, in the same or a different
142
        /// thread. The <c>XPathExecutable</c> is not affected by any changes made to the <c>XPathCompiler</c>
143
        /// once it has been compiled.</returns>
144

    
145
        public XPathExecutable Compile(String source)
146
        {
147
            JXPathEvaluator eval = new JXPathEvaluator(config);
148
            eval.setStaticContext(env);
149
            JXPathExpression cexp = eval.createExpression(source);
150
            return new XPathExecutable(cexp, config, env, declaredVariables);
151
        }
152
    }
153

    
154
    /// <summary>
155
    /// An <c>XPathExecutable</c> represents the compiled form of an XPath expression. 
156
    /// To evaluate the expression,
157
    /// it must first be loaded to form an <c>XPathSelector</c>.
158
    /// </summary>
159
    /// <remarks>
160
    /// <para>An <c>XPathExecutable</c> is immutable, and therefore thread-safe. It is simplest to
161
    /// load a new <c>XPathSelector</c> each time the expression is to be evaluated. However, the 
162
    /// <c>XPathSelector</c> is serially reusable within a single thread.</para>
163
    /// <para>An <c>XPathExecutable</c> is created by using one of the <c>Compile</c>
164
    /// methods on the <c>XPathCompiler</c> class.</para>
165
    /// </remarks>    
166

    
167
    [Serializable]
168
    public class XPathExecutable
169
    {
170

    
171
        private JXPathExpression exp;
172
        private JConfiguration config;
173
        private JIndependentContext env;
174
        private ArrayList declaredVariables;
175

    
176
        // internal constructor
177

    
178
        internal XPathExecutable(JXPathExpression exp, JConfiguration config,
179
            JIndependentContext env, ArrayList declaredVariables)
180
        {
181
            this.exp = exp;
182
            this.config = config;
183
            this.env = env;
184
            this.declaredVariables = declaredVariables;
185
        }
186

    
187
        /// <summary>
188
        /// Load the compiled XPath expression to prepare it for execution.
189
        /// </summary>
190
        /// <returns>
191
        /// An <c>XPathSelector</c>. The returned <c>XPathSelector</c> can be used to
192
        /// set up the dynamic context, and then to evaluate the expression.
193
        /// </returns>
194

    
195
        public XPathSelector Load()
196
        {
197
            return new XPathSelector(exp, config, env, declaredVariables);
198
        }
199
    }
200

    
201
    /// <summary inherits="IEnumerable">
202
    /// An <c>XPathSelector</c> represents a compiled and loaded XPath expression ready for execution.
203
    /// The <c>XPathSelector</c> holds details of the dynamic evaluation context for the XPath expression.
204
    /// </summary>
205
    /// <remarks>
206
    /// <para>An <c>XPathSelector</c> should not be used concurrently in multiple threads. It is safe,
207
    /// however, to reuse the object within a single thread to evaluate the same XPath expression several times.
208
    /// Evaluating the expression does not change the context that has been established.</para>
209
    /// <para>An <c>XPathSelector</c> is always constructed by running the <c>Load</c> method of
210
    /// an <c>XPathExecutable</c>.</para>
211
    /// </remarks>     
212

    
213
    [Serializable]
214
    public class XPathSelector : IEnumerable
215
    {
216

    
217
        private JXPathExpression exp;
218
        private JConfiguration config;
219
        private JXPathDynamicContext dynamicContext;
220
        private JIndependentContext env;
221
        private ArrayList declaredVariables;
222

    
223
        // internal constructor
224

    
225
        internal XPathSelector(JXPathExpression exp, JConfiguration config,
226
            JIndependentContext env, ArrayList declaredVariables)
227
        {
228
            this.exp = exp;
229
            this.config = config;
230
            this.env = env;
231
            this.declaredVariables = declaredVariables;
232
            this.dynamicContext = exp.createDynamicContext(null);
233
        }
234

    
235
        /// <summary>
236
        /// The context item for the XPath expression evaluation.
237
        /// </summary>
238
        /// <remarks> This may be either a node or an atomic
239
        /// value. Most commonly it will be a document node, which might be constructed
240
        /// using the <c>Build</c> method of the <c>DocumentBuilder</c> object.
241
        /// </remarks>
242

    
243
        public XdmItem ContextItem
244
        {
245
            get { return (XdmItem)XdmValue.Wrap(dynamicContext.getContextItem()); }
246
            set { dynamicContext.setContextItem((JItem)value.Unwrap()); }
247
        }
248

    
249
        /// <summary>
250
        /// Set the value of a variable
251
        /// </summary>
252
        /// <param name="name">The name of the variable. This must match the name of a variable
253
        /// that was declared to the XPathCompiler. No error occurs if the expression does not
254
        /// actually reference a variable with this name.</param>
255
        /// <param name="value">The value to be given to the variable.</param>
256
        
257

    
258
        public void SetVariable(QName name, XdmValue value)
259
        {
260
            JXPathVariable var = null;
261
            String uri = (name.Uri == null ? "" : name.Uri);
262
            String local = name.LocalName;
263
            foreach (JXPathVariable v in declaredVariables)
264
            {
265
                String vuri = v.getVariableQName().getNamespaceURI();
266
                if (vuri == null)
267
                {
268
                    vuri = "";
269
                }
270
                if (vuri == uri && v.getVariableQName().getLocalName() == local)
271
                {
272
                    var = v;
273
                    break;
274
                }
275
            }
276
            if (var == null)
277
            {
278
                throw new ArgumentException("Variable has not been declared: " + name);
279
            }
280
            dynamicContext.setVariable(var, value.Unwrap());
281
        }
282

    
283
        /// <summary>
284
        /// Evaluate the expression, returning the result as an <c>XdmValue</c> (that is,
285
        /// a sequence of nodes and/or atomic values).
286
        /// </summary>
287
        /// <remarks>
288
        /// Although a singleton result <i>may</i> be represented as an <c>XdmItem</c>, there is
289
        /// no guarantee that this will always be the case. If you know that the expression will return at
290
        /// most one node or atomic value, it is best to use the <c>EvaluateSingle</c> method, which 
291
        /// does guarantee that an <c>XdmItem</c> (or null) will be returned.
292
        /// </remarks>
293
        /// <returns>
294
        /// An <c>XdmValue</c> representing the results of the expression. 
295
        /// </returns>
296

    
297
        public XdmValue Evaluate()
298
        {
299
            JValueRepresentation value = JSequenceExtent.makeSequenceExtent(
300
                exp.iterate(dynamicContext));
301
            return XdmValue.Wrap(value);
302
        }
303

    
304
        /// <summary>
305
        /// Evaluate the XPath expression, returning the result as an <c>XdmItem</c> (that is,
306
        /// a single node or atomic value).
307
        /// </summary>
308
        /// <returns>
309
        /// An <c>XdmItem</c> representing the result of the expression, or null if the expression
310
        /// returns an empty sequence. If the expression returns a sequence of more than one item,
311
        /// any items after the first are ignored.
312
        /// </returns>
313

    
314

    
315
        public XdmItem EvaluateSingle()
316
        {
317
            net.sf.saxon.om.Item i = exp.evaluateSingle(dynamicContext);
318
            if (i == null)
319
            {
320
                return null;
321
            }
322
            return (XdmItem)XdmValue.Wrap(i);
323
        }
324

    
325
        /// <summary>
326
        /// Evaluate the expression, returning the result as an <c>IEnumerator</c> (that is,
327
        /// an enumerator over a sequence of nodes and/or atomic values).
328
        /// </summary>
329
        /// <returns>
330
        /// An enumerator over the sequence that represents the results of the expression.
331
        /// Each object in this sequence will be an instance of <c>XdmItem</c>. Note
332
        /// that the expression may be evaluated lazily, which means that a successful response
333
        /// from this method does not imply that the expression has executed successfully: failures
334
        /// may be reported later while retrieving items from the iterator. 
335
        /// </returns>
336

    
337
        public IEnumerator GetEnumerator()
338
        {
339
            return new SequenceEnumerator(exp.iterate(dynamicContext));
340
        }
341

    
342
    }
343

    
344

    
345

    
346

    
347
}
348

    
349
//
350
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
351
// you may not use this file except in compliance with the License. You may obtain a copy of the
352
// License at http://www.mozilla.org/MPL/
353
//
354
// Software distributed under the License is distributed on an "AS IS" basis,
355
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
356
// See the License for the specific language governing rights and limitations under the License.
357
//
358
// The Original Code is: all this file.
359
//
360
// The Initial Developer of the Original Code is Michael H. Kay.
361
//
362
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
363
//
364
// Contributor(s): none.
365
//
(6-6/8)