KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > expr > FragmentValue


1 package com.icl.saxon.expr;
2 import com.icl.saxon.*;
3 import com.icl.saxon.om.*;
4 import com.icl.saxon.tree.TreeBuilder;
5 import com.icl.saxon.tree.AttributeCollection;
6 import com.icl.saxon.output.*;
7 import java.util.Vector;
8 import java.util.Enumeration;
9 import org.xml.sax.Attributes;
10 import javax.xml.transform.TransformerException;
11
12
13 /**
14 * This class represents a Value of type result tree fragment. <BR>
15 * A Result Tree Fragment can be created by defining a variable in XSL whose value is defined by
16 * the contents of the xsl:variable element, possibly including start and end element tags. <BR>
17 */

18
19 public final class FragmentValue extends SingletonNodeSet {
20
21     private char[] buffer = new char[4096];
22     private int used = 0;
23     private Vector events = new Vector(20, 20);
24     private String baseURI = null;
25     private FragmentEmitter emitter = new FragmentEmitter();
26     private Controller controller;
27
28     private static AttributeCollection emptyAttributeCollection = new AttributeCollection((NamePool)null);
29
30     private static Integer START_ELEMENT = new Integer(1);
31     private static Integer END_ELEMENT = new Integer(2);
32     private static Integer START_NAMESPACE = new Integer(3);
33     private static Integer END_NAMESPACE = new Integer(4);
34     private static Integer CHARACTERS = new Integer(5);
35     private static Integer PROCESSING_INSTRUCTION = new Integer(6);
36     private static Integer COMMENT = new Integer(7);
37     private static Integer ESCAPING_ON = new Integer(8);
38     private static Integer ESCAPING_OFF = new Integer(9);
39
40     public FragmentValue(Controller c) {
41         controller = c;
42         generalUseAllowed = false;
43     }
44
45     /**
46     * Set the Base URI for the nodes in the result tree fragment. This is defined to be
47     * the Base URI of the relevant xsl:variable element in the stylesheet.
48     */

49
50     public void setBaseURI(String uri) {
51         baseURI = uri;
52     }
53
54     /**
55     * Provide a namepool
56     */

57     
58     //public void setNamePool(NamePool pool) {
59
// namePool = pool;
60
//}
61

62     /**
63     * Get an Emitter that can be used to feed data to this result tree fragment
64     */

65
66     public Emitter getEmitter() {
67         return emitter;
68     }
69
70     /**
71     * Convert the result tree fragment to a string.
72     */

73
74     public String asString() {
75         return new String(buffer, 0, used);
76     }
77
78     /**
79     * Evaluate an expression as a String and write the result to the
80     * specified outputter.<br>
81     * @param out The required outputter
82     * @param context The context in which the expression is to be evaluated
83     */

84
85     public void outputStringValue(Outputter out, Context context) throws TransformerException {
86         out.writeContent(buffer, 0, used);
87     }
88
89     /**
90     * Convert the result tree fragment to a number
91     */

92
93     public double asNumber() {
94         return Value.stringToNumber(asString());
95     }
96
97     /**
98     * Convert the result tree fragment to a boolean
99     */

100
101     public boolean asBoolean() {
102         return true;
103     }
104
105     /**
106     * Count the nodes in the node-set.
107     */

108
109     public int getCount() {
110         return 1;
111     }
112   
113     /**
114     * Simplify the expression
115     */

116
117     public Expression simplify() {
118         // overrides method on superclass
119
return this;
120     }
121
122     /**
123     * Get the first node in the nodeset (in document order)
124     * @return the first node
125     */

126
127     public NodeInfo getFirst() {
128         return getRootNode();
129     }
130
131     /**
132     * Return an enumeration of this nodeset value.
133     */

134
135     public NodeEnumeration enumerate() throws XPathException {
136         if (!generalUseAllowed) {
137             throw new XPathException("Cannot process a result tree fragment as a node-set under XSLT 1.0");
138         }
139         return new SingletonEnumeration(getRootNode());
140     }
141
142     /**
143     * Test whether a nodeset "equals" another Value
144     */

145
146     public boolean equals(Value other) throws XPathException {
147         if (other instanceof StringValue) { // short cut for common case
148
return asString().equals(other.asString());
149         }
150         return new StringValue(asString()).equals(other);
151     }
152
153     /**
154     * Test whether a nodeset "not-equals" another Value
155     */

156
157     public boolean notEquals(Value other) throws XPathException {
158         return new StringValue(asString()).notEquals(other);
159     }
160
161     /**
162     * Test how a FragmentValue compares to another Value under a relational comparison.
163     */

164
165     public boolean compare(int operator, Value other) throws XPathException {
166         return new StringValue(asString()).compare(operator, other);
167     }
168
169     /**
170     * Return the type of the value
171     * @return Value.NODESET (always)
172     */

173
174     public int getType() {
175         return Value.NODESET;
176     }
177     
178     /**
179     * Determine the data type of the expression, if possible
180     * @return Value.NODESET
181     */

182
183     public int getDataType() {
184         return Value.NODESET;
185     }
186
187     /**
188     * Get the root (document) node
189     */

190
191     public DocumentInfo getRootNode() {
192         if (node!=null) { // only do it once
193
return (DocumentInfo)node;
194         }
195         try {
196             Builder builder = new TreeBuilder();
197             builder.setSystemId(baseURI);
198             builder.setNamePool(controller.getNamePool());
199             builder.startDocument();
200             replay(builder);
201             builder.endDocument();
202             node = builder.getCurrentDocument();
203             controller.getDocumentPool().add((DocumentInfo)node, null);
204             return (DocumentInfo)node;
205         } catch (TransformerException err) {
206             throw new InternalSaxonError("Error building temporary tree: " + err.getMessage());
207         }
208     }
209
210     /**
211     * Copy the result tree fragment value to a given Outputter
212     */

213
214     public void copy(Outputter out) throws TransformerException {
215         Emitter emitter = out.getEmitter();
216         replay(emitter);
217     }
218
219     /**
220     * Replay the saved emitter events to a new emitter
221     */

222
223     public void replay(Emitter emitter) throws TransformerException {
224         Enumeration enum = events.elements();
225         
226         while (enum.hasMoreElements()) {
227             Object e = enum.nextElement();
228             Object e1;
229             Object e2;
230             Object e3;
231             if (e==START_ELEMENT) {
232                 e1 = enum.nextElement();
233                 e2 = enum.nextElement();
234                 e3 = enum.nextElement();
235                 int[] namespaces = (int[])e3;
236                 emitter.startElement(((Integer)e1).intValue(),
237                                      (AttributeCollection)e2,
238                                      namespaces, namespaces.length);
239                 
240             } else if (e==END_ELEMENT) {
241                 e1 = enum.nextElement();
242                 emitter.endElement(((Integer)e1).intValue());
243                 
244             } else if (e==CHARACTERS) {
245                 e1 = enum.nextElement();
246                 emitter.characters(buffer, ((int[])e1)[0], ((int[])e1)[1]);
247                                 
248             } else if (e==PROCESSING_INSTRUCTION) {
249                 e1 = enum.nextElement();
250                 e2 = enum.nextElement();
251                 emitter.processingInstruction((String)e1, (String)e2);
252                 
253             } else if (e==COMMENT) {
254                 e1 = enum.nextElement();
255                 emitter.comment(((String)e1).toCharArray(), 0, ((String)e1).length());
256
257             } else if (e==ESCAPING_ON) {
258                 emitter.setEscaping(true);
259
260             } else if (e==ESCAPING_OFF) {
261                 emitter.setEscaping(false);
262                 
263             } else {
264                 throw new InternalSaxonError("Corrupt data in temporary tree: " + e);
265             }
266         }
267         
268     }
269     
270     /**
271     * Diagnostic print of expression structure
272     */

273     
274     public void display(int level) {
275         System.err.println(indent(level) + "** result tree fragment **");
276     }
277
278     //////////////////////////////////////////////////////////////////////////////////
279
// Implement the Emitter interface
280
//////////////////////////////////////////////////////////////////////////////////
281

282     private class FragmentEmitter extends Emitter {
283     
284         boolean previousCharacters = false;
285     
286         /**
287         * Notify document start
288         */

289     
290         public void startDocument() {
291             previousCharacters = false;
292         }
293     
294         /**
295         * Notify document end
296         */

297     
298         public void endDocument() {
299             previousCharacters = false;
300         }
301     
302         /**
303         * Output an element start tag.
304         * @params name The Name object naming the element. Use the getDisplayName() method
305         * to obtain the tag to display in XML output.
306         * @params attributes The attributes (excluding namespace declarations) associated with
307         * this element. Note that the emitter is permitted to modify this list, e.g. to add
308         * namespace declarations.
309         */

310     
311         public void startElement(int name, Attributes attributes,
312                                  int[] namespaces, int nscount) {
313             events.addElement(START_ELEMENT);
314             events.addElement(new Integer(name));
315     
316     
317     
318             // copy the attribute collection
319
AttributeCollection atts;
320             int numAtts = attributes.getLength();
321             if (numAtts==0) {
322                 atts = emptyAttributeCollection;
323             } else {
324                 atts = new AttributeCollection((AttributeCollection)attributes);
325             }
326     
327             events.addElement(atts);
328             
329             // copy the namespaces
330
int[] ns = new int[nscount];
331             System.arraycopy(namespaces, 0, ns, 0, nscount);
332             events.addElement(ns);
333     
334             previousCharacters = false;
335         }
336     
337         /**
338         * Output an element end tag
339         * @params name The Name object naming the element. Use the getDisplayName() method
340         * to obtain the tag to display in XML output.
341         */

342     
343         public void endElement(int name) {
344             events.addElement(END_ELEMENT);
345             events.addElement(new Integer(name));
346             previousCharacters = false;
347         }
348        
349         /**
350         * Output character data
351         */

352     
353         public void characters(char[] chars, int start, int len) {
354             while (used + len >= buffer.length) {
355                 char[] newbuffer = new char[buffer.length * 2];
356                 System.arraycopy(buffer, 0, newbuffer, 0, used);
357                 buffer = newbuffer;
358             }
359             System.arraycopy(chars, start, buffer, used, len);
360             if (previousCharacters) {
361                 // concatenate with the previous text node
362
int[] v = (int[])events.elementAt(events.size()-1);
363                 v[1] += len;
364             } else {
365                 events.addElement(CHARACTERS);
366                 int[] val = {used, len}; // objects are expensive so we only create one
367
events.addElement(val);
368             }
369             used += len;
370             previousCharacters = true;
371         }
372     
373         /**
374         * Output a processing instruction
375         */

376     
377         public void processingInstruction(String name, String data) {
378             events.addElement(PROCESSING_INSTRUCTION);
379             events.addElement(name);
380             events.addElement(data);
381             previousCharacters = false;
382         }
383         
384         /**
385         * Output a comment. <br>
386         */

387     
388         public void comment (char[] chars, int start, int length) {
389             events.addElement(COMMENT);
390             events.addElement(new String(chars, start, length));
391             previousCharacters = false;
392         }
393     
394         /**
395         * Switch escaping on or off. This is called when the XSLT disable-output-escaping attribute
396         * is used to switch escaping on or off.
397         */

398     
399         public void setEscaping(boolean escaping) throws TransformerException {
400             events.addElement((escaping ? ESCAPING_ON : ESCAPING_OFF));
401             previousCharacters = false;
402         }
403         
404     } // end of inner class FragmentEmitter
405

406
407 }
408
409 //
410
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
411
// you may not use this file except in compliance with the License. You may obtain a copy of the
412
// License at http://www.mozilla.org/MPL/
413
//
414
// Software distributed under the License is distributed on an "AS IS" basis,
415
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
416
// See the License for the specific language governing rights and limitations under the License.
417
//
418
// The Original Code is: all this file.
419
//
420
// The Initial Developer of the Original Code is
421
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
422
//
423
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
424
//
425
// Contributor(s): none.
426
//
427

428
Popular Tags