1 package com.thaiopensource.relaxng.impl; 2 3 import com.thaiopensource.validate.Validator; 4 import com.thaiopensource.relaxng.parse.sax.DtdContext; 5 import com.thaiopensource.xml.util.WellKnownNamespaces; 6 import com.thaiopensource.xml.util.Name; 7 import org.xml.sax.Attributes ; 8 import org.xml.sax.ErrorHandler ; 9 import org.xml.sax.Locator ; 10 import org.xml.sax.SAXException ; 11 import org.xml.sax.SAXParseException ; 12 import org.xml.sax.DTDHandler ; 13 import org.xml.sax.ContentHandler ; 14 15 import java.util.Hashtable ; 16 17 public class PatternValidator extends DtdContext implements Validator, ContentHandler , DTDHandler { 18 private final ValidatorPatternBuilder builder; 19 private final Pattern start; 20 private final ErrorHandler eh; 21 private Hashtable recoverPatternTable; 22 private PatternMemo memo; 23 private boolean hadError; 24 private boolean collectingCharacters; 25 private final StringBuffer charBuf = new StringBuffer (); 26 private PrefixMapping prefixMapping = new PrefixMapping("xml", WellKnownNamespaces.XML, null); 27 private Locator locator; 28 29 private static final class PrefixMapping { 30 private final String prefix; 31 private final String namespaceURI; 32 private final PrefixMapping previous; 33 34 PrefixMapping(String prefix, String namespaceURI, PrefixMapping prev) { 35 this.prefix = prefix; 36 this.namespaceURI = namespaceURI; 37 this.previous = prev; 38 } 39 40 PrefixMapping getPrevious() { 41 return previous; 42 } 43 } 44 45 private void startCollectingCharacters() { 46 if (!collectingCharacters) { 47 collectingCharacters = true; 48 charBuf.setLength(0); 49 } 50 } 51 52 private void flushCharacters() throws SAXException { 53 collectingCharacters = false; 54 int len = charBuf.length(); 55 for (int i = 0; i < len; i++) { 56 switch (charBuf.charAt(i)) { 57 case ' ': 58 case '\r': 59 case '\t': 60 case '\n': 61 break; 62 default: 63 text(); 64 return; 65 } 66 } 67 } 68 69 public void startElement(String namespaceURI, 70 String localName, 71 String qName, 72 Attributes atts) throws SAXException { 73 if (collectingCharacters) 74 flushCharacters(); 75 76 Name name = new Name(namespaceURI, localName); 77 if (!setMemo(memo.startTagOpenDeriv(name))) { 78 PatternMemo next = memo.startTagOpenRecoverDeriv(name); 79 if (!next.isNotAllowed()) 80 error("required_elements_missing"); 81 else { 82 next = builder.getPatternMemo(builder.makeAfter(findElement(name), memo.getPattern())); 83 error(next.isNotAllowed() ? "unknown_element" : "out_of_context_element", name); 84 } 85 memo = next; 86 } 87 int len = atts.getLength(); 88 for (int i = 0; i < len; i++) { 89 Name attName = new Name(atts.getURI(i), atts.getLocalName(i)); 90 91 if (!setMemo(memo.startAttributeDeriv(attName))) 92 error("impossible_attribute_ignored", attName); 93 else if (!setMemo(memo.dataDeriv(atts.getValue(i), this))) { 94 error("bad_attribute_value", attName); 95 memo = memo.recoverAfter(); 96 } 97 } 98 if (!setMemo(memo.endAttributes())) { 99 error("required_attributes_missing"); 101 memo = memo.ignoreMissingAttributes(); 102 } 103 if (memo.getPattern().getContentType() == Pattern.DATA_CONTENT_TYPE) 104 startCollectingCharacters(); 105 } 106 107 private PatternMemo fixAfter(PatternMemo p) { 108 return builder.getPatternMemo(p.getPattern().applyForPattern(new ApplyAfterFunction(builder) { 109 Pattern apply(Pattern p) { 110 return builder.makeEmpty(); 111 } 112 })); 113 } 114 115 public void endElement(String namespaceURI, 116 String localName, 117 String qName) throws SAXException { 118 if (collectingCharacters) { 121 collectingCharacters = false; 122 if (!setMemo(memo.textOnly())) { 123 error("only_text_not_allowed"); 124 memo = memo.recoverAfter(); 125 return; 126 } 127 final String data = charBuf.toString(); 128 if (!setMemo(memo.dataDeriv(data, this))) { 129 PatternMemo next = memo.recoverAfter(); 130 if (!memo.isNotAllowed()) { 131 if (!next.isNotAllowed() 132 || fixAfter(memo).dataDeriv(data, this).isNotAllowed()) 133 error("string_not_allowed"); 134 } 135 memo = next; 136 } 137 } 138 else if (!setMemo(memo.endTagDeriv())) { 139 PatternMemo next = memo.recoverAfter(); 140 if (!memo.isNotAllowed()) { 141 if (!next.isNotAllowed() 142 || fixAfter(memo).endTagDeriv().isNotAllowed()) 143 error("unfinished_element"); 144 } 145 memo = next; 146 } 147 } 148 149 public void characters(char ch[], int start, int length) throws SAXException { 150 if (collectingCharacters) { 151 charBuf.append(ch, start, length); 152 return; 153 } 154 for (int i = 0; i < length; i++) { 155 switch (ch[start + i]) { 156 case ' ': 157 case '\r': 158 case '\t': 159 case '\n': 160 break; 161 default: 162 text(); 163 return; 164 } 165 } 166 } 167 168 private void text() throws SAXException { 169 if (!setMemo(memo.mixedTextDeriv())) 170 error("text_not_allowed"); 171 } 172 173 public void endDocument() { 174 } 176 177 public void setDocumentLocator(Locator loc) { 178 locator = loc; 179 } 180 181 public void startDocument() throws SAXException { 182 if (memo.isNotAllowed()) 183 error("schema_allows_nothing"); 184 } 185 public void processingInstruction(String target, String date) { } 186 public void skippedEntity(String name) { } 187 public void ignorableWhitespace(char[] ch, int start, int len) { } 188 public void startPrefixMapping(String prefix, String uri) { 189 prefixMapping = new PrefixMapping(prefix, uri, prefixMapping); 190 } 191 public void endPrefixMapping(String prefix) { 192 prefixMapping = prefixMapping.getPrevious(); 193 } 194 195 public PatternValidator(Pattern pattern, ValidatorPatternBuilder builder, ErrorHandler eh) { 196 this.start = pattern; 197 this.builder = builder; 198 this.eh = eh; 199 reset(); 200 } 201 202 public void reset() { 203 hadError = false; 204 collectingCharacters = false; 205 locator = null; 206 memo = builder.getPatternMemo(start); 207 prefixMapping = new PrefixMapping("xml", WellKnownNamespaces.XML, null); 208 clearDtdContext(); 209 } 210 211 public ContentHandler getContentHandler() { 212 return this; 213 } 214 215 public DTDHandler getDTDHandler() { 216 return this; 217 } 218 219 private void error(String key) throws SAXException { 220 if (hadError && memo.isNotAllowed()) 221 return; 222 hadError = true; 223 eh.error(new SAXParseException (SchemaBuilderImpl.localizer.message(key), locator)); 224 } 225 226 private void error(String key, Name arg) throws SAXException { 227 error(key, NameFormatter.format(arg)); 228 } 229 230 private void error(String key, String arg) throws SAXException { 231 if (hadError && memo.isNotAllowed()) 232 return; 233 hadError = true; 234 eh.error(new SAXParseException (SchemaBuilderImpl.localizer.message(key, arg), locator)); 235 } 236 237 238 private boolean setMemo(PatternMemo m) { 239 if (m.isNotAllowed()) 240 return false; 241 else { 242 memo = m; 243 return true; 244 } 245 } 246 247 private Pattern findElement(Name name) { 248 if (recoverPatternTable == null) 249 recoverPatternTable = new Hashtable (); 250 Pattern p = (Pattern)recoverPatternTable.get(name); 251 if (p == null) { 252 p = FindElementFunction.findElement(builder, name, start); 253 recoverPatternTable.put(name, p); 254 } 255 return p; 256 } 257 258 public String resolveNamespacePrefix(String prefix) { 259 PrefixMapping tem = prefixMapping; 260 do { 261 if (tem.prefix.equals(prefix)) 262 return tem.namespaceURI; 263 tem = tem.previous; 264 } while (tem != null); 265 return null; 266 } 267 268 public String getBaseUri() { 269 return null; 270 } 271 } 272 | Popular Tags |