1 package com.thaiopensource.relaxng.impl; 2 3 import org.relaxng.datatype.Datatype; 4 import org.xml.sax.ErrorHandler ; 5 import org.xml.sax.Locator ; 6 import org.xml.sax.SAXException ; 7 import org.xml.sax.SAXParseException ; 8 9 import java.util.Enumeration ; 10 import java.util.Hashtable ; 11 import java.util.Vector ; 12 13 import com.thaiopensource.xml.util.Name; 14 15 public class IdTypeMapBuilder { 16 private boolean hadError; 17 private final ErrorHandler eh; 18 private final PatternFunction idTypeFunction = new IdTypeFunction(); 19 private final IdTypeMapImpl idTypeMap = new IdTypeMapImpl(); 20 private final Hashtable elementProcessed = new Hashtable (); 21 private final Vector possibleConflicts = new Vector (); 22 23 private void notePossibleConflict(NameClass elementNameClass, NameClass attributeNameClass, Locator loc) { 24 possibleConflicts.addElement(new PossibleConflict(elementNameClass, attributeNameClass, loc)); 25 } 26 27 private static class WrappedSAXException extends RuntimeException { 28 private final SAXException cause; 29 WrappedSAXException(SAXException cause) { 30 this.cause = cause; 31 } 32 } 33 34 private static class PossibleConflict { 35 private final NameClass elementNameClass; 36 private final NameClass attributeNameClass; 37 private final Locator locator; 38 39 private PossibleConflict(NameClass elementNameClass, NameClass attributeNameClass, Locator locator) { 40 this.elementNameClass = elementNameClass; 41 this.attributeNameClass = attributeNameClass; 42 this.locator = locator; 43 } 44 } 45 46 private static class ScopedName { 47 private final Name elementName; 48 private final Name attributeName; 49 50 private ScopedName(Name elementName, Name attributeName) { 51 this.elementName = elementName; 52 this.attributeName = attributeName; 53 } 54 55 public int hashCode() { 56 return elementName.hashCode() ^ attributeName.hashCode(); 57 } 58 59 public boolean equals(Object obj) { 60 if (!(obj instanceof ScopedName)) 61 return false; 62 ScopedName other = (ScopedName)obj; 63 return elementName.equals(other.elementName) && attributeName.equals(other.attributeName); 64 } 65 } 66 67 private static class IdTypeMapImpl implements IdTypeMap { 68 private final Hashtable table = new Hashtable (); 69 public int getIdType(Name elementName, Name attributeName) { 70 Integer n = (Integer )table.get(new ScopedName(elementName, attributeName)); 71 if (n == null) 72 return Datatype.ID_TYPE_NULL; 73 return n.intValue(); 74 } 75 private void add(Name elementName, Name attributeName, int idType) { 76 table.put(new ScopedName(elementName, attributeName), new Integer (idType)); 77 } 78 } 79 80 private class IdTypeFunction extends AbstractPatternFunction { 81 public Object caseOther(Pattern p) { 82 return new Integer (Datatype.ID_TYPE_NULL); 83 } 84 85 public Object caseData(DataPattern p) { 86 return new Integer (p.getDatatype().getIdType()); 87 } 88 89 public Object caseDataExcept(DataExceptPattern p) { 90 return new Integer (p.getDatatype().getIdType()); 91 } 92 93 public Object caseValue(ValuePattern p) { 94 return new Integer (p.getDatatype().getIdType()); 95 } 96 } 97 98 private class BuildFunction extends AbstractPatternFunction { 99 private final NameClass elementNameClass; 100 private final Locator locator; 101 private final boolean attributeIsParent; 102 103 BuildFunction(NameClass elementNameClass, Locator locator) { 104 this.elementNameClass = elementNameClass; 105 this.locator = locator; 106 this.attributeIsParent = false; 107 } 108 109 BuildFunction(NameClass elementNameClass, Locator locator, boolean attributeIsParent) { 110 this.elementNameClass = elementNameClass; 111 this.locator = locator; 112 this.attributeIsParent = attributeIsParent; 113 } 114 115 private BuildFunction down() { 116 if (!attributeIsParent) 117 return this; 118 return new BuildFunction(elementNameClass, locator, false); 119 } 120 121 public Object caseChoice(ChoicePattern p) { 122 BuildFunction f = down(); 123 p.getOperand1().apply(f); 124 p.getOperand2().apply(f); 125 return null; 126 } 127 128 public Object caseInterleave(InterleavePattern p) { 129 BuildFunction f = down(); 130 p.getOperand1().apply(f); 131 p.getOperand2().apply(f); 132 return null; 133 } 134 135 public Object caseGroup(GroupPattern p) { 136 BuildFunction f = down(); 137 p.getOperand1().apply(f); 138 p.getOperand2().apply(f); 139 return null; 140 } 141 142 public Object caseOneOrMore(OneOrMorePattern p) { 143 p.getOperand().apply(down()); 144 return null; 145 } 146 147 public Object caseElement(ElementPattern p) { 148 if (elementProcessed.get(p) != null) 149 return null; 150 elementProcessed.put(p, p); 151 p.getContent().apply(new BuildFunction(p.getNameClass(), p.getLocator())); 152 return null; 153 } 154 155 public Object caseAttribute(AttributePattern p) { 156 int idType = ((Integer )p.getContent().apply(idTypeFunction)).intValue(); 157 if (idType != Datatype.ID_TYPE_NULL) { 158 NameClass attributeNameClass = p.getNameClass(); 159 if (!(attributeNameClass instanceof SimpleNameClass)) { 160 error("id_attribute_name_class", p.getLocator()); 161 return null; 162 } 163 elementNameClass.accept(new ElementNameClassVisitor(((SimpleNameClass)attributeNameClass).getName(), 164 locator, 165 idType)); 166 } 167 else 168 notePossibleConflict(elementNameClass, p.getNameClass(), locator); 169 p.getContent().apply(new BuildFunction(null, p.getLocator(), true)); 170 return null; 171 } 172 173 private void datatype(Datatype dt) { 174 if (dt.getIdType() != Datatype.ID_TYPE_NULL && !attributeIsParent) 175 error("id_parent", locator); 176 } 177 178 public Object caseData(DataPattern p) { 179 datatype(p.getDatatype()); 180 return null; 181 } 182 183 public Object caseDataExcept(DataExceptPattern p) { 184 datatype(p.getDatatype()); 185 p.getExcept().apply(down()); 186 return null; 187 } 188 189 public Object caseValue(ValuePattern p) { 190 datatype(p.getDatatype()); 191 return null; 192 } 193 194 public Object caseList(ListPattern p) { 195 p.getOperand().apply(down()); 196 return null; 197 } 198 199 public Object caseOther(Pattern p) { 200 return null; 201 } 202 } 203 204 private class ElementNameClassVisitor implements NameClassVisitor { 205 private final Name attributeName; 206 private final Locator locator; 207 private final int idType; 208 209 ElementNameClassVisitor(Name attributeName, Locator locator, int idType) { 210 this.attributeName = attributeName; 211 this.locator = locator; 212 this.idType = idType; 213 } 214 215 public void visitChoice(NameClass nc1, NameClass nc2) { 216 nc1.accept(this); 217 nc2.accept(this); 218 } 219 220 public void visitName(Name elementName) { 221 int tem = idTypeMap.getIdType(elementName, attributeName); 222 if (tem != Datatype.ID_TYPE_NULL && tem != idType) 223 error("id_type_conflict", elementName, attributeName, locator); 224 idTypeMap.add(elementName, attributeName, idType); 225 } 226 227 public void visitNsName(String ns) { 228 visitOther(); 229 } 230 231 public void visitNsNameExcept(String ns, NameClass nc) { 232 visitOther(); 233 } 234 235 public void visitAnyName() { 236 visitOther(); 237 } 238 239 public void visitAnyNameExcept(NameClass nc) { 240 visitOther(); 241 } 242 243 public void visitNull() { 244 } 245 246 public void visitError() { 247 } 248 249 private void visitOther() { 250 error("id_element_name_class", locator); 251 } 252 } 253 254 private void error(String key, Locator locator) { 255 hadError = true; 256 if (eh != null) 257 try { 258 eh.error(new SAXParseException (SchemaBuilderImpl.localizer.message(key), locator)); 259 } 260 catch (SAXException e) { 261 throw new WrappedSAXException(e); 262 } 263 } 264 265 private void error(String key, Name arg1, Name arg2, Locator locator) { 266 hadError = true; 267 if (eh != null) 268 try { 269 eh.error(new SAXParseException (SchemaBuilderImpl.localizer.message(key, NameFormatter.format(arg1), NameFormatter.format(arg2)), 270 locator)); 271 } 272 catch (SAXException e) { 273 throw new WrappedSAXException(e); 274 } 275 } 276 277 public IdTypeMapBuilder(ErrorHandler eh, Pattern pattern) throws SAXException { 278 this.eh = eh; 279 try { 280 pattern.apply(new BuildFunction(null, null)); 281 for (Enumeration e = possibleConflicts.elements(); 282 e.hasMoreElements();) { 283 PossibleConflict pc = (PossibleConflict)e.nextElement(); 284 if (pc.elementNameClass instanceof SimpleNameClass 285 && pc.attributeNameClass instanceof SimpleNameClass) { 286 Name elementName = ((SimpleNameClass)pc.elementNameClass).getName(); 287 Name attributeName = ((SimpleNameClass)pc.attributeNameClass).getName(); 288 int idType = idTypeMap.getIdType(elementName, 289 attributeName); 290 if (idType != Datatype.ID_TYPE_NULL) 291 error("id_type_conflict", elementName, attributeName, pc.locator); 292 } 293 else { 294 for (Enumeration f = idTypeMap.table.keys(); f.hasMoreElements();) { 295 ScopedName sn = (ScopedName)f.nextElement(); 296 if (pc.elementNameClass.contains(sn.elementName) 297 && pc.attributeNameClass.contains(sn.attributeName)) { 298 error("id_type_conflict", sn.elementName, sn.attributeName, pc.locator); 299 break; 300 } 301 } 302 } 303 } 304 } 305 catch (WrappedSAXException e) { 306 throw e.cause; 307 } 308 } 309 310 public IdTypeMap getIdTypeMap() { 311 if (hadError) 312 return null; 313 return idTypeMap; 314 } 315 } 316 | Popular Tags |