KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > type > BuiltInAtomicType


1 package net.sf.saxon.type;
2
3 import net.sf.saxon.Err;
4 import net.sf.saxon.ConversionContext;
5 import net.sf.saxon.expr.Expression;
6 import net.sf.saxon.expr.StaticContext;
7 import net.sf.saxon.functions.NormalizeSpace;
8 import net.sf.saxon.instruct.ValueOf;
9 import net.sf.saxon.om.*;
10 import net.sf.saxon.style.StandardNames;
11 import net.sf.saxon.trans.DynamicError;
12 import net.sf.saxon.trans.XPathException;
13 import net.sf.saxon.value.*;
14
15 import java.io.Serializable JavaDoc;
16
17 /**
18  * This class represents a built-in atomic type, which may be either a primitive type
19  * (such as xs:decimal or xs:anyURI) or a derived type (such as xs:ID or xdt:dayTimeDuration).
20  */

21
22 public class BuiltInAtomicType implements AtomicType, Serializable JavaDoc {
23
24     int fingerprint;
25     int baseFingerprint = -1;
26
27     public BuiltInAtomicType() {}
28
29     public BuiltInAtomicType(int fingerprint) {
30         this.fingerprint = fingerprint;
31     }
32
33     /**
34      * Get the most specific possible atomic type that all items in this SimpleType belong to
35      * @return the lowest common supertype of all member types
36      */

37
38     public AtomicType getCommonAtomicType() {
39         return this;
40     }
41
42     /**
43      * Get the validation status - always valid
44      */

45     public final int getValidationStatus() {
46         return VALIDATED;
47     }
48
49     /**
50      * Returns the value of the 'block' attribute for this type, as a bit-significant
51      * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION}
52      *
53      * @return the value of the 'block' attribute for this type
54      */

55
56     public final int getBlock() {
57         return 0;
58     }
59
60     /**
61      * Gets the integer code of the derivation method used to derive this type from its
62      * parent. Returns zero for primitive types.
63      *
64      * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION}
65      */

66
67     public final int getDerivationMethod() {
68         return SchemaType.DERIVATION_RESTRICTION;
69     }
70
71     /**
72      * Determines whether derivation (of a particular kind)
73      * from this type is allowed, based on the "final" property
74      *
75      * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST}
76      * @return true if this kind of derivation is allowed
77      */

78
79     public final boolean allowsDerivation(int derivation) {
80         return true;
81     }
82
83     public final void setBaseTypeFingerprint(int baseFingerprint) {
84         this.baseFingerprint = baseFingerprint;
85     }
86
87     /**
88      * Get the fingerprint of the name of this type
89      *
90      * @return the fingerprint. Returns an invented fingerprint for an anonymous type.
91      */

92
93     public int getFingerprint() {
94         return fingerprint;
95     }
96
97     /**
98      * Get the namecode of the name of this type. This includes the prefix from the original
99      * type declaration: in the case of built-in types, there may be a conventional prefix
100      * or there may be no prefix.
101      */

102
103     public int getNameCode() {
104         return fingerprint;
105     }
106
107     /**
108      * Get the display name of the type: that is, a lexical QName with an arbitrary prefix
109      *
110      * @return a lexical QName identifying the type
111      */

112
113     public String JavaDoc getDisplayName() {
114         return StandardNames.getDisplayName(fingerprint);
115     }
116
117     /**
118      * Test whether this SchemaType is a complex type
119      *
120      * @return true if this SchemaType is a complex type
121      */

122
123     public final boolean isComplexType() {
124         return false;
125     }
126
127     /**
128      * Returns the base type that this type inherits from. This method can be used to get the
129      * base type of a type that is known to be valid.
130      * If this type is a Simpletype that is a built in primitive type then null is returned.
131      *
132      * @return the base type.
133      * @throws IllegalStateException if this type is not valid.
134      */

135
136     public final SchemaType getBaseType() {
137         if (baseFingerprint == -1) {
138             return null;
139         } else {
140             return BuiltInSchemaFactory.getSchemaType(baseFingerprint);
141         }
142     }
143
144     /**
145      * Test whether a given item conforms to this type
146      *
147      * @param item The item to be tested
148      * @return true if the item is an instance of this type; false otherwise
149      */

150
151     public boolean matchesItem(Item item) {
152         if (item instanceof AtomicValue) {
153             AtomicValue value = (AtomicValue)item;
154             AtomicType type = (AtomicType)value.getItemType();
155             if (type.getFingerprint()==this.getFingerprint()) {
156                 // note, with compiled stylesheets one can have two objects representing
157
// the same type, so comparing identity is not safe
158
return true;
159             }
160             return Type.isSubType(type, this);
161         } else {
162             return false;
163         }
164     }
165
166     /**
167      * Get the type from which this item type is derived by restriction. This
168      * is the supertype in the XPath type heirarchy, as distinct from the Schema
169      * base type: this means that the supertype of xs:boolean is xdt:anyAtomicType,
170      * whose supertype is item() (rather than xs:anySimpleType).
171      *
172      * @return the supertype, or null if this type is item()
173      */

174
175     public ItemType getSuperType() {
176         SchemaType base = getBaseType();
177         if (base instanceof AnySimpleType) {
178             return AnyItemType.getInstance();
179         } else {
180             return (ItemType)base;
181         }
182     }
183
184     /**
185      * Get the primitive item type corresponding to this item type. For item(),
186      * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds,
187      * it is the value representing the node kind, for example Type.ELEMENT.
188      * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER.
189      * For other atomic types it is the primitive type as defined in XML Schema,
190      * except that INTEGER is considered to be a primitive type.
191      */

192
193     public ItemType getPrimitiveItemType() {
194         if (Type.isPrimitiveType(getFingerprint())) {
195              return this;
196          } else {
197              ItemType s = (ItemType)getBaseType();
198              if (s instanceof AtomicType) {
199                  return s.getPrimitiveItemType();
200              } else {
201                  return this;
202              }
203          }
204     }
205
206     /**
207      * Get the primitive type corresponding to this item type. For item(),
208      * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds,
209      * it is the value representing the node kind, for example Type.ELEMENT.
210      * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER.
211      * For other atomic types it is the primitive type as defined in XML Schema,
212      * except that INTEGER is considered to be a primitive type.
213      */

214
215     public int getPrimitiveType() {
216         int x = getFingerprint();
217         if (Type.isPrimitiveType(x)) {
218             return x;
219         } else {
220             SchemaType s = getBaseType();
221             if (s instanceof AtomicType) {
222                 return ((AtomicType)s).getPrimitiveType();
223             } else {
224                 return this.getFingerprint();
225             }
226         }
227     }
228
229     /**
230      * Determine whether this type is supported in a basic XSLT processor
231      */

232
233     public boolean isAllowedInBasicXSLT() {
234         int fp = getFingerprint();
235         return (Type.isPrimitiveType(fp) && fp != StandardNames.XS_NOTATION);
236     }
237
238     /**
239      * Produce a representation of this type name for use in error messages.
240      * Where this is a QName, it will use conventional prefixes
241      */

242
243     public String JavaDoc toString(NamePool pool) {
244         return getDisplayName();
245     }
246
247     /**
248      * Get the item type of the atomic values that will be produced when an item
249      * of this type is atomized
250      */

251
252     public AtomicType getAtomizedItemType() {
253         return this;
254     }
255
256     /**
257      * Returns the base type that this type inherits from. This method can be used to get the
258      * base type of a type that is known to be valid.
259      * If this type is a Simpletype that is a built in primitive type then null is returned.
260      *
261      * @return the base type.
262      * @throws IllegalStateException if this type is not valid.
263      */

264
265     public SchemaType getKnownBaseType() {
266         return getBaseType();
267     }
268
269     /**
270      * Test whether this is the same type as another type. They are considered to be the same type
271      * if they are derived from the same type definition in the original XML representation (which
272      * can happen when there are multiple includes of the same file)
273      */

274
275     public boolean isSameType(SchemaType other) {
276         return (other.getFingerprint() == this.getFingerprint());
277     }
278
279     public String JavaDoc getDescription() {
280         return getDisplayName();
281     }
282
283     public String JavaDoc toString() {
284         return getDisplayName();
285     }
286
287     /**
288      * Check that this type is validly derived from a given type
289      *
290      * @param type the type from which this type is derived
291      * @param block the derivations that are blocked by the relevant element declaration
292      * @throws SchemaException if the derivation is not allowed
293      */

294
295     public void isTypeDerivationOK(SchemaType type, int block) throws SchemaException, ValidationException {
296         //To change body of implemented methods use File | Settings | File Templates.
297
}
298
299     /**
300      * Returns true if this SchemaType is a SimpleType
301      *
302      * @return true (always)
303      */

304
305     public final boolean isSimpleType() {
306         return true;
307     }
308
309     /**
310      * Test whether this Simple Type is an atomic type
311      * @return true, this is an atomic type
312      */

313
314     public boolean isAtomicType() {
315         return true;
316     }
317
318
319     /**
320      * Returns true if this type is derived by list, or if it is derived by restriction
321      * from a list type, or if it is a union that contains a list as one of its members
322      *
323      * @return true if this is a list type
324      */

325
326     public boolean isListType() {
327         return false;
328     }
329
330     /**
331      * Return true if this type is a union type (that is, if its variety is union)
332      *
333      * @return true for a union type
334      */

335
336     public boolean isUnionType() {
337         return false;
338     }
339
340     /**
341      * Determine the whitespace normalization required for values of this type
342      *
343      * @return one of PRESERVE, REPLACE, COLLAPSE
344      */

345
346     public int getWhitespaceAction() {
347         if (getPrimitiveType() == Type.STRING) {
348             if (Type.isSubType(this,
349                     (ItemType)BuiltInSchemaFactory.getSchemaType(StandardNames.XS_TOKEN))) {
350                 return Whitespace.COLLAPSE;
351             } else if (Type.isSubType(this,
352                     (ItemType)BuiltInSchemaFactory.getSchemaType(StandardNames.XS_NORMALIZED_STRING))) {
353                 return Whitespace.REPLACE;
354             } else {
355                 return Whitespace.PRESERVE;
356             }
357         } else {
358             return Whitespace.COLLAPSE;
359         }
360     }
361
362     /**
363      * Apply the whitespace normalization rules for this simple type
364      *
365      * @param value the string before whitespace normalization
366      * @return the string after whitespace normalization
367      */

368
369     public CharSequence JavaDoc applyWhitespaceNormalization(CharSequence JavaDoc value) throws ValidationException {
370         int action = getWhitespaceAction();
371         switch (action) {
372             case Whitespace.PRESERVE:
373                 return value;
374             case Whitespace.REPLACE:
375                 FastStringBuffer sb = new FastStringBuffer(value.length());
376                 for (int i = 0; i < value.length(); i++) {
377                     if ("\n\r\t".indexOf(value.charAt(i)) >= 0) {
378                         sb.append(' ');
379                     } else {
380                         sb.append(value.charAt(i));
381                     }
382                 }
383                 return sb;
384             case Whitespace.COLLAPSE:
385                 return NormalizeSpace.normalize(value.toString());
386             default:
387                 throw new IllegalArgumentException JavaDoc("Unknown whitespace facet value");
388         }
389     }
390
391     /**
392      * Returns the built-in base type this type is derived from.
393      *
394      * @return the first built-in type found when searching up the type hierarchy
395      */

396     public SchemaType getBuiltInBaseType() throws ValidationException {
397         BuiltInAtomicType base = this;
398         while ((base != null) && (base.getFingerprint() > 1023)) {
399             base = (BuiltInAtomicType)base.getBaseType();
400         }
401         return base;
402     }
403
404     /**
405      * Test whether this simple type is namespace-sensitive, that is, whether
406      * it is derived from xs:QName or xs:NOTATION
407      *
408      * @return true if this type is derived from xs:QName or xs:NOTATION
409      */

410
411     public boolean isNamespaceSensitive() {
412         BuiltInAtomicType base = this;
413         int fp = base.getFingerprint();
414         while (fp > 1023) {
415             base = (BuiltInAtomicType)base.getBaseType();
416             fp = base.getFingerprint();
417         }
418
419         if (fp == StandardNames.XS_QNAME || fp == StandardNames.XS_NOTATION) {
420             return true;
421         }
422         return false;
423     }
424
425     /**
426      * Check whether a given input string is valid according to this SimpleType
427      *
428      * @param value the input string to be checked
429      * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type
430      * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive
431      * content will throw an UnsupportedOperationException.
432      * @param conversion
433      * @return XPathException if the value is invalid. Note that the exception is returned rather than being thrown.
434      * Returns null if the value is valid.
435      * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace
436      * resolver is supplied
437      */

438
439     public ValidationException validateContent(CharSequence JavaDoc value, NamespaceResolver nsResolver, ConversionContext conversion) {
440         int f = getFingerprint();
441         if (f==StandardNames.XS_STRING ||
442                 f==StandardNames.XS_ANY_SIMPLE_TYPE ||
443                 f==StandardNames.XDT_UNTYPED_ATOMIC ||
444                 f==StandardNames.XDT_ANY_ATOMIC_TYPE) {
445             return null;
446         }
447         ValidationException result = null;
448         if (isNamespaceSensitive()) {
449             if (nsResolver == null) {
450                 throw new UnsupportedOperationException JavaDoc("Cannot validate a QName without a namespace resolver");
451             }
452             try {
453                 String JavaDoc[] parts = Name.getQNameParts(value.toString());
454                 String JavaDoc uri = nsResolver.getURIForPrefix(parts[0], true);
455                 if (uri == null) {
456                     result = new ValidationException("Namespace prefix " + Err.wrap(parts[0]) +
457                             " has not been declared");
458                 }
459                 new QNameValue(parts[0], uri, parts[1]);
460             } catch (QNameException err) {
461                 result = new ValidationException("Invalid lexical QName " + Err.wrap(value));
462             } catch (XPathException err) {
463                 result = new ValidationException(err.getMessage());
464             }
465         } else {
466
467             Value v = StringValue.convertStringToBuiltInType(value, this, true);
468             if (v instanceof ValidationErrorValue) {
469                 result = new ValidationException("Value " + Err.wrap(value, Err.VALUE) + " is invalid for type "
470                         + getDisplayName() + ". " + ((ValidationErrorValue)v).getException().getMessage());
471             }
472         }
473         return result;
474     }
475
476     /**
477      * Get the typed value of a node that is annotated with this schema type
478      *
479      * @param node the node whose typed value is required
480      * @return an iterator over the items making up the typed value of this node. The objects
481      * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue}
482      */

483
484     public final SequenceIterator getTypedValue(NodeInfo node)
485             throws XPathException {
486         try {
487             return getTypedValue(node.getStringValue(), new InscopeNamespaceResolver(node), node.getConfiguration());
488         } catch (ValidationException err) {
489             throw new DynamicError("Internal error: value doesn't match its type annotation. " + err.getMessage());
490         }
491     }
492
493     /**
494      * Get the typed value of a node that is annotated with this schema type.
495      * The result of this method will always be consistent with the method
496      * {@link #getTypedValue}. However, this method is often more convenient and may be
497      * more efficient, especially in the common case where the value is expected to be a singleton.
498      *
499      * @param node the node whose typed value is required
500      * @return the typed value.
501      * @since 8.5
502      */

503
504     public Value atomize(NodeInfo node) throws XPathException {
505                 // Fast path for common cases
506
if (fingerprint == StandardNames.XS_STRING) {
507             return StringValue.makeStringValue(node.getStringValueCS());
508         } else if (fingerprint == StandardNames.XDT_UNTYPED_ATOMIC) {
509             return new UntypedAtomicValue(node.getStringValueCS());
510         } else if (isNamespaceSensitive()) {
511             try {
512                 NamespaceResolver resolver = new InscopeNamespaceResolver(node);
513                 String JavaDoc[] parts = Name.getQNameParts(node.getStringValueCS());
514                 String JavaDoc uri = resolver.getURIForPrefix(parts[0], true);
515                 if (uri == null) {
516                     throw new ValidationException("Namespace prefix " + Err.wrap(parts[0]) +
517                             " has not been declared");
518                 }
519                 return new QNameValue(parts[0], uri, parts[1]);
520             } catch (QNameException err) {
521                 throw new ValidationException("Invalid lexical QName " + Err.wrap(node.getStringValueCS()));
522             } catch (XPathException err) {
523                 throw new ValidationException(err.getMessage());
524             }
525         }
526         AtomicValue val = StringValue.convertStringToBuiltInType(node.getStringValueCS(), this, true);
527         if (val instanceof ValidationErrorValue) {
528             throw ((ValidationErrorValue)val).getException();
529         }
530         return val;
531     }
532
533     /**
534      * Get the typed value corresponding to a given string value, assuming it is
535      * valid against this type
536      *
537      * @param value the string value
538      * @param resolver a namespace resolver used to resolve any namespace prefixes appearing
539      * in the content of values. Can supply null, in which case any namespace-sensitive content
540      * will be rejected.
541      * @param conversion
542      * @return an iterator over the atomic sequence comprising the typed value. The objects
543      * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue}
544      */

545
546     public SequenceIterator getTypedValue(CharSequence JavaDoc value, NamespaceResolver resolver, ConversionContext conversion)
547             throws ValidationException {
548         // Fast path for common cases
549
if (fingerprint == StandardNames.XS_STRING) {
550             return SingletonIterator.makeIterator(StringValue.makeStringValue(value));
551         } else if (fingerprint == StandardNames.XDT_UNTYPED_ATOMIC) {
552             return SingletonIterator.makeIterator(new UntypedAtomicValue(value));
553         } else if (isNamespaceSensitive()) {
554             try {
555                 String JavaDoc[] parts = Name.getQNameParts(value.toString());
556                 String JavaDoc uri = resolver.getURIForPrefix(parts[0], true);
557                 if (uri == null) {
558                     throw new ValidationException("Namespace prefix " + Err.wrap(parts[0]) +
559                             " has not been declared");
560                 }
561                 return SingletonIterator.makeIterator(new QNameValue(parts[0], uri, parts[1]));
562             } catch (QNameException err) {
563                 throw new ValidationException("Invalid lexical QName " + Err.wrap(value));
564             } catch (XPathException err) {
565                 throw new ValidationException(err.getMessage());
566             }
567         }
568         AtomicValue val = StringValue.convertStringToBuiltInType(value, this, true);
569         if (val instanceof ValidationErrorValue) {
570             throw ((ValidationErrorValue)val).getException();
571         }
572         return SingletonIterator.makeIterator(val);
573     }
574
575
576     /**
577      * Factory method to create values of a derived atomic type. This method
578      * is not used to create values of a built-in type, even one that is not
579      * primitive.
580      *
581      * @param primValue the value in the value space of the primitive type
582      * @param lexicalValue the value in the lexical space. If null, the string value of primValue
583      * @param validate true if the value is to be validated against the facets of the derived
584      * type; false if the caller knows that the value is already valid.
585      */

586
587     public AtomicValue makeDerivedValue(AtomicValue primValue, CharSequence JavaDoc lexicalValue, boolean validate) {
588         throw new UnsupportedOperationException JavaDoc("makeDerivedValue is not supported for built-in types");
589     }
590
591     /**
592      * Analyze an expression to see whether the expression is capable of delivering a value of this
593      * type.
594      *
595      * @param expression the expression that delivers the content
596      * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT},
597      * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT}
598      * @param env
599      * @throws net.sf.saxon.trans.XPathException
600      * if the expression will never deliver a value of the correct type
601      */

602
603     public void analyzeContentExpression(Expression expression, int kind, StaticContext env) throws XPathException {
604         analyzeContentExpression(this, expression, env, kind);
605     }
606
607    /**
608      * Analyze an expression to see whether the expression is capable of delivering a value of this
609      * type.
610      * @param simpleType the simple type against which the expression is to be checked
611      * @param expression the expression that delivers the content
612      * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT},
613      * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT}
614      * @throws net.sf.saxon.trans.XPathException
615      * if the expression will never deliver a value of the correct type
616      */

617
618     public static void analyzeContentExpression(SimpleType simpleType, Expression expression, StaticContext env, int kind)
619     throws XPathException {
620         if (kind == Type.ELEMENT) {
621             expression.checkPermittedContents(simpleType, env, true);
622 // // if we are building the content of an element or document, no atomization will take
623
// // place, and therefore the presence of any element or attribute nodes in the content will
624
// // cause a validity error, since only simple content is allowed
625
// if (Type.isSubType(itemType, NodeKindTest.makeNodeKindTest(Type.ELEMENT))) {
626
// throw new StaticError("The content of an element with a simple type must not include any element nodes");
627
// }
628
// if (Type.isSubType(itemType, NodeKindTest.makeNodeKindTest(Type.ATTRIBUTE))) {
629
// throw new StaticError("The content of an element with a simple type must not include any attribute nodes");
630
// }
631
} else if (kind == Type.ATTRIBUTE) {
632             // for attributes, do a check only for text nodes and atomic values: anything else gets atomized
633
if (expression instanceof ValueOf || expression instanceof Value) {
634                 expression.checkPermittedContents(simpleType, env, true);
635             }
636         }
637     }
638 }
639
640 //
641
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
642
// you may not use this file except in compliance with the License. You may obtain a copy of the
643
// License at http://www.mozilla.org/MPL/
644
//
645
// Software distributed under the License is distributed on an "AS IS" basis,
646
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
647
// See the License for the specific language governing rights and limitations under the License.
648
//
649
// The Original Code is: all this file.
650
//
651
// The Initial Developer of the Original Code is Saxonica Limited
652
//
653
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
654
//
655
// Contributor(s): none
656
//
Popular Tags