1 /* 2 ****************************************************************************** 3 * Copyright (C) 2004, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ****************************************************************************** 6 */ 7 package org.unicode.cldr.tool; 8 9 import java.io.File; 10 import java.io.FileInputStream; 11 import java.io.IOException; 12 import java.io.PrintWriter; 13 import java.util.Collection; 14 import java.util.Comparator; 15 import java.util.HashMap; 16 import java.util.Iterator; 17 import java.util.Map; 18 import java.util.Set; 19 import java.util.TreeMap; 20 import java.util.TreeSet; 21 import java.util.regex.Matcher; 22 23 import org.unicode.cldr.util.CLDRFile; 24 import org.unicode.cldr.util.CLDRPaths; 25 import org.unicode.cldr.util.CldrUtility; 26 import org.unicode.cldr.util.DtdData; 27 import org.unicode.cldr.util.Factory; 28 import org.unicode.cldr.util.PathUtilities; 29 import org.unicode.cldr.util.PatternCache; 30 import org.unicode.cldr.util.StandardCodes; 31 import org.unicode.cldr.util.TransliteratorUtilities; 32 import org.xml.sax.Attributes; 33 import org.xml.sax.ContentHandler; 34 import org.xml.sax.InputSource; 35 import org.xml.sax.Locator; 36 import org.xml.sax.SAXException; 37 import org.xml.sax.XMLReader; 38 import org.xml.sax.ext.DeclHandler; 39 40 public class GenerateAttributeList { 41 Map<String, Map<String, Set<String>[]>> element_attribute_valueSet = new TreeMap<>(); 42 Set<String> allElements = new TreeSet<>(); 43 Map<String, String> defaults = new HashMap<>(); 44 GenerateAttributeList(Factory cldrFactory)45 public GenerateAttributeList(Factory cldrFactory) throws IOException { 46 addFromStandardCodes(); 47 addFromDTD(CLDRPaths.COMMON_DIRECTORY + "main/en.xml"); 48 addFromDTD(CLDRPaths.COMMON_DIRECTORY + "supplemental/characters.xml"); 49 addFromDirectory(CLDRPaths.COMMON_DIRECTORY + "collation/"); 50 addFromDirectory(CLDRPaths.COMMON_DIRECTORY + "main/"); 51 addFromDirectory(CLDRPaths.COMMON_DIRECTORY + "rbnf/"); 52 addFromDirectory(CLDRPaths.COMMON_DIRECTORY + "segments/"); 53 addFromDirectory(CLDRPaths.COMMON_DIRECTORY + "supplemental/"); 54 addFromDirectory(CLDRPaths.COMMON_DIRECTORY + "transforms/"); 55 } 56 57 /** 58 * 59 */ addFromStandardCodes()60 private void addFromStandardCodes() { 61 StandardCodes sc = StandardCodes.make(); 62 addFromStandardCodes(sc, "language"); 63 addFromStandardCodes(sc, "territory"); 64 addFromStandardCodes(sc, "script"); 65 addFromStandardCodes(sc, "variant"); 66 addFromStandardCodes(sc, "currency"); 67 addFromStandardCodes(sc, "tzid"); 68 } 69 70 /** 71 * 72 */ addFromStandardCodes(StandardCodes sc, String cat)73 private void addFromStandardCodes(StandardCodes sc, String cat) { 74 Collection<String> c = sc.getGoodAvailableCodes(cat); 75 String target = cat.equals("tzid") ? "zone" : cat; 76 for (Iterator<String> it = c.iterator(); it.hasNext();) { 77 String item = it.next(); 78 add(target, "type", item, true); 79 } 80 } 81 82 /** 83 * @throws IOException 84 * 85 */ addFromDTD(String filename)86 private void addFromDTD(String filename) throws IOException { 87 // StringBufferInputStream fis = new StringBufferInputStream( 88 // "<!DOCTYPE ldml SYSTEM \"http://www.unicode.org/cldr/dtd/1.2/ldml.dtd\"><ldml></ldml>"); 89 FileInputStream fis = new FileInputStream(filename); 90 try { 91 XMLReader xmlReader = CLDRFile.createXMLReader(true); 92 MyDeclHandler me = new MyDeclHandler(); 93 xmlReader.setProperty("http://xml.org/sax/properties/declaration-handler", me); 94 InputSource is = new InputSource(fis); 95 is.setSystemId(filename); 96 // xmlReader.setContentHandler(me); 97 // xmlReader.setErrorHandler(me); 98 xmlReader.parse(is); 99 } catch (Exception e) { 100 e.printStackTrace(); 101 } finally { 102 fis.close(); 103 } 104 } 105 addFromDirectory(String directory)106 private void addFromDirectory(String directory) throws IOException { 107 File dir = new File(directory); 108 directory = PathUtilities.getNormalizedPathString(dir); 109 String[] files = dir.list(); 110 for (int i = 0; i < files.length; ++i) { 111 if (files[i].startsWith(".#")) continue; 112 if (!files[i].endsWith(".xml")) continue; 113 String file = directory + File.separatorChar + files[i]; 114 if (new File(file).isDirectory()) continue; 115 addFromFiles(file); 116 } 117 } 118 addFromFiles(String file)119 private void addFromFiles(String file) throws IOException { 120 // StringBufferInputStream fis = new StringBufferInputStream( 121 // "<!DOCTYPE ldml SYSTEM \"http://www.unicode.org/cldr/dtd/1.2/ldml.dtd\"><ldml></ldml>"); 122 System.out.println(file); 123 FileInputStream fis = new FileInputStream(file); 124 try { 125 XMLReader xmlReader = CLDRFile.createXMLReader(true); 126 xmlReader.setContentHandler(new MyContentHandler()); 127 InputSource is = new InputSource(fis); 128 is.setSystemId(file); 129 130 // xmlReader.setErrorHandler(me); 131 // xmlReader.setProperty("http://xml.org/sax/properties/declaration-handler", me); 132 xmlReader.parse(is); 133 } catch (Exception e) { 134 System.err.println("Failure in " + file); 135 e.printStackTrace(); 136 } finally { 137 fis.close(); 138 } 139 } 140 add(String element, String attribute, String attributeValue, boolean dtd)141 void add(String element, String attribute, String attributeValue, boolean dtd) { 142 // fiddle the fields 143 if (element.equals("generation") && attribute.equals("date")) 144 attributeValue = "[date]"; 145 else if (element.equals("version") && attribute.equals("number")) 146 attributeValue = "[revision]"; 147 else if (attribute.equals("draft") 148 || attribute.equals("validSubLocales") 149 || attribute.equals("standard") 150 || attribute.equals("references")) 151 element = "[common]"; 152 else if (attribute.equals("alt")) { 153 int pos = attributeValue.indexOf("proposed"); 154 if (pos == 0) return; 155 if (pos > 0) attributeValue = attributeValue.substring(0, pos - 1); 156 element = "[common]"; 157 } 158 // now add 159 Map<String, Set<String>[]> attribute_valueSet = element_attribute_valueSet.get(element); 160 if (attribute_valueSet == null) element_attribute_valueSet.put(element, attribute_valueSet = new TreeMap<>()); 161 Set<String>[] valueSets = attribute_valueSet.get(attribute); 162 if (valueSets == null) { 163 Comparator<String> c = DtdData.getAttributeValueComparator(element, attribute); 164 valueSets = new Set[2]; 165 valueSets[0] = new TreeSet<>(c); 166 valueSets[1] = new TreeSet<>(); 167 attribute_valueSet.put(attribute, valueSets); 168 } 169 try { 170 valueSets[dtd ? 1 : 0].add(attributeValue); 171 } catch (Exception e) { 172 throw new IllegalArgumentException("Error with " + element 173 + ", " + attribute + ", " + attributeValue + ", " + dtd, e); 174 } 175 } 176 show(PrintWriter pw)177 void show(PrintWriter pw) { 178 pw.println("<html><head>"); 179 pw.println("<style>td,th { border-style: solid; border-width: 1; vertical-align: top }</style>"); 180 pw.println("</head><body>"); 181 pw.println("<p>Date: $" + 182 "Date$</p>"); 183 pw.println("<p>Version: " + ToolConstants.CHART_DISPLAY_VERSION + "</p>"); 184 pw.println("<table>"); 185 pw.println("<tr><th>Element</th><th>Attribute</th><th>Actual Attribute Values</th><th>Other DTD Attribute Values</th></tr>"); 186 187 // show those with no attributes 188 /* 189 * Set hasNoAttributes = new TreeSet(allElements); 190 * hasNoAttributes.removeAll(element_attribute_valueSet.keySet()); 191 * pw.print("<tr><td>"); 192 * pw.print(toString(hasNoAttributes)); 193 * pw.println("</td><td>{none}</td><td>{none}</td></tr>"); 194 */ 195 196 for (Iterator<String> it = element_attribute_valueSet.keySet().iterator(); it.hasNext();) { 197 String element = it.next(); 198 Map<String, Set<String>[]> attribute_valueSet = element_attribute_valueSet.get(element); 199 int size = attribute_valueSet.size(); 200 if (size == 0) continue; 201 boolean first = true; 202 for (Iterator<String> it2 = attribute_valueSet.keySet().iterator(); it2.hasNext();) { 203 String attribute = it2.next(); 204 Set<String>[] valueSets = attribute_valueSet.get(attribute); 205 pw.print("<tr>"); 206 if (first) { 207 first = false; 208 pw.print("<td" + (size == 1 ? "" : " rowSpan='" + attribute_valueSet.size() + "'") + ">" + element 209 + "</td>"); 210 } 211 pw.print("<td>" + attribute + "</td><td>"); 212 String defaultKey = element + "|" + attribute; 213 pw.print(toString(valueSets[0], defaultKey)); 214 pw.println("</td><td>"); 215 Set<String> toRemove = new TreeSet<>(valueSets[0]); 216 Set<String> remainder = new TreeSet<>(valueSets[1]); 217 remainder.removeAll(toRemove); 218 pw.print(toString(remainder, defaultKey)); 219 pw.println("</td></tr>"); 220 } 221 } 222 pw.println("</table>"); 223 pw.println(CldrUtility.ANALYTICS); 224 pw.println("</body></html>"); 225 } 226 227 /** 228 * 229 */ toString(Collection<String> source, String defaultKey)230 private String toString(Collection<String> source, String defaultKey) { 231 StringBuffer result = new StringBuffer(); 232 boolean first = true; 233 for (Iterator<String> it = source.iterator(); it.hasNext();) { 234 String value = it.next(); 235 if (first) 236 first = false; 237 else 238 result.append(", "); 239 final boolean isDefault = value.equals(defaults.get(defaultKey)); 240 if (isDefault) { 241 result.append("<b>"); 242 } 243 result.append(TransliteratorUtilities.toHTML.transform(value)); 244 if (isDefault) { 245 result.append("</b>"); 246 } 247 } 248 return result.toString(); 249 } 250 251 class MyDeclHandler implements DeclHandler { 252 253 Matcher idmatcher = PatternCache.get("[a-zA-Z][-_a-zA-Z0-9]*").matcher(""); 254 255 @Override attributeDecl(String eName, String aName, String type, String mode, String value)256 public void attributeDecl(String eName, String aName, String type, String mode, String value) 257 throws SAXException { 258 // System.out.println("Attribute\t" + eName + "\t" + aName + "\t" + type + "\t" + mode + "\t" + value); 259 if (value != null) { 260 add(eName, aName, value, true); 261 defaults.put(eName + "|" + aName, value); 262 } 263 idmatcher.reset(type); 264 while (idmatcher.find()) { 265 add(eName, aName, idmatcher.group(), true); 266 } 267 } 268 269 /* 270 * (non-Javadoc) 271 * 272 * @see org.xml.sax.ext.DeclHandler#elementDecl(java.lang.String, java.lang.String) 273 */ 274 @Override elementDecl(String name, String model)275 public void elementDecl(String name, String model) throws SAXException { 276 // TODO Auto-generated method stub 277 278 } 279 280 /* 281 * (non-Javadoc) 282 * 283 * @see org.xml.sax.ext.DeclHandler#internalEntityDecl(java.lang.String, java.lang.String) 284 */ 285 @Override internalEntityDecl(String name, String value)286 public void internalEntityDecl(String name, String value) throws SAXException { 287 // TODO Auto-generated method stub 288 289 } 290 291 /* 292 * (non-Javadoc) 293 * 294 * @see org.xml.sax.ext.DeclHandler#externalEntityDecl(java.lang.String, java.lang.String, java.lang.String) 295 */ 296 @Override externalEntityDecl(String name, String publicId, String systemId)297 public void externalEntityDecl(String name, String publicId, String systemId) throws SAXException { 298 // TODO Auto-generated method stub 299 300 } 301 } 302 303 class MyContentHandler implements ContentHandler { 304 305 /* 306 * (non-Javadoc) 307 * 308 * @see org.xml.sax.ContentHandler#endDocument() 309 */ 310 @Override endDocument()311 public void endDocument() throws SAXException { 312 // TODO Auto-generated method stub 313 314 } 315 316 /* 317 * (non-Javadoc) 318 * 319 * @see org.xml.sax.ContentHandler#startDocument() 320 */ 321 @Override startDocument()322 public void startDocument() throws SAXException { 323 // TODO Auto-generated method stub 324 325 } 326 327 /* 328 * (non-Javadoc) 329 * 330 * @see org.xml.sax.ContentHandler#characters(char[], int, int) 331 */ 332 @Override characters(char[] ch, int start, int length)333 public void characters(char[] ch, int start, int length) throws SAXException { 334 // TODO Auto-generated method stub 335 336 } 337 338 /* 339 * (non-Javadoc) 340 * 341 * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int) 342 */ 343 @Override ignorableWhitespace(char[] ch, int start, int length)344 public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { 345 // TODO Auto-generated method stub 346 347 } 348 349 /* 350 * (non-Javadoc) 351 * 352 * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String) 353 */ 354 @Override endPrefixMapping(String prefix)355 public void endPrefixMapping(String prefix) throws SAXException { 356 // TODO Auto-generated method stub 357 358 } 359 360 /* 361 * (non-Javadoc) 362 * 363 * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String) 364 */ 365 @Override skippedEntity(String name)366 public void skippedEntity(String name) throws SAXException { 367 // TODO Auto-generated method stub 368 369 } 370 371 /* 372 * (non-Javadoc) 373 * 374 * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator) 375 */ 376 @Override setDocumentLocator(Locator locator)377 public void setDocumentLocator(Locator locator) { 378 // TODO Auto-generated method stub 379 380 } 381 382 /* 383 * (non-Javadoc) 384 * 385 * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String) 386 */ 387 @Override processingInstruction(String target, String data)388 public void processingInstruction(String target, String data) throws SAXException { 389 // TODO Auto-generated method stub 390 391 } 392 393 /* 394 * (non-Javadoc) 395 * 396 * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String) 397 */ 398 @Override startPrefixMapping(String prefix, String uri)399 public void startPrefixMapping(String prefix, String uri) throws SAXException { 400 // TODO Auto-generated method stub 401 402 } 403 404 /* 405 * (non-Javadoc) 406 * 407 * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String) 408 */ 409 @Override endElement(String namespaceURI, String localName, String qName)410 public void endElement(String namespaceURI, String localName, String qName) throws SAXException { 411 // TODO Auto-generated method stub 412 413 } 414 415 /* 416 * (non-Javadoc) 417 * 418 * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, 419 * org.xml.sax.Attributes) 420 */ 421 @Override startElement(String namespaceURI, String localName, String qName, Attributes attributes)422 public void startElement(String namespaceURI, String localName, String qName, Attributes attributes) 423 throws SAXException { 424 if (attributes == null) return; 425 for (int i = 0; i < attributes.getLength(); ++i) { 426 String attribute = attributes.getQName(i); 427 String value = attributes.getValue(i); 428 add(qName, attribute, value, false); 429 } 430 } 431 } 432 getElement_attribute_valueSet()433 public Map<String, Map<String, Set<String>[]>> getElement_attribute_valueSet() { 434 return element_attribute_valueSet; 435 } 436 } 437