001: package net.sf.saxon.type;
002:
003: import net.sf.saxon.Err;
004: import net.sf.saxon.expr.Expression;
005: import net.sf.saxon.expr.StaticContext;
006: import net.sf.saxon.expr.XPathContext;
007: import net.sf.saxon.instruct.ValueOf;
008: import net.sf.saxon.om.*;
009: import net.sf.saxon.style.StandardNames;
010: import net.sf.saxon.trans.DynamicError;
011: import net.sf.saxon.trans.XPathException;
012: import net.sf.saxon.value.*;
013:
014: import java.io.Serializable;
015:
016: /**
017: * This class represents a built-in atomic type, which may be either a primitive type
018: * (such as xs:decimal or xs:anyURI) or a derived type (such as xs:ID or xdt:dayTimeDuration).
019: */
020:
021: public class BuiltInAtomicType implements AtomicType, Serializable {
022:
023: int fingerprint;
024: int baseFingerprint = -1;
025:
026: public BuiltInAtomicType() {
027: }
028:
029: public BuiltInAtomicType(int fingerprint) {
030: this .fingerprint = fingerprint;
031: }
032:
033: /**
034: * Get the most specific possible atomic type that all items in this SimpleType belong to
035: * @return the lowest common supertype of all member types
036: */
037:
038: public AtomicType getCommonAtomicType() {
039: return this ;
040: }
041:
042: /**
043: * Get the validation status - always valid
044: */
045: public final int getValidationStatus() {
046: return VALIDATED;
047: }
048:
049: /**
050: * Returns the value of the 'block' attribute for this type, as a bit-significant
051: * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION}
052: *
053: * @return the value of the 'block' attribute for this type
054: */
055:
056: public final int getBlock() {
057: return 0;
058: }
059:
060: /**
061: * Gets the integer code of the derivation method used to derive this type from its
062: * parent. Returns zero for primitive types.
063: *
064: * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION}
065: */
066:
067: public final int getDerivationMethod() {
068: return SchemaType.DERIVATION_RESTRICTION;
069: }
070:
071: /**
072: * Determines whether derivation (of a particular kind)
073: * from this type is allowed, based on the "final" property
074: *
075: * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST}
076: * @return true if this kind of derivation is allowed
077: */
078:
079: public final boolean allowsDerivation(int derivation) {
080: return true;
081: }
082:
083: public final void setBaseTypeFingerprint(int baseFingerprint) {
084: this .baseFingerprint = baseFingerprint;
085: }
086:
087: /**
088: * Get the fingerprint of the name of this type
089: *
090: * @return the fingerprint. Returns an invented fingerprint for an anonymous type.
091: */
092:
093: public int getFingerprint() {
094: return fingerprint;
095: }
096:
097: /**
098: * Get the namecode of the name of this type. This includes the prefix from the original
099: * 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 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: * @param context
149: * @return true if the item is an instance of this type; false otherwise
150: */
151:
152: public boolean matchesItem(Item item, XPathContext context) {
153: if (item instanceof AtomicValue) {
154: AtomicValue value = (AtomicValue) item;
155: AtomicType type = (AtomicType) value.getItemType(null);
156: if (type.getFingerprint() == this .getFingerprint()) {
157: // note, with compiled stylesheets one can have two objects representing
158: // the same type, so comparing identity is not safe
159: return true;
160: }
161: return context.getNamePool().getTypeHierarchy().isSubType(
162: type, this );
163: } else {
164: return false;
165: }
166: }
167:
168: /**
169: * Get the type from which this item type is derived by restriction. This
170: * is the supertype in the XPath type heirarchy, as distinct from the Schema
171: * base type: this means that the supertype of xs:boolean is xdt:anyAtomicType,
172: * whose supertype is item() (rather than xs:anySimpleType).
173: *
174: * @return the supertype, or null if this type is item()
175: * @param th
176: */
177:
178: public ItemType getSuperType(TypeHierarchy th) {
179: SchemaType base = getBaseType();
180: if (base instanceof AnySimpleType) {
181: return AnyItemType.getInstance();
182: } else {
183: return (ItemType) base;
184: }
185: }
186:
187: /**
188: * Get the primitive item type corresponding to this item type. For item(),
189: * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds,
190: * it is the value representing the node kind, for example Type.ELEMENT.
191: * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER.
192: * For other atomic types it is the primitive type as defined in XML Schema,
193: * except that INTEGER is considered to be a primitive type.
194: */
195:
196: public ItemType getPrimitiveItemType() {
197: if (Type.isPrimitiveType(getFingerprint())) {
198: return this ;
199: } else {
200: ItemType s = (ItemType) getBaseType();
201: if (s instanceof AtomicType) {
202: return s.getPrimitiveItemType();
203: } else {
204: return this ;
205: }
206: }
207: }
208:
209: /**
210: * Get the primitive type corresponding to this item type. For item(),
211: * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds,
212: * it is the value representing the node kind, for example Type.ELEMENT.
213: * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER.
214: * For other atomic types it is the primitive type as defined in XML Schema,
215: * except that INTEGER is considered to be a primitive type.
216: */
217:
218: public int getPrimitiveType() {
219: int x = getFingerprint();
220: if (Type.isPrimitiveType(x)) {
221: return x;
222: } else {
223: SchemaType s = getBaseType();
224: if (s instanceof AtomicType) {
225: return ((AtomicType) s).getPrimitiveType();
226: } else {
227: return this .getFingerprint();
228: }
229: }
230: }
231:
232: /**
233: * Determine whether this type is supported in a basic XSLT processor
234: */
235:
236: public boolean isAllowedInBasicXSLT() {
237: int fp = getFingerprint();
238: return (Type.isPrimitiveType(fp) && fp != StandardNames.XS_NOTATION);
239: }
240:
241: /**
242: * Produce a representation of this type name for use in error messages.
243: * Where this is a QName, it will use conventional prefixes
244: */
245:
246: public String toString(NamePool pool) {
247: return getDisplayName();
248: }
249:
250: /**
251: * Get the item type of the atomic values that will be produced when an item
252: * of this type is atomized
253: */
254:
255: public AtomicType getAtomizedItemType() {
256: return this ;
257: }
258:
259: /**
260: * Returns the base type that this type inherits from. This method can be used to get the
261: * base type of a type that is known to be valid.
262: * If this type is a Simpletype that is a built in primitive type then null is returned.
263: *
264: * @return the base type.
265: * @throws IllegalStateException if this type is not valid.
266: */
267:
268: public SchemaType getKnownBaseType() {
269: return getBaseType();
270: }
271:
272: /**
273: * Test whether this is the same type as another type. They are considered to be the same type
274: * if they are derived from the same type definition in the original XML representation (which
275: * can happen when there are multiple includes of the same file)
276: */
277:
278: public boolean isSameType(SchemaType other) {
279: return (other.getFingerprint() == this .getFingerprint());
280: }
281:
282: public String getDescription() {
283: return getDisplayName();
284: }
285:
286: public String toString() {
287: return getDisplayName();
288: }
289:
290: /**
291: * Check that this type is validly derived from a given type
292: *
293: * @param type the type from which this type is derived
294: * @param block the derivations that are blocked by the relevant element declaration
295: * @throws SchemaException if the derivation is not allowed
296: */
297:
298: public void isTypeDerivationOK(SchemaType type, int block)
299: throws SchemaException, ValidationException {
300: //To change body of implemented methods use File | Settings | File Templates.
301: }
302:
303: /**
304: * Returns true if this SchemaType is a SimpleType
305: *
306: * @return true (always)
307: */
308:
309: public final boolean isSimpleType() {
310: return true;
311: }
312:
313: /**
314: * Test whether this Simple Type is an atomic type
315: * @return true, this is an atomic type
316: */
317:
318: public boolean isAtomicType() {
319: return true;
320: }
321:
322: /**
323: * Returns true if this type is derived by list, or if it is derived by restriction
324: * from a list type, or if it is a union that contains a list as one of its members
325: *
326: * @return true if this is a list type
327: */
328:
329: public boolean isListType() {
330: return false;
331: }
332:
333: /**
334: * Return true if this type is a union type (that is, if its variety is union)
335: *
336: * @return true for a union type
337: */
338:
339: public boolean isUnionType() {
340: return false;
341: }
342:
343: /**
344: * Determine the whitespace normalization required for values of this type
345: *
346: * @return one of PRESERVE, REPLACE, COLLAPSE
347: * @param th
348: */
349:
350: public int getWhitespaceAction(TypeHierarchy th) {
351: if (getPrimitiveType() == Type.STRING) {
352: if (th.isSubType(this , (ItemType) BuiltInSchemaFactory
353: .getSchemaType(StandardNames.XS_TOKEN))) {
354: return Whitespace.COLLAPSE;
355: } else if (th
356: .isSubType(
357: this ,
358: (ItemType) BuiltInSchemaFactory
359: .getSchemaType(StandardNames.XS_NORMALIZED_STRING))) {
360: return Whitespace.REPLACE;
361: } else {
362: return Whitespace.PRESERVE;
363: }
364: } else {
365: return Whitespace.COLLAPSE;
366: }
367: }
368:
369: /**
370: * Returns the built-in base type this type is derived from.
371: *
372: * @return the first built-in type found when searching up the type hierarchy
373: */
374: public SchemaType getBuiltInBaseType() throws ValidationException {
375: BuiltInAtomicType base = this ;
376: while ((base != null) && (base.getFingerprint() > 1023)) {
377: base = (BuiltInAtomicType) base.getBaseType();
378: }
379: return base;
380: }
381:
382: /**
383: * Test whether this simple type is namespace-sensitive, that is, whether
384: * it is derived from xs:QName or xs:NOTATION
385: *
386: * @return true if this type is derived from xs:QName or xs:NOTATION
387: */
388:
389: public boolean isNamespaceSensitive() {
390: BuiltInAtomicType base = this ;
391: int fp = base.getFingerprint();
392: while (fp > 1023) {
393: base = (BuiltInAtomicType) base.getBaseType();
394: fp = base.getFingerprint();
395: }
396:
397: if (fp == StandardNames.XS_QNAME
398: || fp == StandardNames.XS_NOTATION) {
399: return true;
400: }
401: return false;
402: }
403:
404: /**
405: * Check whether a given input string is valid according to this SimpleType
406: *
407: * @param value the input string to be checked
408: * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type
409: * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive
410: * content will throw an UnsupportedOperationException.
411: * @param nameChecker
412: * @return XPathException if the value is invalid. Note that the exception is returned rather than being thrown.
413: * Returns null if the value is valid.
414: * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace
415: * resolver is supplied
416: */
417:
418: public ValidationException validateContent(CharSequence value,
419: NamespaceResolver nsResolver, NameChecker nameChecker) {
420: int f = getFingerprint();
421: if (f == StandardNames.XS_STRING
422: || f == StandardNames.XS_ANY_SIMPLE_TYPE
423: || f == StandardNames.XDT_UNTYPED_ATOMIC
424: || f == StandardNames.XDT_ANY_ATOMIC_TYPE) {
425: return null;
426: }
427: ValidationException result = null;
428: if (isNamespaceSensitive()) {
429: if (nsResolver == null) {
430: throw new UnsupportedOperationException(
431: "Cannot validate a QName without a namespace resolver");
432: }
433: try {
434: String[] parts = nameChecker.getQNameParts(value
435: .toString());
436: String uri = nsResolver.getURIForPrefix(parts[0], true);
437: if (uri == null) {
438: result = new ValidationException(
439: "Namespace prefix " + Err.wrap(parts[0])
440: + " has not been declared");
441: }
442: new QNameValue(parts[0], uri, parts[1], nameChecker);
443: } catch (QNameException err) {
444: result = new ValidationException(
445: "Invalid lexical QName " + Err.wrap(value));
446: } catch (XPathException err) {
447: result = new ValidationException(err.getMessage());
448: }
449: } else {
450:
451: Value v = StringValue.convertStringToBuiltInType(value,
452: this , nameChecker);
453: if (v instanceof ValidationErrorValue) {
454: result = new ValidationException("Value "
455: + Err.wrap(value, Err.VALUE)
456: + " is invalid for type "
457: + getDisplayName()
458: + ". "
459: + ((ValidationErrorValue) v).getException()
460: .getMessage());
461: }
462: }
463: return result;
464: }
465:
466: /**
467: * Get the typed value of a node that is annotated with this schema type
468: *
469: * @param node the node whose typed value is required
470: * @return an iterator over the items making up the typed value of this node. The objects
471: * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue}
472: */
473:
474: public final SequenceIterator getTypedValue(NodeInfo node)
475: throws XPathException {
476: try {
477: return getTypedValue(node.getStringValue(),
478: new InscopeNamespaceResolver(node), node
479: .getConfiguration().getNameChecker());
480: } catch (ValidationException err) {
481: throw new DynamicError(
482: "Internal error: value doesn't match its type annotation. "
483: + err.getMessage());
484: }
485: }
486:
487: /**
488: * Get the typed value of a node that is annotated with this schema type.
489: * The result of this method will always be consistent with the method
490: * {@link #getTypedValue}. However, this method is often more convenient and may be
491: * more efficient, especially in the common case where the value is expected to be a singleton.
492: *
493: * @param node the node whose typed value is required
494: * @return the typed value.
495: * @since 8.5
496: */
497:
498: public Value atomize(NodeInfo node) throws XPathException {
499: // Fast path for common cases
500: if (fingerprint == StandardNames.XS_STRING) {
501: return StringValue.makeStringValue(node.getStringValueCS());
502: } else if (fingerprint == StandardNames.XDT_UNTYPED_ATOMIC) {
503: return new UntypedAtomicValue(node.getStringValueCS());
504: }
505: final NameChecker checker = node.getConfiguration()
506: .getNameChecker();
507: if (isNamespaceSensitive()) {
508: try {
509: NamespaceResolver resolver = new InscopeNamespaceResolver(
510: node);
511: String[] parts = checker.getQNameParts(node
512: .getStringValueCS());
513: String uri = resolver.getURIForPrefix(parts[0], true);
514: if (uri == null) {
515: throw new ValidationException("Namespace prefix "
516: + Err.wrap(parts[0])
517: + " has not been declared");
518: }
519: return new QNameValue(parts[0], uri, parts[1], checker);
520: } catch (QNameException err) {
521: throw new ValidationException("Invalid lexical QName "
522: + Err.wrap(node.getStringValueCS()));
523: } catch (XPathException err) {
524: throw new ValidationException(err.getMessage());
525: }
526: }
527: AtomicValue val = StringValue.convertStringToBuiltInType(node
528: .getStringValueCS(), this , checker);
529: if (val instanceof ValidationErrorValue) {
530: throw ((ValidationErrorValue) val).getException();
531: }
532: return val;
533: }
534:
535: /**
536: * Get the typed value corresponding to a given string value, assuming it is
537: * valid against this type
538: *
539: * @param value the string value
540: * @param resolver a namespace resolver used to resolve any namespace prefixes appearing
541: * in the content of values. Can supply null, in which case any namespace-sensitive content
542: * will be rejected.
543: * @param nameChecker
544: * @return an iterator over the atomic sequence comprising the typed value. The objects
545: * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue}
546: */
547:
548: public SequenceIterator getTypedValue(CharSequence value,
549: NamespaceResolver resolver, NameChecker nameChecker)
550: throws ValidationException {
551: // Fast path for common cases
552: if (fingerprint == StandardNames.XS_STRING) {
553: return SingletonIterator.makeIterator(StringValue
554: .makeStringValue(value));
555: } else if (fingerprint == StandardNames.XDT_UNTYPED_ATOMIC) {
556: return SingletonIterator
557: .makeIterator(new UntypedAtomicValue(value));
558: } else if (isNamespaceSensitive()) {
559: try {
560: String[] parts = nameChecker.getQNameParts(value
561: .toString());
562: String uri = resolver.getURIForPrefix(parts[0], true);
563: if (uri == null) {
564: throw new ValidationException("Namespace prefix "
565: + Err.wrap(parts[0])
566: + " has not been declared");
567: }
568: return SingletonIterator.makeIterator(new QNameValue(
569: parts[0], uri, parts[1], nameChecker));
570: } catch (QNameException err) {
571: throw new ValidationException("Invalid lexical QName "
572: + Err.wrap(value));
573: } catch (XPathException err) {
574: throw new ValidationException(err.getMessage());
575: }
576: }
577: AtomicValue val = StringValue.convertStringToBuiltInType(value,
578: this , nameChecker);
579: if (val instanceof ValidationErrorValue) {
580: throw ((ValidationErrorValue) val).getException();
581: }
582: return SingletonIterator.makeIterator(val);
583: }
584:
585: /**
586: * Factory method to create values of a derived atomic type. This method
587: * is not used to create values of a built-in type, even one that is not
588: * primitive.
589: *
590: * @param primValue the value in the value space of the primitive type
591: * @param lexicalValue the value in the lexical space. If null, the string value of primValue
592: * @param validate true if the value is to be validated against the facets of the derived
593: * type; false if the caller knows that the value is already valid.
594: */
595:
596: public AtomicValue makeDerivedValue(AtomicValue primValue,
597: CharSequence lexicalValue, boolean validate) {
598: throw new UnsupportedOperationException(
599: "makeDerivedValue is not supported for built-in types");
600: }
601:
602: /**
603: * Analyze an expression to see whether the expression is capable of delivering a value of this
604: * type.
605: *
606: * @param expression the expression that delivers the content
607: * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT},
608: * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT}
609: * @param env
610: * @throws net.sf.saxon.trans.XPathException
611: * if the expression will never deliver a value of the correct type
612: */
613:
614: public void analyzeContentExpression(Expression expression,
615: int kind, StaticContext env) throws XPathException {
616: analyzeContentExpression(this , expression, env, kind);
617: }
618:
619: /**
620: * Analyze an expression to see whether the expression is capable of delivering a value of this
621: * type.
622: * @param simpleType the simple type against which the expression is to be checked
623: * @param expression the expression that delivers the content
624: * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT},
625: * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT}
626: * @throws net.sf.saxon.trans.XPathException
627: * if the expression will never deliver a value of the correct type
628: */
629:
630: public static void analyzeContentExpression(SimpleType simpleType,
631: Expression expression, StaticContext env, int kind)
632: throws XPathException {
633: if (kind == Type.ELEMENT) {
634: expression.checkPermittedContents(simpleType, env, true);
635: // // if we are building the content of an element or document, no atomization will take
636: // // place, and therefore the presence of any element or attribute nodes in the content will
637: // // cause a validity error, since only simple content is allowed
638: // if (Type.isSubType(itemType, NodeKindTest.makeNodeKindTest(Type.ELEMENT))) {
639: // throw new StaticError("The content of an element with a simple type must not include any element nodes");
640: // }
641: // if (Type.isSubType(itemType, NodeKindTest.makeNodeKindTest(Type.ATTRIBUTE))) {
642: // throw new StaticError("The content of an element with a simple type must not include any attribute nodes");
643: // }
644: } else if (kind == Type.ATTRIBUTE) {
645: // for attributes, do a check only for text nodes and atomic values: anything else gets atomized
646: if (expression instanceof ValueOf
647: || expression instanceof Value) {
648: expression
649: .checkPermittedContents(simpleType, env, true);
650: }
651: }
652: }
653: }
654:
655: //
656: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
657: // you may not use this file except in compliance with the License. You may obtain a copy of the
658: // License at http://www.mozilla.org/MPL/
659: //
660: // Software distributed under the License is distributed on an "AS IS" basis,
661: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
662: // See the License for the specific language governing rights and limitations under the License.
663: //
664: // The Original Code is: all this file.
665: //
666: // The Initial Developer of the Original Code is Saxonica Limited
667: //
668: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
669: //
670: // Contributor(s): none
671: //
|