001: // Copyright (c) 2007 Per M.A. Bothner.
002: // This is free software; for specifics see ../../../COPYING.
003:
004: package gnu.kawa.xml;
005:
006: import gnu.bytecode.*;
007: import gnu.xml.*; /* #ifdef use:java.util.regex */
008: import java.util.regex.Pattern;
009: import java.util.regex.Matcher;
010:
011: /* #endif */
012:
013: public class XStringType extends XDataType {
014: /* #ifdef use:java.util.regex */
015: Pattern pattern;
016: /* #endif */
017:
018: static ClassType XStringType = ClassType
019: .make("gnu.kawa.xml.XString");
020:
021: public XStringType(String name, XDataType base, int typeCode,
022: String pattern) {
023: super (name, XStringType, typeCode);
024: baseType = base;
025: /* #ifdef use:java.util.regex */
026: if (pattern != null)
027: this .pattern = Pattern.compile(pattern);
028: /* #endif */
029: }
030:
031: public static final XStringType normalizedStringType = new XStringType(
032: "normalizedString", stringType,
033: NORMALIZED_STRING_TYPE_CODE, null);
034:
035: public static final XStringType tokenType = new XStringType(
036: "token", normalizedStringType, TOKEN_TYPE_CODE, null);
037:
038: public static final XStringType languageType = new XStringType(
039: "language", tokenType, LANGUAGE_TYPE_CODE,
040: "[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*");
041:
042: public static final XStringType NMTOKENType = new XStringType(
043: "NMTOKEN", tokenType, NMTOKEN_TYPE_CODE, "\\c+"); // FIXME check pattern
044:
045: public static final XStringType NameType = new XStringType("Name",
046: tokenType, NAME_TYPE_CODE, null);
047:
048: public static final XStringType NCNameType = new XStringType(
049: "NCName", NameType, NCNAME_TYPE_CODE, null);
050:
051: public static final XStringType IDType = new XStringType("ID",
052: NCNameType, ID_TYPE_CODE, null);
053:
054: public static final XStringType IDREFType = new XStringType(
055: "IDREF", NCNameType, IDREF_TYPE_CODE, null);
056:
057: public static final XStringType ENTITYType = new XStringType(
058: "ENTITY", NCNameType, ENTITY_TYPE_CODE, null);
059:
060: public boolean isInstance(Object obj) {
061: if (!(obj instanceof XString))
062: return false;
063: /*
064: if (this == stringType)
065: return true;
066: */
067: XDataType objType = ((XString) obj).getStringType();
068: while (objType != null) {
069: if (objType == this )
070: return true;
071: objType = objType.baseType;
072: }
073: return false;
074: }
075:
076: /** Check if the String matches the restrictions on this type.
077: * Assumes any normalization has been done.
078: * @return null on success or an error message otherwise.
079: */
080: public String matches(String value) {
081: boolean status;
082: switch (typeCode) {
083: case NORMALIZED_STRING_TYPE_CODE:
084: case TOKEN_TYPE_CODE:
085: // Assumes that TextUtils.replaceWhitespace returns the original
086: // string if it was original normalized.
087: // This is suboptimal, but the extra cost is minor when the string
088: // is already normalized, which presumably is the common case.
089: boolean collapse = typeCode == TOKEN_TYPE_CODE;
090: status = value == TextUtils.replaceWhitespace(value,
091: collapse);
092: break;
093: case NAME_TYPE_CODE:
094: status = XName.isName(value);
095: break;
096: case NCNAME_TYPE_CODE:
097: case ID_TYPE_CODE:
098: case IDREF_TYPE_CODE:
099: case ENTITY_TYPE_CODE:
100: status = XName.isNCName(value);
101: break;
102: case NMTOKEN_TYPE_CODE:
103: status = XName.isNmToken(value);
104: break;
105: default:
106: status = pattern == null
107: || pattern.matcher(value).matches();
108: }
109: // If we haven't returned a more specific error message:
110: return status ? null : "not a valid XML " + getName();
111: }
112:
113: public Object valueOf(String value) {
114: value = TextUtils.replaceWhitespace(value,
115: this != normalizedStringType);
116: String err = matches(value);
117: if (err != null) // we're not using err yet. FIXME.
118: throw new ClassCastException("cannot cast " + value
119: + " to " + name);
120: return new XString(value, this );
121: }
122:
123: public Object cast(Object value) {
124: if (value instanceof XString) {
125: XString xvalue = (XString) value;
126: if (xvalue.getStringType() == this )
127: return xvalue;
128: }
129: return valueOf((String) stringType.cast(value));
130: }
131:
132: public static XString makeNCName(String value) {
133: return (XString) NCNameType.valueOf(value);
134: }
135: }
|