KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > om > AttributeCollectionImpl


1 package net.sf.saxon.om;
2
3 import net.sf.saxon.event.LocationProvider;
4 import net.sf.saxon.style.StandardNames;
5 import org.xml.sax.Attributes JavaDoc;
6
7
8 /**
9  * AttributeCollectionImpl is an implementation of both the SAX2 interface Attributes
10  * and the Saxon equivalent AttributeCollection.
11  *
12  * <p>As well as providing the information required by the SAX2 interface, an
13  * AttributeCollection can hold type information (as needed to support the JAXP 1.3
14  * {@link javax.xml.validation.ValidatorHandler} interface), and location information
15  * for debugging. The location information is used in the case of attributes on a result
16  * tree to identify the location in the query or stylesheet from which they were
17  * generated.
18  */

19
20 public final class AttributeCollectionImpl implements Attributes JavaDoc, AttributeCollection {
21
22     // Attribute values are maintained as an array of Strings. Everything else is maintained
23
// in the form of integers.
24

25     private NamePool namePool;
26     private LocationProvider locationProvider;
27     private String JavaDoc[] values = null;
28     private int[] codes = null;
29     private int used = 0;
30
31     // Empty attribute collection. The caller is trusted not to try and modify it.
32

33     public static final AttributeCollection EMPTY_ATTRIBUTE_COLLECTION =
34             new AttributeCollectionImpl(null);
35
36     // Layout of the integer array. There are RECSIZE integers for each attribute.
37

38     private static final int RECSIZE = 4;
39
40     private static final int NAMECODE = 0;
41     private static final int TYPECODE = 1;
42     private static final int LOCATIONID = 2;
43     private static final int PROPERTIES = 3;
44
45     /**
46      * Create an empty attribute list.
47      */

48
49     public AttributeCollectionImpl(NamePool pool) {
50         namePool = pool;
51         used = 0;
52     }
53
54     /**
55      * Set the location provider. This must be set if the methods getSystemId() and getLineNumber()
56      * are to be used to get location information for an attribute.
57      */

58
59     public void setLocationProvider(LocationProvider provider) {
60         this.locationProvider = provider;
61     }
62
63     /**
64      * Add an attribute to an attribute list. The parameters correspond
65      * to the parameters of the {@link net.sf.saxon.event.Receiver#attribute(int, int, CharSequence, int, int)}
66      * method. There is no check that the name of the attribute is distinct from other attributes
67      * already in the collection: this check must be made by the caller.
68      *
69      * @param nameCode Integer representing the attribute name.
70      * @param typeCode The attribute type code
71      * @param value The attribute value (must not be null)
72      * @param locationId Identifies the attribtue location.
73      * @param properties Attribute properties
74      */

75
76     public void addAttribute(int nameCode, int typeCode, String JavaDoc value, int locationId, int properties) {
77         if (values == null) {
78             values = new String JavaDoc[5];
79             codes = new int[5 * RECSIZE];
80             used = 0;
81         }
82         if (values.length == used) {
83             int newsize = (used == 0 ? 5 : used * 2);
84             String JavaDoc[] v2 = new String JavaDoc[newsize];
85             int[] c2 = new int[newsize * RECSIZE];
86             System.arraycopy(values, 0, v2, 0, used);
87             System.arraycopy(codes, 0, c2, 0, used*RECSIZE);
88             values = v2;
89             codes = c2;
90         }
91         int n = used*RECSIZE;
92         codes[n+NAMECODE] = nameCode;
93         codes[n+TYPECODE] = typeCode;
94         codes[n+LOCATIONID] = locationId;
95         codes[n+PROPERTIES] = properties;
96         values[used++] = value;
97     }
98
99     /**
100      * Set (overwrite) an attribute in the attribute list. The parameters correspond
101      * to the parameters of the {@link net.sf.saxon.event.Receiver#attribute(int, int, CharSequence, int, int)}
102      * method.
103      * @param index Identifies the entry to be replaced
104      * @param nameCode Integer representing the attribute name.
105      * @param typeCode The attribute type code
106      * @param value The attribute value (must not be null)
107      * @param locationId Identifies the attribtue location.
108      * @param properties Attribute properties
109      */

110
111     public void setAttribute(int index, int nameCode, int typeCode, String JavaDoc value, int locationId, int properties) {
112         int n = index*RECSIZE;
113         codes[n+NAMECODE] = nameCode;
114         codes[n+TYPECODE] = typeCode;
115         codes[n+LOCATIONID] = locationId;
116         codes[n+PROPERTIES] = properties;
117         values[index] = value;
118     }
119
120
121     /**
122      * Clear the attribute list. This removes the values but doesn't free the memory used.
123      * free the memory, use clear() then compact().
124      */

125
126     public void clear() {
127         used = 0;
128     }
129
130     /**
131      * Compact the attribute list to avoid wasting memory
132      */

133
134     public void compact() {
135         if (used == 0) {
136             codes = null;
137             values = null;
138         } else if (values.length > used) {
139             String JavaDoc[] v2 = new String JavaDoc[used];
140             int[] c2 = new int[used * RECSIZE];
141             System.arraycopy(values, 0, v2, 0, used);
142             System.arraycopy(codes, 0, c2, 0, used*RECSIZE);
143             values = v2;
144             codes = c2;
145         }
146     }
147
148     /**
149      * Return the number of attributes in the list.
150      *
151      * @return The number of attributes in the list.
152      */

153
154     public int getLength() {
155         return (values == null ? 0 : used);
156     }
157
158     /**
159      * Get the namecode of an attribute (by position).
160      *
161      * @param index The position of the attribute in the list.
162      * @return The display name of the attribute as a string, or null if there
163      * is no attribute at that position.
164      */

165
166     public int getNameCode(int index) {
167         if (codes == null) {
168             return -1;
169         }
170         if (index < 0 || index >= used) {
171             return -1;
172         }
173
174         return codes[index * RECSIZE + NAMECODE];
175     }
176
177     /**
178      * Get the namecode of an attribute (by position).
179      *
180      * @param index The position of the attribute in the list.
181      * @return The type annotation, as the fingerprint of the type name.
182      * The bit {@link net.sf.saxon.om.NodeInfo.IS_DTD_TYPE} represents a DTD-derived type.
183      */

184
185     public int getTypeAnnotation(int index) {
186         if (codes == null) {
187             return StandardNames.XDT_UNTYPED_ATOMIC;
188         }
189         if (index < 0 || index >= used) {
190             return StandardNames.XDT_UNTYPED_ATOMIC;
191         }
192
193         return codes[index * RECSIZE + TYPECODE];
194     }
195
196     /**
197      * Get the locationID of an attribute (by position)
198      * @param index The position of the attribute in the list.
199      * @return The location identifier of the attribute. This can be supplied
200      * to a {@link net.sf.saxon.event.LocationProvider} in order to obtain the
201      * actual system identifier and line number of the relevant location
202      */

203
204     public int getLocationId(int index) {
205         if (codes == null) {
206             return -1;
207         }
208         if (index < 0 || index >= used) {
209             return -1;
210         }
211
212         return codes[index * RECSIZE + LOCATIONID];
213     }
214
215     /**
216      * Get the systemId part of the location of an attribute, at a given index.
217      *
218      * <p>Attribute location information is not available from a SAX parser, so this method
219      * is not useful for getting the location of an attribute in a source document. However,
220      * in a Saxon result document, the location information represents the location in the
221      * stylesheet of the instruction used to generate this attribute, which is useful for
222      * debugging.</p>
223      * @param index the required attribute
224      * @return the systemId of the location of the attribute
225      */

226
227     public String JavaDoc getSystemId(int index) {
228         return locationProvider.getSystemId(getLocationId(index));
229     }
230
231     /**
232      * Get the line number part of the location of an attribute, at a given index.
233      *
234      * <p>Attribute location information is not available from a SAX parser, so this method
235      * is not useful for getting the location of an attribute in a source document. However,
236      * in a Saxon result document, the location information represents the location in the
237      * stylesheet of the instruction used to generate this attribute, which is useful for
238      * debugging.</p>
239      * @param index the required attribute
240      * @return the line number of the location of the attribute
241      */

242
243      public int getLineNumber(int index) {
244          return locationProvider.getLineNumber(getLocationId(index));
245      }
246
247     /**
248      * Get the properties of an attribute (by position)
249      * @param index The position of the attribute in the list.
250      * @return The properties of the attribute. This is a set
251      * of bit-settings defined in class {@link net.sf.saxon.event.ReceiverOptions}. The
252      * most interesting of these is {{@link net.sf.saxon.event.ReceiverOptions#DEFAULTED_ATTRIBUTE},
253      * which indicates an attribute that was added to an element as a result of schema validation.
254      */

255
256     public int getProperties(int index) {
257         if (codes == null) {
258             return -1;
259         }
260         if (index < 0 || index >= used) {
261             return -1;
262         }
263
264         return codes[index * RECSIZE + PROPERTIES];
265     }
266
267     /**
268      * Get the prefix of the name of an attribute (by position).
269      *
270      * @param index The position of the attribute in the list.
271      * @return The prefix of the attribute name as a string, or null if there
272      * is no attribute at that position. Returns "" for an attribute that
273      * has no prefix.
274      */

275
276     public String JavaDoc getPrefix(int index) {
277         if (codes == null) {
278             return null;
279         }
280         if (index < 0 || index >= used) {
281             return null;
282         }
283         return namePool.getPrefix(getNameCode(index));
284     }
285
286     /**
287      * Get the lexical QName of an attribute (by position).
288      *
289      * @param index The position of the attribute in the list.
290      * @return The lexical QName of the attribute as a string, or null if there
291      * is no attribute at that position.
292      */

293
294     public String JavaDoc getQName(int index) {
295         if (codes == null) {
296             return null;
297         }
298         if (index < 0 || index >= used) {
299             return null;
300         }
301         return namePool.getDisplayName(getNameCode(index));
302     }
303
304     /**
305      * Get the local name of an attribute (by position).
306      *
307      * @param index The position of the attribute in the list.
308      * @return The local name of the attribute as a string, or null if there
309      * is no attribute at that position.
310      */

311
312     public String JavaDoc getLocalName(int index) {
313         if (codes == null) {
314             return null;
315         }
316         if (index < 0 || index >= used) {
317             return null;
318         }
319         return namePool.getLocalName(getNameCode(index));
320     }
321
322     /**
323      * Get the namespace URI of an attribute (by position).
324      *
325      * @param index The position of the attribute in the list.
326      * @return The local name of the attribute as a string, or null if there
327      * is no attribute at that position.
328      */

329
330     public String JavaDoc getURI(int index) {
331         if (codes == null) {
332             return null;
333         }
334         if (index < 0 || index >= used) {
335             return null;
336         }
337         return namePool.getURI(getNameCode(index));
338     }
339
340
341     /**
342      * Get the type of an attribute (by position). This is a SAX2 method,
343      * so it gets the type name as a DTD attribute type, mapped from the
344      * schema type code.
345      *
346      * @param index The position of the attribute in the list.
347      * @return The attribute type as a string ("NMTOKEN" for an
348      * enumeration, and "CDATA" if no declaration was
349      * read), or null if there is no attribute at
350      * that position.
351      */

352
353     public String JavaDoc getType(int index) {
354         int typeCode = getTypeAnnotation(index) & NamePool.FP_MASK;
355         switch (typeCode) {
356             case StandardNames.XS_ID: return "ID";
357             case StandardNames.XS_IDREF: return "IDREF";
358             case StandardNames.XS_NMTOKEN: return "NMTOKEN";
359             case StandardNames.XS_ENTITY: return "ENTITY";
360             case StandardNames.XS_IDREFS: return "IDREFS";
361             case StandardNames.XS_NMTOKENS: return "NMTOKENS";
362             case StandardNames.XS_ENTITIES: return "ENTITIES";
363             default: return "CDATA";
364         }
365     }
366
367     /**
368      * Get the type of an attribute (by name).
369      *
370      * @param uri The namespace uri of the attribute.
371      * @param localname The local name of the attribute.
372      * @return The index position of the attribute
373      */

374
375     public String JavaDoc getType(String JavaDoc uri, String JavaDoc localname) {
376         int index = findByName(uri, localname);
377         return (index < 0 ? null : getType(index));
378     }
379
380     /**
381      * Get the value of an attribute (by position).
382      *
383      * @param index The position of the attribute in the list.
384      * @return The attribute value as a string, or null if
385      * there is no attribute at that position.
386      */

387
388     public String JavaDoc getValue(int index) {
389         if (values == null) {
390             return null;
391         }
392         if (index < 0 || index >= used) {
393             return null;
394         }
395         return values[index];
396     }
397
398     /**
399      * Get the value of an attribute (by name).
400      *
401      * @param uri The namespace uri of the attribute.
402      * @param localname The local name of the attribute.
403      * @return The index position of the attribute
404      */

405
406     public String JavaDoc getValue(String JavaDoc uri, String JavaDoc localname) {
407         int index = findByName(uri, localname);
408         return (index < 0 ? null : getValue(index));
409     }
410
411     /**
412      * Get the attribute value using its fingerprint
413      */

414
415     public String JavaDoc getValueByFingerprint(int fingerprint) {
416         int index = findByFingerprint(fingerprint);
417         return (index < 0 ? null : getValue(index));
418     }
419
420     /**
421      * Get the index of an attribute, from its lexical QName
422      *
423      * @param qname The lexical QName of the attribute. The prefix must match.
424      * @return The index position of the attribute
425      */

426
427     public int getIndex(String JavaDoc qname) {
428         if (codes == null) {
429             return -1;
430         }
431         if (qname.indexOf(':') < 0) {
432             return findByName("", qname);
433         }
434         // Searching using prefix+localname is not recommended, but SAX allows it...
435
String JavaDoc[] parts;
436         try {
437             parts = Name.getQNameParts(qname);
438         } catch (QNameException err) {
439             return -1;
440         }
441         String JavaDoc prefix = parts[0];
442         if (prefix.equals("")) {
443             return findByName("", qname);
444         } else {
445             String JavaDoc localName = parts[1];
446             for (int i = 0; i < used; i++) {
447                 String JavaDoc lname = namePool.getLocalName(getNameCode(i));
448                 String JavaDoc ppref = namePool.getPrefix(getNameCode(i));
449                 if (localName.equals(lname) && prefix.equals(ppref)) {
450                     return i;
451                 }
452             }
453             return -1;
454         }
455     }
456
457     /**
458      * Get the index of an attribute (by name).
459      *
460      * @param uri The namespace uri of the attribute.
461      * @param localname The local name of the attribute.
462      * @return The index position of the attribute
463      */

464
465     public int getIndex(String JavaDoc uri, String JavaDoc localname) {
466         return findByName(uri, localname);
467     }
468
469     /**
470      * Get the index, given the fingerprint.
471      * Return -1 if not found.
472      */

473
474     public int getIndexByFingerprint(int fingerprint) {
475         return findByFingerprint(fingerprint);
476     }
477
478     /**
479      * Get the type of an attribute (by lexical QName).
480      *
481      * @param name The lexical QName of the attribute.
482      * @return The attribute type as a string (e.g. "NMTOKEN", or
483      * "CDATA" if no declaration was read).
484      */

485
486     public String JavaDoc getType(String JavaDoc name) {
487         int index = getIndex(name);
488         return getType(index);
489     }
490
491
492     /**
493      * Get the value of an attribute (by lexical QName).
494      *
495      * @param name The attribute name (a lexical QName).
496      * The prefix must match the prefix originally used. This method is defined in SAX, but is
497      * not recommended except where the prefix is null.
498      */

499
500     public String JavaDoc getValue(String JavaDoc name) {
501         int index = getIndex(name);
502         return getValue(index);
503     }
504
505     /**
506      * Find an attribute by expanded name
507      * @param uri the namespace uri
508      * @param localName the local name
509      * @return the index of the attribute, or -1 if absent
510      */

511
512     private int findByName(String JavaDoc uri, String JavaDoc localName) {
513         if (namePool == null) {
514             return -1; // indicates an empty attribute set
515
}
516         int f = namePool.getFingerprint(uri, localName);
517         if (f == -1) {
518             return -1;
519         }
520         return findByFingerprint(f);
521     }
522
523     /**
524      * Find an attribute by fingerprint
525      *
526      * @return the index of the attribute, or -1 if absent
527      */

528
529     private int findByFingerprint(int fingerprint) {
530         if (codes == null) {
531             return -1;
532         }
533         for (int i = 0; i < used; i++) {
534             if (fingerprint == (codes[i*RECSIZE + NAMECODE] & NamePool.FP_MASK)) {
535                 return i;
536             }
537         }
538         return -1;
539     }
540
541     /**
542      * Determine whether a given attribute has the is-ID property set
543      */

544
545     public boolean isId(int index) {
546         return getType(index).equals("ID") ||
547                 ((getNameCode(index) & NamePool.FP_MASK) == StandardNames.XML_ID);
548     }
549
550 }
551
552 //
553
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
554
// you may not use this file except in compliance with the License. You may obtain a copy of the
555
// License at http://www.mozilla.org/MPL/
556
//
557
// Software distributed under the License is distributed on an "AS IS" basis,
558
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
559
// See the License for the specific language governing rights and limitations under the License.
560
//
561
// The Original Code is: all this file.
562
//
563
// The Initial Developer of the Original Code is Michael H. Kay.
564
//
565
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
566
//
567
// Contributor(s): none.
568
//
569
Popular Tags