KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > tree > DocumentImpl


1 package com.icl.saxon.tree;
2 import com.icl.saxon.om.NodeInfo;
3 import com.icl.saxon.om.DocumentInfo;
4 import com.icl.saxon.om.NamePool;
5 import com.icl.saxon.Controller;
6 import com.icl.saxon.Context;
7 import com.icl.saxon.KeyManager;
8 import com.icl.saxon.om.AxisEnumeration;
9 import com.icl.saxon.expr.NodeSetExtent;
10 import com.icl.saxon.output.Outputter;
11 import com.icl.saxon.pattern.Pattern;
12 import com.icl.saxon.sort.LocalOrderComparer;
13
14 import java.util.*;
15 import java.net.*;
16 import org.xml.sax.Attributes JavaDoc;
17 import javax.xml.transform.TransformerException JavaDoc;
18
19 import org.w3c.dom.*;
20
21 /**
22   * A node in the XML parse tree representing the Document itself (or equivalently, the root
23   * node of the Document).<P>
24   * @author <A HREF="mailto:mhkay@iclway.co.uk>Michael H. Kay</A>
25   */

26
27 public final class DocumentImpl extends ParentNodeImpl
28     implements DocumentInfo, Document {
29
30     //private static int nextDocumentNumber = 0;
31

32     private ElementImpl documentElement;
33
34     private Hashtable idTable = null;
35     //private int documentNumber;
36
private Hashtable entityTable = null;
37     private Hashtable elementList = null;
38     private StringBuffer JavaDoc characterBuffer;
39     private NamePool namePool;
40     private NodeFactory nodeFactory;
41     private LineNumberMap lineNumberMap;
42     private SystemIdMap systemIdMap = new SystemIdMap();
43
44     // list of indexes for keys. Each entry is a triple: KeyManager, fingerprint of Key name, Hashtable.
45
// This reflects the fact that the same document may contain indexes for more than one stylesheet.
46

47     private Object JavaDoc[] index = new Object JavaDoc[30];
48     private int indexEntriesUsed = 0;
49
50     public DocumentImpl() {
51         parent = null;
52     }
53
54     /**
55     * Set the character buffer
56     */

57
58     protected void setCharacterBuffer(StringBuffer JavaDoc buffer) {
59         characterBuffer = buffer;
60     }
61
62     /**
63     * Get the character buffer
64     */

65
66     public final StringBuffer JavaDoc getCharacterBuffer() {
67         return characterBuffer;
68     }
69
70     /**
71     * Set the name pool used for all names in this document
72     */

73     
74     public void setNamePool(NamePool pool) {
75         namePool = pool;
76     }
77     
78     /**
79     * Get the name pool used for the names in this document
80     */

81     
82     public NamePool getNamePool() {
83         return namePool;
84     }
85
86     /**
87     * Set the node factory that was used to build this document
88     */

89     
90     public void setNodeFactory(NodeFactory factory) {
91         nodeFactory = factory;
92     }
93     
94     /**
95     * Get the node factory that was used to build this document
96     */

97     
98     public NodeFactory getNodeFactory() {
99         return nodeFactory;
100     }
101
102     /**
103     * Set the top-level element of the document (variously called the root element or the
104     * document element). Note that a DocumentImpl may represent the root of a result tree
105     * fragment, in which case there is no document element.
106     * @param e the top-level element
107     */

108
109     protected void setDocumentElement(ElementImpl e) {
110         documentElement = e;
111     }
112
113     /**
114     * Set the system id of this node
115     */

116
117     public void setSystemId(String JavaDoc uri) {
118         //if (uri==null) {
119
// throw new IllegalArgumentException("System ID must not be null");
120
//}
121
if (uri==null) {
122             uri = "";
123         }
124         systemIdMap.setSystemId(sequence, uri);
125     }
126         
127     /**
128     * Get the system id of this root node
129     */

130
131     public String JavaDoc getSystemId() {
132         return systemIdMap.getSystemId(sequence);
133     }
134
135     /**
136     * Get the base URI of this root node. For a root node the base URI is the same as the
137     * System ID.
138     */

139
140     public String JavaDoc getBaseURI() {
141         return getSystemId();
142     }
143
144     /**
145     * Set the system id of an element in the document
146     */

147
148     protected void setSystemId(int seq, String JavaDoc uri) {
149         if (uri==null) {
150             uri = "";
151         // uri = "*unknown.uri*";
152
// throw new NullPointerException("URI may not be null");
153
}
154         systemIdMap.setSystemId(seq, uri);
155     }
156         
157
158     /**
159     * Get the system id of an element in the document
160     */

161
162     protected String JavaDoc getSystemId(int seq) {
163         return systemIdMap.getSystemId(seq);
164     }
165
166
167     /**
168     * Set line numbering on
169     */

170
171     public void setLineNumbering() {
172         lineNumberMap = new LineNumberMap();
173         lineNumberMap.setLineNumber(sequence, 0);
174     }
175
176     /**
177     * Set the line number for an element. Ignored if line numbering is off.
178     */

179
180     protected void setLineNumber(int sequence, int line) {
181         if (lineNumberMap != null) {
182             lineNumberMap.setLineNumber(sequence, line);
183         }
184     }
185
186     /**
187     * Get the line number for an element. Return -1 if line numbering is off.
188     */

189
190     protected int getLineNumber(int sequence) {
191         if (lineNumberMap != null) {
192             return lineNumberMap.getLineNumber(sequence);
193         }
194         return -1;
195     }
196
197     /**
198     * Get the line number of this root node.
199     * @return 0 always
200     */

201
202     public int getLineNumber() {
203         return 0;
204     }
205
206     /**
207     * Return the type of node.
208     * @return NodeInfo.ROOT (always)
209     */

210
211     public final short getNodeType() {
212         return ROOT;
213     }
214
215     /**
216     * Get next sibling - always null
217     * @return null
218     */

219
220     public final Node getNextSibling() {
221         return null;
222     }
223
224     /**
225     * Get previous sibling - always null
226     * @return null
227     */

228
229     public final Node getPreviousSibling() {
230         return null;
231     }
232
233     /**
234      * Get the root (outermost) element.
235      * @return the Element node for the outermost element of the document.
236      */

237      
238     public Element getDocumentElement() {
239         return (ElementImpl)documentElement;
240     }
241     
242     /**
243     * Get the root (document) node
244     * @return the DocumentInfo representing this document
245     */

246
247     public DocumentInfo getDocumentRoot() {
248         return this;
249     }
250
251     /**
252     * Get a character string that uniquely identifies this node within the document
253     * @return the empty string
254     */

255
256     public String JavaDoc generateId() {
257         return "";
258     }
259
260     /**
261     * Get a list of all elements with a given name fingerprint
262     */

263
264     protected AxisEnumeration getAllElements(int fingerprint) {
265         Integer JavaDoc elkey = new Integer JavaDoc(fingerprint);
266         if (elementList==null) {
267             elementList = new Hashtable();
268         }
269         NodeSetExtent list = (NodeSetExtent)elementList.get(elkey);
270         if (list==null) {
271             list = new NodeSetExtent(LocalOrderComparer.getInstance());
272             list.setSorted(true);
273             NodeImpl next = getNextInDocument(this);
274             while (next!=null) {
275                 if (next.getNodeType()==ELEMENT &&
276                         next.getFingerprint() == fingerprint) {
277                     list.append(next);
278                 }
279                 next = next.getNextInDocument(this);
280             }
281             elementList.put(elkey, list);
282         }
283         return (AxisEnumeration)list.enumerate();
284     }
285
286     /**
287     * Index all the ID attributes. This is done the first time the id() function
288     * is used on this document
289     */

290
291     private void indexIDs() {
292         if (idTable!=null) return; // ID's are already indexed
293
idTable = new Hashtable();
294
295         NodeImpl curr = this;
296         NodeImpl root = curr;
297         while(curr!=null) {
298             if (curr.getNodeType()==ELEMENT) {
299                 ElementImpl e = (ElementImpl)curr;
300                 Attributes JavaDoc atts = e.getAttributeList();
301                 for (int i=0; i<atts.getLength(); i++) {
302                     if ("ID".equals(atts.getType(i))) {
303                         registerID(e, atts.getValue(i));
304                     }
305                 }
306             }
307             curr = curr.getNextInDocument(root);
308         }
309     }
310
311     /**
312     * Register a unique element ID. Fails if there is already an element with that ID.
313     * @param e The Element having a particular unique ID value
314     * @param id The unique ID value
315     */

316
317     private void registerID(NodeInfo e, String JavaDoc id) {
318         // the XPath spec (5.2.1) says ignore the second ID if it's not unique
319
Object JavaDoc old = idTable.get(id);
320         if (old==null) {
321             idTable.put(id, e);
322         }
323         
324     }
325
326     /**
327     * Get the element with a given ID.
328     * @param id The unique ID of the required element, previously registered using registerID()
329     * @return The NodeInfo for the given ID if one has been registered, otherwise null.
330     */

331
332     public NodeInfo selectID(String JavaDoc id) {
333         if (idTable==null) indexIDs();
334         return (NodeInfo)idTable.get(id);
335     }
336
337     /**
338     * Get the index for a given key
339     * @param keymanager The key manager managing this key
340     * @param fingerprint The fingerprint of the name of the key (unique with the key manager)
341     * @return The index, if one has been built, in the form of a Hashtable that
342     * maps the key value to a Vector of nodes having that key value. If no index
343     * has been built, returns null.
344     */

345
346     public synchronized Hashtable getKeyIndex(KeyManager keymanager, int fingerprint) {
347         for (int k=0; k<indexEntriesUsed; k+=3) {
348             if (((KeyManager)index[k])==keymanager &&
349                      ((Integer JavaDoc)index[k+1]).intValue()==fingerprint) {
350                 Object JavaDoc ix = index[k+2];
351                 return (Hashtable)index[k+2];
352
353                             // circular references are now a compile-time error
354
}
355         }
356         return null;
357     }
358
359     /**
360     * Set the index for a given key. The method is synchronized because the same document
361     * can be used by several stylesheets at the same time.
362     * @param keymanager The key manager managing this key
363     * @param fingerprint The fingerprint of the name of the key (unique with the key manager)
364     * @param keyindex the index, in the form of a Hashtable that
365     * maps the key value to a Vector of nodes having that key value. Or the String
366     * "under construction", indicating that the index is being built.
367     */

368
369     public synchronized void setKeyIndex(KeyManager keymanager, int fingerprint, Hashtable keyindex) /*throws SAXException*/ {
370         for (int k=0; k<indexEntriesUsed; k+=3) {
371             if (((KeyManager)index[k])==keymanager &&
372                      ((Integer JavaDoc)index[k+1]).intValue() == fingerprint) {
373                 index[k+2] = keyindex;
374                 return;
375             }
376         }
377
378         if (indexEntriesUsed+3 >= index.length) {
379             Object JavaDoc[] index2 = new Object JavaDoc[indexEntriesUsed*2];
380             System.arraycopy(index, 0, index2, 0, indexEntriesUsed);
381             index = index2;
382         }
383         index[indexEntriesUsed++] = keymanager;
384         index[indexEntriesUsed++] = new Integer JavaDoc(fingerprint);
385         index[indexEntriesUsed++] = keyindex;
386     }
387
388     /**
389     * Set an unparsed entity URI associated with this document. For system use only, while
390     * building the document.
391     */

392
393     protected void setUnparsedEntity(String JavaDoc name, String JavaDoc uri) {
394         if (entityTable==null) {
395             entityTable = new Hashtable();
396         }
397         entityTable.put(name, uri);
398     }
399
400     /**
401     * Get the unparsed entity with a given name
402     * @param name the name of the entity
403     * @return the URI of the entity if there is one, or empty string if not
404     */

405
406     public String JavaDoc getUnparsedEntity(String JavaDoc name) {
407         if (entityTable==null) {
408             return "";
409         }
410         String JavaDoc uri = (String JavaDoc)entityTable.get(name);
411         return (uri==null ? "" : uri);
412     }
413
414     /**
415     * Copy this node to a given outputter
416     */

417
418     public void copy(Outputter out) throws TransformerException JavaDoc {
419         NodeImpl next = (NodeImpl)getFirstChild();
420         while (next!=null) {
421             next.copy(out);
422             next = (NodeImpl)next.getNextSibling();
423         }
424     }
425     
426 }
427
428 //
429
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
430
// you may not use this file except in compliance with the License. You may obtain a copy of the
431
// License at http://www.mozilla.org/MPL/
432
//
433
// Software distributed under the License is distributed on an "AS IS" basis,
434
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
435
// See the License for the specific language governing rights and limitations under the License.
436
//
437
// The Original Code is: all this file except PB-SYNC section.
438
//
439
// The Initial Developer of the Original Code is
440
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
441
//
442
// Portions marked PB-SYNC are Copyright (C) Peter Bryant (pbryant@bigfoot.com). All Rights Reserved.
443
//
444
// Contributor(s): Michael Kay, Peter Bryant.
445
//
446
Popular Tags