001 package com.thaiopensource.datatype.xsd; 002 003 import org.relaxng.datatype.DatatypeException; 004 import org.relaxng.datatype.DatatypeStreamingValidator; 005 import org.relaxng.datatype.ValidationContext; 006 import org.relaxng.datatype.helpers.StreamingValidatorImpl; 007 008 import com.thaiopensource.datatype.Datatype2; 009 010 abstract class DatatypeBase implements Datatype2 { 011 abstract boolean lexicallyAllows(String str); 012 private final int whiteSpace; 013 014 static final int WHITE_SPACE_PRESERVE = 0; 015 static final int WHITE_SPACE_REPLACE = 1; 016 static final int WHITE_SPACE_COLLAPSE = 2; 017 018 DatatypeBase() { 019 whiteSpace = WHITE_SPACE_COLLAPSE; 020 } 021 022 DatatypeBase(int whiteSpace) { 023 this.whiteSpace = whiteSpace; 024 } 025 026 int getWhiteSpace() { 027 return whiteSpace; 028 } 029 030 public boolean isValid(String str, ValidationContext vc) { 031 str = normalizeWhiteSpace(str); 032 return lexicallyAllows(str) && allowsValue(str, vc); 033 } 034 035 public void checkValid(String str, ValidationContext vc) throws DatatypeException { 036 if (!isValid(str, vc)) 037 throw new DatatypeException(); 038 } 039 040 public Object createValue(String str, ValidationContext vc) { 041 str = normalizeWhiteSpace(str); 042 if (!lexicallyAllows(str)) 043 return null; 044 return getValue(str, vc); 045 } 046 047 final String normalizeWhiteSpace(String str) { 048 switch (whiteSpace) { 049 case WHITE_SPACE_COLLAPSE: 050 return collapseWhiteSpace(str); 051 case WHITE_SPACE_REPLACE: 052 return replaceWhiteSpace(str); 053 } 054 return str; 055 } 056 057 /* Requires lexicallyAllows to be true. Must return same value as 058 getValue(str, vc) != null. */ 059 boolean allowsValue(String str, ValidationContext vc) { 060 return true; 061 } 062 063 /* Requires lexicallyAllows to be true. Returns null if value does not satisfy 064 constraints on value space. */ 065 abstract Object getValue(String str, ValidationContext vc); 066 067 OrderRelation getOrderRelation() { 068 return null; 069 } 070 071 /* For datatypes that have a length. */ 072 Measure getMeasure() { 073 return null; 074 } 075 076 static private final String collapseWhiteSpace(String s) { 077 int i = collapseStart(s); 078 if (i < 0) 079 return s; 080 StringBuffer buf = new StringBuffer(s.substring(0, i)); 081 boolean collapsing = (i == 0 || s.charAt(i - 1) == ' '); 082 for (int len = s.length(); i < len; i++) { 083 char c = s.charAt(i); 084 switch (c) { 085 case '\r': 086 case '\n': 087 case '\t': 088 case ' ': 089 if (!collapsing) { 090 buf.append(' '); 091 collapsing = true; 092 } 093 break; 094 default: 095 collapsing = false; 096 buf.append(c); 097 break; 098 } 099 } 100 if (buf.length() > 0 && buf.charAt(buf.length() - 1) == ' ') 101 buf.setLength(buf.length() - 1); 102 return buf.toString(); 103 } 104 105 static private final int collapseStart(String s) { 106 for (int i = 0, len = s.length(); i < len; i++) { 107 switch (s.charAt(i)) { 108 case ' ': 109 if (i == 0 || s.charAt(i - 1) == ' ' || i == len - 1) 110 return i; 111 break; 112 case '\r': 113 case '\n': 114 case '\t': 115 return i; 116 } 117 } 118 return -1; 119 } 120 121 static private final String replaceWhiteSpace(String s) { 122 int len = s.length(); 123 for (int i = 0; i < len; i++) 124 switch (s.charAt(i)) { 125 case '\r': 126 case '\n': 127 case '\t': 128 { 129 char[] buf = s.toCharArray(); 130 buf[i] = ' '; 131 for (++i; i < len; i++) 132 switch (buf[i]) { 133 case '\r': 134 case '\n': 135 case '\t': 136 buf[i] = ' '; 137 } 138 return new String(buf); 139 } 140 } 141 return s; 142 } 143 144 DatatypeBase getPrimitive() { 145 return this; 146 } 147 148 public boolean isContextDependent() { 149 return false; 150 } 151 152 public boolean alwaysValid() { 153 return false; 154 } 155 156 public int getIdType() { 157 return ID_TYPE_NULL; 158 } 159 160 public int valueHashCode(Object value) { 161 return value.hashCode(); 162 } 163 164 public boolean sameValue(Object value1, Object value2) { 165 return value1.equals(value2); 166 } 167 168 public DatatypeStreamingValidator createStreamingValidator(ValidationContext vc) { 169 return new StreamingValidatorImpl(this, vc); 170 } 171 }