1 /* 2 ******************************************************************************* 3 * Copyright (C) 2003-2012, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7 /** 8 * @author Ram Viswanadha 9 */ 10 package org.unicode.cldr.icu; 11 12 import java.io.File; 13 import java.io.FileOutputStream; 14 import java.io.OutputStreamWriter; 15 import java.io.PrintWriter; 16 import java.util.Calendar; 17 import java.util.Enumeration; 18 import java.util.Hashtable; 19 import java.util.Iterator; 20 import java.util.Map; 21 import java.util.Set; 22 import java.util.TreeMap; 23 import java.util.TreeSet; 24 import java.util.Vector; 25 26 import org.unicode.cldr.util.LDMLUtilities; 27 import org.w3c.dom.Document; 28 import org.w3c.dom.NamedNodeMap; 29 import org.w3c.dom.Node; 30 import org.w3c.dom.NodeList; 31 32 import com.ibm.icu.lang.UCharacter; 33 import com.ibm.icu.text.Collator; 34 import com.ibm.icu.text.DecimalFormat; 35 import com.ibm.icu.text.Normalizer; 36 import com.ibm.icu.text.RuleBasedCollator; 37 import com.ibm.icu.util.ULocale; 38 39 public class LDMLComparator { 40 /* 41 * This application will compare different locale data xml files 42 * conforming to localeElements.dtd and produces an xml file file 43 * in the format 44 */ 45 private static final int OPT_DIFF = 0x4000; /* 2exp15 */// PN 46 private static final int OPT_DIFF_REF_COMMON = 0x8000; /* 2exp16 */// PN 47 private static final int OPT_BULK = 0x00010000; // PN 48 private static final int OPT_CASE_SENSITIVE = 0x00020000; // PN 49 private static final int OPT_VETTING = 0x00040000; 50 private static final int OPT_UNKNOWN = 0x00080000; 51 52 private static final String COMMON = "common"; 53 private static final String ICU = "icu"; 54 private static final String IBM_TOR = "ibm"; 55 private static final String WINDOWS = "windows"; 56 private static final String SUNJDK = "sunjdk"; 57 private static final String IBMJDK = "ibmjdk"; 58 private static final String HPUX = "hp"; 59 private static final String APPLE = "apple"; 60 private static final String SOLARIS = "solaris"; 61 private static final String OPEN_OFFICE = "open_office"; 62 private static final String AIX = "aix"; 63 private static final String LINUX = "linux"; 64 65 private static final String ALTERNATE_TITLE = "(Original)"; 66 private static final String ALT_COLOR = "#DDDDFD"; 67 // PN added 68 private static final String DIFF = "diff"; 69 private static final String DIFF_REF_COMMON = "diff_ref_common"; 70 private static final String BULK = "bulk"; 71 private static final String CASE_SENSITIVE = "case_sensitive"; 72 private static final String VETTING = "vetting"; 73 private static final String[] PLATFORM_PRINT_ORDER = { 74 COMMON, 75 ICU, 76 WINDOWS, 77 SUNJDK, 78 IBMJDK, 79 IBM_TOR, 80 APPLE, 81 SOLARIS, 82 OPEN_OFFICE, 83 AIX, 84 LINUX, 85 HPUX, 86 }; 87 88 private static final String USER_OPTIONS[] = { 89 "-" + COMMON, 90 "-" + ICU, 91 "-" + IBM_TOR, 92 "-" + WINDOWS, 93 "-" + SUNJDK, 94 "-" + IBMJDK, 95 "-" + HPUX, 96 "-" + APPLE, 97 "-" + SOLARIS, 98 "-" + OPEN_OFFICE, 99 "-" + AIX, 100 "-" + LINUX, 101 "-s", 102 "-d", 103 "-" + DIFF, // PN added, indicates that only differing elements/attributes to be written to html 104 "-" + DIFF_REF_COMMON, // PN added, same as diff only common is excluded from diff but gets printed to html for 105 // reference purposes 106 "-" + BULK, // do a bulk comparison of folder contents 107 "-" + CASE_SENSITIVE, // do case sensitive matching (by default it's not case sensitive) 108 "-" + VETTING // go into Vetting mode. (show draft, etc) 109 }; 110 main(String[] args)111 public static void main(String[] args) { 112 LDMLComparator comparator = new LDMLComparator(); 113 comparator.processArgs(args); 114 } 115 getDefaultCollation()116 static Collator getDefaultCollation() { 117 // if (DEFAULT_COLLATION != null) return DEFAULT_COLLATION; 118 RuleBasedCollator temp = (RuleBasedCollator) Collator.getInstance(ULocale.ENGLISH); 119 temp.setStrength(Collator.IDENTICAL); 120 temp.setNumericCollation(true); 121 // DEFAULT_COLLATION = temp; 122 return temp; 123 } 124 125 Hashtable<String, String> optionTable = new Hashtable<>(); 126 private String destFolder = "."; 127 private String localeStr; 128 private Calendar cal = Calendar.getInstance(); 129 private Hashtable<String, String> colorHash = new Hashtable<>(); 130 private String goldFileName; 131 private String goldKey; 132 private int serialNumber = 0; 133 private Map<String, Object> compareMap = new TreeMap<>(getDefaultCollation()); 134 private Hashtable<String, String> doesNotExist = new Hashtable<>(); 135 private Hashtable<String, String> requested = new Hashtable<>(); 136 private Hashtable<String, String> deprecatedLanguageCodes = new Hashtable<>(); 137 private Hashtable<String, String> deprecatedCountryCodes = new Hashtable<>(); 138 private Set<String> vettingSet = new TreeSet<>(); 139 private String encoding = "UTF-8"; // default encoding 140 141 // PN added 142 private Vector<String> m_PlatformVect = new Vector<>(); // holds names of platforms 143 private Vector<String> m_PlatformFolderVect = new Vector<>(); // holds names of folders containing locale data 144 // for each platform 145 private int m_iOptions; 146 private Map<String, AccumulatedResults> m_AccumulatedResultsMap = new TreeMap<>(); 147 private int m_iTotalConflictingElements = 0; 148 private int m_iTotalNonConflictingElements = 0; 149 private Map<String, SummaryData> m_LocaleSummaryDataMap = new TreeMap<>(); // key = localename, 150 // data = summary info 151 private boolean m_Vetting = false; 152 153 private int m_totalCount = 0; 154 private int m_diffcount = 0; 155 private String m_Messages = ""; 156 157 private class CompareElement { 158 String node; 159 String index; 160 String parentNode; 161 Hashtable<String, String> platformData = new Hashtable<>(); 162 String referenceUrl; 163 } 164 165 // PN added 166 // used for bulk comparisons 167 // holds the locales where the element identified by node,index and parentNode conflict 168 // for at least 2 of the platforms tested 169 // holds the locales where the element identified by node,index and parentNode don't 170 // for at all the platforms tested 171 private class AccumulatedResults { 172 String node; 173 String index; 174 String parentNode; 175 Vector<String> localeVectDiff = new Vector<>(); // holds locales where a conflict in data was found 176 Vector<String> localeVectSame = new Vector<>(); // holds locales where a no conflict in data was found 177 } 178 179 private class SummaryData { 180 String m_szPlatforms; 181 int m_iNumConflictingElements; 182 } 183 LDMLComparator()184 LDMLComparator() { 185 // initialize the color hash 186 colorHash.put(COMMON, "#AD989D"); 187 colorHash.put(ICU, "#CCFF00"); 188 colorHash.put(IBM_TOR, "#FF7777"); 189 colorHash.put(WINDOWS, "#98FB98"); 190 colorHash.put(SUNJDK, "#FF6633"); 191 colorHash.put(IBMJDK, "#CCFFFF"); 192 colorHash.put(HPUX, "#FFE4B5"); 193 colorHash.put(APPLE, "#FFBBBB"); 194 colorHash.put(SOLARIS, "#CC9966"); 195 colorHash.put(OPEN_OFFICE, "#FFFF33"); 196 colorHash.put(AIX, "#EB97FE"); 197 colorHash.put(LINUX, "#1191F1"); 198 // TODO - use deprecatedMap instead. 199 // deprecatedLanguageCodes.put("sh", "what ever the new one is"); 200 deprecatedLanguageCodes.put("iw", "he"); 201 deprecatedLanguageCodes.put("in", "id"); 202 deprecatedLanguageCodes.put("ji", "yi"); 203 deprecatedLanguageCodes.put("jw", "jv"); // this does not even exist, JDK thinks jw is javanese!! 204 205 // country codes 206 deprecatedCountryCodes.put("TP", "TL"); 207 deprecatedCountryCodes.put("ZR", "CD"); 208 } 209 processArgs(String[] args)210 private void processArgs(String[] args) { 211 m_iOptions = identifyOptions(args); 212 if ((args.length < 2) || ((m_iOptions & OPT_UNKNOWN) != 0)) { 213 printUsage(); 214 return; 215 } 216 boolean warning[] = new boolean[1]; 217 warning[0] = false; 218 Enumeration<String> en = optionTable.keys(); 219 220 try { 221 // check for bulk operation 222 if ((m_iOptions & OPT_BULK) != 0) { 223 doBulkComparison(); 224 } else { 225 localeStr = goldFileName.substring(goldFileName.lastIndexOf(File.separatorChar) + 1, 226 goldFileName.lastIndexOf('.')); 227 228 String fileName = destFolder + File.separator + localeStr + ".html"; 229 m_totalCount = 0; 230 m_diffcount = 0; 231 if ((m_iOptions & OPT_VETTING) != 0) { 232 m_Vetting = true; 233 addVettable(goldFileName, goldKey); 234 } else { 235 addToCompareMap(goldFileName, goldKey); 236 } 237 for (; en.hasMoreElements();) { 238 String key = en.nextElement(); 239 String compFile = optionTable.get(key); 240 if ((m_iOptions & OPT_VETTING) != 0) { 241 addVettable(goldFileName, goldKey); 242 } else { 243 addToCompareMap(compFile, key); 244 } 245 } 246 if ((m_totalCount == 0) && m_Vetting) { // only optional for vetting. 247 // System.out.println("INFO: no file created (nothing to write..) " + fileName); 248 } else { 249 OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(fileName), encoding); 250 System.out.println("INFO: Writing: " + fileName + "\t(" + m_totalCount + " items)"); 251 PrintWriter writer = new PrintWriter(os); 252 printHTML(writer, localeStr); 253 { 254 ULocale ourLocale = new ULocale(localeStr); 255 String idxFileName = destFolder + File.separator + ourLocale.getDisplayLanguage() + "_" 256 + ourLocale.getDisplayCountry() + "_" + localeStr + ".idx"; 257 OutputStreamWriter is = new OutputStreamWriter(new FileOutputStream(idxFileName), "utf-8"); 258 PrintWriter indexwriter = new PrintWriter(is); 259 indexwriter.println("<tr>"); 260 indexwriter.println(" <td>" + 261 localeStr + 262 "</td>"); 263 indexwriter.println(" <td><a href=\"" + localeStr + ".html" + "\">" + 264 ourLocale.getDisplayName() + "</a></td>"); 265 indexwriter.println(" <td>" + m_totalCount + "</td>"); 266 if (!m_Vetting) { 267 indexwriter.println(" <td>" + m_diffcount + "</td>"); 268 } 269 indexwriter.println("<td></td>"); // TODO: need to calculate full path (i.e. seed/main/ssy.xml) and append to CLDRURLS.something 270 indexwriter.println("</tr>"); 271 is.close(); 272 } 273 // TODO: handle vettingSet; 274 } 275 } 276 } catch (Exception e) { 277 e.printStackTrace(); 278 } 279 280 } 281 printUsage()282 private void printUsage() { 283 System.err.println("Usage: LDMLComparator [<option>:<gold>] filename1 [option] filename2 ... \n" + 284 " LDMLComparator [-common:<gold>] filename [-icu] filename" + 285 " [-ibmjdk] filename [-windows] filename" + 286 " [-hpux] filename [-solaris] filename" + 287 " [-ibmtor] filename [-apple] filename" + 288 " [-sunjdk] filename [-open_office] filename" + 289 " [-aix] filename [-linux] filename" + 290 " [-diff / -diff_ref_common] [-bulk]" + 291 " [-case_sensitive (only active if -diff of -diff-ref-common option selected)]"); 292 System.err.println("\nExample 1: \n " + 293 "LDMLComparator -solaris:gold foldername1 -sunjdk foldername2 -common foldername3 -diff-ref-common -bulk\n" 294 + 295 "\t\t will do a bulk comparison of the locales in folder1 and folder2 \n " + 296 "\t\t and print the values of any differing elements plus the \n" + 297 "\t\t corresponding element's value in folder3 to bulk.html \n" + 298 "\t\t as well as a summary to bulk_summary.html \n"); 299 System.err.println("Example 2: \n" + 300 "LDMLComparator -common:gold filename1 -sunjdk filename2 -diff \n" + 301 "\t\t will do a comparison of the locales specified by filename1 and \n" + 302 "\t\t filename2 and print the values of any differing elements \n" + 303 "\t\t to a file called filename1.html in the current directory \n"); 304 } 305 identifyOptions(String[] options)306 private int identifyOptions(String[] options) { 307 int result = 0; 308 for (int j = 0; j < options.length; j++) { 309 String option = options[j]; 310 boolean isGold = false; 311 if (option.startsWith("-")) { 312 if (option.indexOf(":gold") > 0) { 313 option = option.substring(0, option.indexOf(":")); 314 isGold = true; 315 } 316 boolean optionRecognized = false; 317 for (int i = 0; i < USER_OPTIONS.length; i++) { 318 319 if (USER_OPTIONS[i].equals(option)) { 320 result |= 1 << i; // calculate option bit value 321 optionRecognized = true; 322 if (USER_OPTIONS[i].equals("-s")) { 323 } else if (USER_OPTIONS[i].equals("-d")) { 324 destFolder = options[++j]; 325 } else if (USER_OPTIONS[i].equals("-" + DIFF)) { 326 327 } else if (USER_OPTIONS[i].equals("-" + DIFF_REF_COMMON)) { 328 329 } else if (USER_OPTIONS[i].equals("-" + BULK)) { 330 331 } else if (USER_OPTIONS[i].equals("-" + VETTING)) { 332 m_Vetting = true; 333 } else if (USER_OPTIONS[i].equals("-" + CASE_SENSITIVE)) { 334 } else { 335 if (!isGold) { 336 optionTable.put(option.substring(1, option.length()), options[++j]); 337 338 } else { 339 goldFileName = options[++j]; 340 goldKey = option.substring(1, option.length()); 341 } 342 // PN added 343 m_PlatformVect.add(option.substring(1, option.length())); 344 m_PlatformFolderVect.add(options[j]); 345 } 346 break; 347 } 348 } 349 if (!optionRecognized) { 350 result |= OPT_UNKNOWN; 351 } 352 } else { 353 if (m_Vetting == true) { 354 vettingSet.add(option); 355 } 356 } 357 } 358 359 return result; 360 } 361 printTableHeader(PrintWriter writer)362 private void printTableHeader(PrintWriter writer) { 363 364 writer.print(" <tr>\n" + 365 " <th>N.</th>\n" + 366 " <th>ParentNode</th>\n" + 367 " <th>Name</th>\n" + 368 " <th>ID</th>\n"); 369 370 for (int i = 0; i < PLATFORM_PRINT_ORDER.length && PLATFORM_PRINT_ORDER[i] != null; i++) { 371 String name = PLATFORM_PRINT_ORDER[i]; 372 String folder; 373 374 Object obj = requested.get(name); 375 if (obj != null && doesNotExist.get(name) == null) { 376 folder = name + "/main/"; 377 if (name.equals("icu") || name.equals("common") || name.indexOf("jdk") >= 0) { 378 int index = localeStr.indexOf("_"); 379 String parent = ""; 380 if (index > -1) { 381 parent = localeStr.substring(0, index); 382 } 383 writer.print(" <th bgcolor=\"" + 384 colorHash.get(name) + "\">" + 385 name.toUpperCase() + 386 " (<a href=\"../../" + folder + localeStr + ".xml\">" + localeStr + "</a>," + 387 " <a href=\"../../" + folder + parent + ".xml\">" + parent + "</a>," + 388 " <a href=\"../../" + folder + "root.xml\">root</a>)" + 389 "</th>\n"); 390 } else { 391 writer.print(" <th bgcolor=\"" + 392 colorHash.get(name) + "\">" + 393 name.toUpperCase() + 394 " (<a href=\"../../" + folder + localeStr + ".xml\">" + localeStr + "</a>)" + 395 "</th>\n"); 396 } 397 } 398 } 399 if (m_Vetting) { 400 writer.print("<th bgcolor=\"" + ALT_COLOR + "\">" + ALTERNATE_TITLE + "</th>"); 401 } 402 writer.print(" </tr>\n"); 403 } 404 405 // PN added printTableHeaderForDifferences(PrintWriter writer)406 private void printTableHeaderForDifferences(PrintWriter writer) { 407 408 writer.print(" <tr>\n" + 409 " <th width=10%>N.</th>\n" + 410 " <th width=10%>ParentNode</th>\n" + 411 " <th width=10%>Name</th>\n" + 412 " <th width=10%>ID</th>\n"); 413 414 for (int i = 0; i < m_PlatformVect.size(); i++) { 415 String name = m_PlatformVect.elementAt(i); 416 String folder; 417 418 // Object obj = requested.get(name); 419 // if(obj!=null && doesNotExist.get(name)==null ) 420 // { 421 folder = name + "/xml/"; 422 writer.print(" <th bgcolor=\"" + 423 colorHash.get(name) + "\">" + 424 name.toUpperCase() + 425 " (<a href=\"../" + folder + localeStr + ".xml\">xml</a>)" + 426 "</th>\n"); 427 // not used numPlatforms++; 428 429 // } 430 } 431 if (m_Vetting) { 432 writer.print("<th>" + ALTERNATE_TITLE + "</th>"); 433 } 434 writer.print(" </tr>\n"); 435 } 436 437 // PN added 438 // method to print differing elements/attributes only to HTML 439 // returns false if a difference found otherwise true printDifferentValues(CompareElement element, PrintWriter writer)440 private boolean printDifferentValues(CompareElement element, PrintWriter writer) { 441 boolean isEqual = true; 442 // following don't count 443 if ((element.node.compareTo("generation") == 0) 444 || (element.node.compareTo("version") == 0)) { 445 return isEqual; 446 } 447 448 String compareTo = null; 449 boolean bFoundFirst = false; 450 for (int i = 0; i < m_PlatformVect.size(); i++) { 451 String value = element.platformData.get(m_PlatformVect.elementAt(i)); 452 if (value == null) 453 continue; 454 // loop until non null value is found, this is the reference for comparison 455 if (bFoundFirst == false) { 456 compareTo = value; 457 bFoundFirst = true; 458 } else { // we have something to compare this element to 459 if (Normalizer.compare(compareTo, value, 0) == 0) { 460 isEqual = true; 461 } else if (Normalizer.compare(compareTo, value, Normalizer.COMPARE_IGNORE_CASE) == 0) { 462 if ((m_iOptions & OPT_CASE_SENSITIVE) == 0) { // it's not a case sensitive search so this is a match 463 isEqual = true; 464 } else { 465 isEqual = false; 466 break; // we have found a difference therefore break out of loop , we will print full row 467 } 468 } else { 469 isEqual = false; 470 break; // we have found a difference therefore break out of loop , we will print full row 471 } 472 } // end if 473 } // end while 474 475 // if any differences found then print all non null values 476 if (isEqual == false) { 477 writer.print(" <tr>\n"); 478 writer.print(" <td><a NAME=\"" + serialNumber + "\" href=\"#" + serialNumber + "\">" 479 + serialNumber + "</a></td>\n"); 480 writer.print(" <td>" + mapToAbbr(element.parentNode) + "</td>\n"); 481 writer.print(" <td>" + mapToAbbr(element.node) + "</td>\n"); 482 writer.print(" <td>" + element.index + "</td>\n"); 483 484 for (int i = 0; i < m_PlatformVect.size(); i++) { 485 String val = element.platformData.get(m_PlatformVect.elementAt(i)); 486 if (val != null) { 487 writer.print(" <td>" + val + "</td>\n"); 488 } else { 489 writer.print(" <td> </td>\n"); 490 } 491 } // end while 492 493 writer.print(" </tr>\n"); 494 serialNumber++; 495 } // endif 496 return isEqual; 497 } 498 499 // PN added 500 // method to print differing elements/attributes only to HTML excluding Common from diff 501 // only if the other platfroms differ amongst themselves will the Common data be printed 502 // returns false if a difference found otherwise true printDifferentValuesWithRef(CompareElement element, PrintWriter writer)503 private boolean printDifferentValuesWithRef(CompareElement element, PrintWriter writer) { 504 boolean isEqual = true; 505 // following don't count 506 if ((element.node.compareTo("generation") == 0) 507 || (element.node.compareTo("version") == 0)) { 508 return isEqual; 509 } 510 511 String compareTo = null; 512 boolean bFoundFirst = false; 513 for (int i = 0; i < m_PlatformVect.size(); i++) { 514 // excluding Common from diff 515 String platform = m_PlatformVect.elementAt(i); 516 if (platform.compareTo(COMMON) == 0) 517 continue; 518 519 String value = element.platformData.get(platform); 520 if (value == null) 521 continue; 522 523 // loop until non null value is found, this is the reference for comparison 524 if (bFoundFirst == false) { 525 compareTo = value; 526 bFoundFirst = true; 527 } else { // we have something to compare this element to 528 if (Normalizer.compare(compareTo, value, 0) == 0) { 529 isEqual = true; 530 } else if (Normalizer.compare(compareTo, value, Normalizer.COMPARE_IGNORE_CASE) == 0) { 531 // case difference on date and time format doesn't matter 532 if ((element.parentNode.compareTo("timeFormat") == 0) 533 || (element.parentNode.compareTo("dateFormat") == 0)) { 534 isEqual = true; 535 } else { 536 if ((m_iOptions & OPT_CASE_SENSITIVE) == 0) { // it's not a case sensitive search so this is a match 537 isEqual = true; 538 } else { 539 isEqual = false; 540 break; // we have found a difference therefore break out of loop , we will print full row 541 } 542 } 543 } else { 544 isEqual = false; 545 break; // we have found a difference therefore break out of loop , we will print full row 546 } 547 } // end if 548 } // end while 549 550 // if any differences found then print all non null values 551 if (isEqual == false) { 552 writer.print(" <tr>\n"); 553 writer.print(" <td><a NAME=\"" + serialNumber + "\" href=\"#" + serialNumber + "\">" 554 + serialNumber + "</a></td>\n"); 555 writer.print(" <td>" + mapToAbbr(element.parentNode) + "</td>\n"); 556 writer.print(" <td>" + mapToAbbr(element.node) + "</td>\n"); 557 writer.print(" <td>" + element.index + "</td>\n"); 558 559 for (int i = 0; i < m_PlatformVect.size(); i++) { 560 String val = element.platformData.get(m_PlatformVect.elementAt(i)); 561 if (val != null) { 562 writer.print(" <td>" + val + "</td>\n"); 563 } else { 564 writer.print(" <td> </td>\n"); 565 } 566 } // end while 567 568 writer.print(" </tr>\n"); 569 serialNumber++; 570 } // endif 571 572 return isEqual; 573 } 574 printValue(CompareElement element, PrintWriter writer)575 private void printValue(CompareElement element, PrintWriter writer) { 576 577 writer.print(" <tr>\n"); 578 writer.print(" <td><a NAME=\"" + serialNumber + "\" href=\"#" + serialNumber + "\">" 579 + serialNumber + "</a></td>\n"); 580 writer.print(" <td>" + mapToAbbr(element.parentNode) + "</td>\n"); 581 writer.print(" <td>" + mapToAbbr(element.node) + "</td>\n"); 582 writer.print(" <td>" + element.index + "</td>\n"); 583 serialNumber++; 584 585 for (int i = 0; i < PLATFORM_PRINT_ORDER.length; i++) { 586 String value = element.platformData.get(PLATFORM_PRINT_ORDER[i]); 587 String color = colorHash.get(PLATFORM_PRINT_ORDER[i]); 588 boolean caseDiff = false; 589 boolean isEqual = false; 590 // the locale exists for the given platform but there is no data 591 // so just write non breaking space and continue 592 // else the object contains value to be written .. so write it 593 if (value == null) { 594 if (requested.get(PLATFORM_PRINT_ORDER[i]) != null && doesNotExist.get(PLATFORM_PRINT_ORDER[i]) == null) { 595 writer.print(" <td> </td>\n"); 596 } 597 } else { 598 // pick the correct color 599 for (int j = 0; j < i; j++) { 600 String compareTo = element.platformData.get(PLATFORM_PRINT_ORDER[j]); 601 if (compareTo == null) { 602 continue; 603 } else if (value.equals("")) { 604 color = "#FFFFFF"; 605 break; 606 } else if (element.parentNode.indexOf("decimalFormat") > -1 607 || element.parentNode.indexOf("currencyFormat") > -1) { 608 if (comparePatterns(compareTo, value)) { 609 color = colorHash.get(PLATFORM_PRINT_ORDER[j]); 610 isEqual = true; 611 break; 612 } 613 } else if (Normalizer.compare(compareTo, value, 0) == 0) { 614 color = colorHash.get(PLATFORM_PRINT_ORDER[j]); 615 isEqual = true; 616 break; 617 } else if (Normalizer.compare(compareTo, value, Normalizer.COMPARE_IGNORE_CASE) == 0) { 618 caseDiff = true; 619 color = colorHash.get(PLATFORM_PRINT_ORDER[j]); 620 break; 621 } 622 } 623 if (isEqual) { 624 value = "="; 625 } else { 626 if (i > 0) { // not the first platform 627 if ((element.node.compareTo("generation") == 0) 628 || (element.node.compareTo("version") == 0)) { 629 // ignored 630 } else { 631 m_diffcount++; 632 } 633 } 634 } 635 if (m_Vetting) { 636 String altText = element.platformData.get("ALT"); 637 writer.print("<td>" + value); 638 String parName = mapToAbbr(element.parentNode); 639 if ((parName.indexOf("_dateFormat") != -1) 640 || (parName.indexOf("_timeFormat") != -1)) { 641 writer.print("<form method=\"POST\" action=\"http://oss.software.ibm.com/cgi-bin/icu/lx/\">" + 642 "<input type=hidden name=\"_\" value=\"" + localeStr + "\"/>" + 643 "<input type=hidden name=\"x\" value=\"" + "dat" + "\"/>" + 644 "<input type=hidden name=\"str\" value=\"" + value + "\"/>" + 645 "<input type=submit value=\"" + "Test" + "\"/>" + 646 "</form>"); 647 } 648 if (/* m_Vetting && */element.referenceUrl != null) { 649 writer.print("<br><div align='right'><a href=\"" + element.referenceUrl 650 + "\"><i>(Ref)</i></a></div>"); 651 } 652 writer.print("</td>"); 653 if (altText != null) { 654 writer.print(" <td bgcolor=" + ALT_COLOR + ">" + altText); 655 writer.print("</td>\n"); 656 } 657 } else { 658 if (caseDiff == true) { 659 writer.print(" <td bgcolor=" + color + ">" + value + "†"); 660 } else { 661 writer.print(" <td bgcolor=" + color + ">" + value); 662 } 663 writer.print("</td>\n"); 664 } 665 } 666 } 667 writer.print(" </tr>\n"); 668 } 669 mapToAbbr(String source)670 private String mapToAbbr(String source) { 671 if (source.equals("icu:ruleBasedNumberFormat")) { 672 return "icu:rbnf"; 673 } 674 if (source.equals("icu:ruleBasedNumberFormats")) { 675 return "icu:rbnfs"; 676 } 677 if (source.equals("exemplarCharacters")) { 678 return "exemplarC"; 679 } 680 if (source.equals("localizedPatternChars")) { 681 return "lpc"; 682 } 683 return source; 684 } 685 printHTML(PrintWriter writer, String localeStr)686 private void printHTML(PrintWriter writer, String localeStr) { 687 // System.out.println("INFO: Creating the comparison chart "); 688 ULocale locale = new ULocale(localeStr); 689 String displayName = localeStr + " (" + locale.getDisplayName() + ") "; 690 if ((m_iOptions & OPT_DIFF_REF_COMMON) != 0) 691 writer.print("<p> Common data shown for reference purposes only</p>\n"); 692 693 if (!m_Vetting) { 694 writer.print("<html>\n" + 695 " <head>\n" + 696 " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n" + 697 " <title>" + localeStr + "</title>\n" + 698 " </head>\n" + 699 " <style>\n" + 700 " <!--\n" + 701 " table { border-spacing: 0; border-collapse: collapse; width: 100%; \n" + 702 " border: 1px solid black }\n" + 703 " td, th { width: 10%; border-spacing: 0; border-collapse: collapse; color: black; \n" + 704 " vertical-align: top; border: 1px solid black }\n" + 705 " -->\n" + 706 " </style>" + 707 " <body bgcolor=\"#FFFFFF\">\n" + 708 " <p><b>" + displayName + 709 "<a href=\"http://oss.software.ibm.com/cgi-bin/icu/lx/en/?_=" + localeStr + "\">Demo</a>, " + 710 "<a href=\"../../comparison_charts.html\">Cover Page</a>, " + 711 "<a href=\"./index.html\">Index</a>, " + 712 "<a href=\"../collation/" + localeStr + ".html\">Collation</a> " + 713 "</b></p>\n" + 714 " <table>\n"); 715 } else { 716 writer.print("<html>\n" + 717 " <head>\n" + 718 " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n" + 719 " <title>Draft/Alt: " + localeStr + "</title>\n" + 720 " </head>\n" + 721 " <style>\n" + 722 " <!--\n" + 723 " table { border-spacing: 0; border-collapse: collapse; \n" + 724 " border: 1px solid black }\n" + 725 " td, th { border-spacing: 0; border-collapse: collapse; color: black; \n" + 726 " vertical-align: top; border: 1px solid black }\n" + 727 " -->\n" + 728 " </style>" + 729 " <body bgcolor=\"#FFFFFF\">\n" + 730 " <p><b>" + displayName + 731 "<a href=\"http://oss.software.ibm.com/cgi-bin/icu/lx/en/?_=" + localeStr + "\">Demo</a>, " + 732 "<a href=\"./index.html\">Main and About</a>, " + 733 "</b></p>\n"); 734 writer.print(" <table>\n"); 735 } 736 737 // PN added 738 if (((m_iOptions & OPT_DIFF) != 0) 739 || ((m_iOptions & OPT_DIFF_REF_COMMON) != 0)) { 740 printTableHeaderForDifferences(writer); 741 } else { 742 printTableHeader(writer); 743 } 744 745 // walk down the compare map and print the data 746 for (Object obj : compareMap.keySet()) { 747 CompareElement element; 748 if (obj != null) { 749 Object value = compareMap.get(obj); 750 if (value instanceof CompareElement) { 751 element = (CompareElement) value; 752 } else { 753 throw new RuntimeException( 754 "The object stored in the compare map is not an instance of CompareElement"); 755 } 756 // PN added 757 if ((m_iOptions & OPT_DIFF) != 0) { 758 printDifferentValues(element, writer); // only print differences 759 } else if ((m_iOptions & OPT_DIFF_REF_COMMON) != 0) { 760 printDifferentValuesWithRef(element, writer); 761 } else { 762 printValue(element, writer); 763 } 764 } else { 765 throw new RuntimeException("No objects stored in the compare map!"); 766 } 767 768 } 769 writer.print(" </table>\n"); 770 771 if (m_Vetting) { 772 if (m_Messages.length() > 0) { 773 writer.print("<table bgcolor=\"#FFBBBB\" border=3><tr><th>Warnings (please see source LDML)</th></tr>" + 774 "<tr><td>" + m_Messages + "</td></tr></table><p/><p/>\n"); 775 } 776 writer.print("<i>Interim page - subject to change</i> (<a href=\"./index.html\">Help</a>)<br/>"); 777 } 778 779 writer.print(" <p>Created on: " + cal.getTime() + "</p>\n" + 780 " </body>\n" + 781 "</html>\n"); 782 writer.flush(); 783 784 writer.flush(); 785 } 786 getFullyResolvedLocale(String localeName, String fileName)787 private Document getFullyResolvedLocale(String localeName, String fileName) { 788 // here we assume that "_" is the delimiter 789 int index = fileName.lastIndexOf(File.separatorChar); 790 String sourceDir = fileName.substring(0, index + 1); 791 String locale = fileName.substring(index + 1, fileName.lastIndexOf(".")); 792 System.out.println("INFO: Creating fully resolved tree for : " + fileName); 793 794 Document doc = LDMLUtilities.getFullyResolvedLDML(sourceDir, locale, true, true, true, true); 795 /* 796 * debugging code 797 * 798 * try{ 799 * OutputStreamWriter writer = new OutputStreamWriter(new 800 * FileOutputStream(destFolder+File.separator+localeName+"_debug.xml"),encoding); 801 * LDMLUtilities.printDOMTree(doc,new PrintWriter(writer)); 802 * writer.flush(); 803 * }catch( Exception e){ 804 * //throw the exception away .. this is for debugging 805 * } 806 */ 807 return doc; 808 } 809 addToCompareMap(String fileName, String key)810 private boolean addToCompareMap(String fileName, String key) { 811 // parse the test doc only if gold doc was parsed OK 812 Document testDoc = getFullyResolvedLocale(key, fileName); 813 requested.put(key, ""); 814 if (null == testDoc) { 815 doesNotExist.put(key, ""); 816 return false; 817 } 818 return extractMergeData(testDoc, key, false); 819 820 } 821 getParsedLocale(String localeName, String fileName)822 private Document getParsedLocale(String localeName, String fileName) { 823 // here we assume that "_" is the delimiter 824 System.out.println("INFO: Parsing " + fileName); 825 Document doc = LDMLUtilities.parse(fileName, true); // ? 826 827 return doc; 828 } 829 addVettable(String fileName, String key)830 private boolean addVettable(String fileName, String key) { 831 // parse the test doc only if gold doc was parsed OK 832 Document testDoc = getParsedLocale(key, fileName); 833 requested.put(key, ""); 834 if (null == testDoc) { 835 doesNotExist.put(key, ""); 836 return false; 837 } 838 return extractMergeData(testDoc, key, false); 839 840 } 841 comparePatterns(String pat1, String pat2)842 private boolean comparePatterns(String pat1, String pat2) { 843 // TODO: just return for now .. this is useful only 844 // when comparing data from toronto 845 try { 846 double args1 = 10000000000.00; 847 double args2 = -10000000000.00; 848 849 DecimalFormat fmt = new DecimalFormat(); 850 851 fmt.applyPattern(pat1); 852 String s1 = fmt.format(args1); 853 String s3 = fmt.format(args2); 854 fmt.applyPattern(pat2); 855 String s2 = fmt.format(args1); 856 String s4 = fmt.format(args2); 857 if (s1.equals(s2) && s3.equals(s4)) { 858 return true; 859 } 860 } catch (Exception e) { 861 // throw away the exception 862 } 863 return false; 864 865 // return true; 866 } 867 trim(String source)868 private String trim(String source) { 869 char[] src = source.toCharArray(); 870 char[] dest = new char[src.length]; 871 872 int start = 0; 873 while (start < (src.length) && (UCharacter.isWhitespace(src[start]))) { 874 start++; 875 } 876 int stop = src.length - 1; 877 while (stop > 0 && (UCharacter.isWhitespace(src[stop]) || (src[stop] == 0xA0))) { 878 stop--; 879 } 880 if (stop != -1 && start != src.length) { 881 System.arraycopy(src, start, dest, 0, (stop - start) + 1); 882 return new String(dest, 0, (stop - start) + 1); 883 } else { 884 return new String(); 885 } 886 887 } 888 addElement(String childNode, String parentNode, String id, String index, String platformValue, String platformName)889 private final void addElement(String childNode, String parentNode, String id, String index, 890 String platformValue, String platformName) { 891 addElement(childNode, parentNode, id, index, platformValue, platformName, null); 892 } 893 addElement(String childNode, String parentNode, String id, String index, String platformValue, String platformName, String referenceUrl)894 private void addElement(String childNode, String parentNode, String id, String index, 895 String platformValue, String platformName, String referenceUrl) { 896 m_totalCount++; 897 Object obj = compareMap.get(id); 898 CompareElement element; 899 if (obj == null) { 900 element = new CompareElement(); 901 // initialize the values 902 element.index = index; 903 element.parentNode = parentNode; 904 element.node = childNode; 905 element.referenceUrl = referenceUrl; 906 // add the element to the compare map 907 compareMap.put(id, element); 908 } else { 909 if (obj instanceof CompareElement) { 910 element = (CompareElement) obj; 911 } else { 912 throw new RuntimeException("The object stored in the compareMap is not a CompareElement object!"); 913 } 914 } 915 916 if ((!element.index.equals(index)) || 917 (!element.node.equals(childNode)) || 918 (!element.parentNode.equals(parentNode))) { 919 throw new RuntimeException("The retrieved object is not the same as the one trying to be saved, id is " 920 + id); 921 } 922 923 element.platformData.put(platformName, platformValue); 924 } 925 childrenAreElements(Node node)926 private boolean childrenAreElements(Node node) { 927 NodeList list = node.getChildNodes(); 928 for (int i = 0; i < list.getLength(); i++) { 929 if (list.item(i).getNodeType() == Node.ELEMENT_NODE) { 930 return true; 931 } 932 } 933 return false; 934 } 935 getTag(String childNodeName, String index)936 private String getTag(String childNodeName, String index) { 937 938 // for months make index a,b,c,d etc 939 if (childNodeName.indexOf("month") > -1) { 940 int i = Integer.parseInt(index); 941 StringBuffer temp = new StringBuffer(); 942 temp.append((char) ('a' + i)); 943 return temp.toString(); 944 } else if (childNodeName.indexOf("day") > -1) { 945 if (index.equals("sun")) { 946 return "a"; 947 } else if (index.equals("mon")) { 948 return "b"; 949 } else if (index.equals("tue")) { 950 return "c"; 951 } else if (index.equals("wed")) { 952 return "d"; 953 } else if (index.equals("thu")) { 954 return "e"; 955 } else if (index.equals("fri")) { 956 return "f"; 957 } else if (index.equals("sat")) { 958 return "g"; 959 } 960 } else { 961 return index; 962 } 963 return ""; 964 } 965 extractMergeData(Node node, String key, boolean parentDraft)966 private boolean extractMergeData(Node node, String key, boolean parentDraft) { 967 Node childOfSource; 968 for (childOfSource = node.getFirstChild(); childOfSource != null; childOfSource = childOfSource 969 .getNextSibling()) { 970 if (childOfSource.getNodeType() != Node.ELEMENT_NODE) { 971 continue; 972 } 973 String altText = null; 974 // String altReferenceUrl = null; 975 Node altForChild = null; 976 boolean subDraft = parentDraft; 977 String childOfSourceName = childOfSource.getNodeName(); 978 // Ignore collation and special tags 979 if (childOfSourceName.equals("collations") || childOfSource.equals("special") 980 || childOfSourceName.indexOf(":") > -1) { 981 continue; 982 } 983 984 if (m_Vetting && LDMLUtilities.isNodeDraft(childOfSource)) { 985 if (!subDraft) { 986 subDraft = true; 987 } 988 } 989 String referenceUrl = null; 990 if (m_Vetting) { 991 referenceUrl = LDMLUtilities.getAttributeValue(childOfSource, LDMLConstants.REFERENCES); 992 if ((referenceUrl != null) && (referenceUrl.length() == 0)) { 993 referenceUrl = null; 994 } 995 } 996 997 if (m_Vetting) { /* Should this be always checked? */ 998 String alt = LDMLUtilities.getAttributeValue(childOfSource, LDMLConstants.ALT); 999 if (alt != null) { 1000 if (alt.equals(LDMLConstants.PROPOSED)) { 1001 if (subDraft == false) { 1002 throw new IllegalArgumentException("***** ERROR Proposed but not draft? " 1003 + childOfSource.toString()); 1004 // NOTREACHED 1005 } 1006 altForChild = LDMLUtilities.getNonAltNodeLike(node, childOfSource); 1007 if (altForChild == null) { 1008 System.out.println("WARNING: can't find a node like this one: " + childOfSource.toString() 1009 + " - consider removing the alt=\"proposed\" attribute."); 1010 alt = null; 1011 } 1012 // altReferenceUrl = LDMLUtilities.getAttributeValue(altForChild, LDMLConstants.REFERENCES); 1013 // if((altReferenceUrl!=null)&&(altReferenceUrl.length()==0)) { 1014 // altReferenceUrl = null; 1015 // } 1016 } else if (subDraft) { /* don't care about nondraft */ 1017 String type = LDMLUtilities.getAttributeValue(childOfSource, LDMLConstants.TYPE); 1018 if (type == null) { 1019 type = ""; 1020 } 1021 m_Messages = m_Messages + " <br> UNKNOWN alt type '" + alt + "' for " + 1022 node.getNodeName() + "/" + childOfSourceName + "/" + type; 1023 System.err.println("Warning: unknown alt type '" + alt + "' - *IGNORING*. " 1024 + childOfSource.toString()); 1025 continue; 1026 } 1027 } 1028 } 1029 1030 if (childrenAreElements(childOfSource) == false) { 1031 NamedNodeMap attr = childOfSource.getAttributes(); 1032 Node typeNode = attr.getNamedItem("type"); 1033 Node altNode = attr.getNamedItem("alt"); 1034 String index = ""; 1035 if (typeNode != null) { 1036 /* 1037 * if(childOfSource.getNodeName().equals("era")&&!key.equals("common")){ 1038 * //remap type for comparison purpose 1039 * // TODO remove this hack 1040 * int j = Integer.parseInt(typeNode.getNodeValue()); 1041 * if(j>0){ 1042 * j--; 1043 * } 1044 * typeNode.setNodeValue(Integer.toString(j)); 1045 * } 1046 */ 1047 String temp = typeNode.getNodeValue(); 1048 1049 if (!temp.equals("standard")) { 1050 index = temp; 1051 } 1052 1053 } 1054 String alt = null; 1055 if (altNode != null) { 1056 alt = altNode.getNodeValue(); 1057 } 1058 if (m_Vetting) { // TODO: all? 1059 Node keyNode = attr.getNamedItem("key"); 1060 if (keyNode != null) { 1061 String temp = keyNode.getNodeValue(); 1062 index = index + " (" + temp + ")"; 1063 } 1064 } 1065 String nodeValue = ""; 1066 Node valueNode = childOfSource.getFirstChild(); 1067 if (valueNode != null) { 1068 String temp = trim(valueNode.getNodeValue()); 1069 if (!temp.equals("standard")) { 1070 nodeValue = temp; 1071 } 1072 } 1073 if (altForChild != null) { 1074 Node valueNode2 = altForChild.getFirstChild(); 1075 if (valueNode2 != null) { 1076 String temp = trim(valueNode2.getNodeValue()); 1077 if (!temp.equals("standard")) { 1078 altText = temp; 1079 } else { 1080 altText = "??? alt=standard"; 1081 } 1082 } else { 1083 altText = "??? alt has no value"; 1084 } 1085 } 1086 Node parentNode = childOfSource.getParentNode(); 1087 String parentNodeName = trim(parentNode.getNodeName()); 1088 String childNodeName = trim(childOfSource.getNodeName()); 1089 Node grandParentNode = childOfSource.getParentNode().getParentNode(); 1090 String grandParentNodeName = grandParentNode.getNodeName(); 1091 NamedNodeMap parentAttrib = parentNode.getAttributes(); 1092 String type = ""; 1093 if (parentAttrib != null) { 1094 Node mytypeNode = parentAttrib.getNamedItem("type"); 1095 if (mytypeNode != null) { 1096 String mytype = mytypeNode.getNodeValue(); 1097 if (!mytype.equals("standard")) { 1098 if (!parentNodeName.equals("calendar")) { 1099 type = mytype; 1100 } else { 1101 parentNodeName = mytype; 1102 } 1103 } 1104 } 1105 1106 } 1107 if (grandParentNodeName.equals("eras")) { 1108 Node calendar = grandParentNode.getParentNode(); 1109 NamedNodeMap gpa = calendar.getAttributes(); 1110 Node gptNode = gpa.getNamedItem("type"); 1111 if (gptNode != null) { 1112 String gptType = gptNode.getNodeValue(); 1113 if (!gptType.equals("standard")) { 1114 grandParentNodeName = gptType; 1115 } 1116 } 1117 parentNodeName = grandParentNodeName + "\u200b_" + parentNodeName; 1118 } 1119 if (grandParentNodeName.equals("calendar")) { 1120 NamedNodeMap gpa = grandParentNode.getAttributes(); 1121 Node gptNode = gpa.getNamedItem("type"); 1122 if (gptNode != null) { 1123 String gptType = gptNode.getNodeValue(); 1124 if (!gptType.equals("standard")) { 1125 grandParentNodeName = gptType; 1126 } 1127 } 1128 parentNodeName = grandParentNodeName + "\u200b_" + parentNodeName; 1129 } 1130 if (grandParentNodeName.equals("monthContext") || grandParentNodeName.equals("dayContext") || 1131 grandParentNodeName.equals("dateFormatLength") || grandParentNodeName.equals("timeFormatLength") || 1132 grandParentNodeName.equals("dateTimeFormatLength")) { 1133 1134 Node calendar = grandParentNode.getParentNode().getParentNode(); 1135 NamedNodeMap ggpa = calendar.getAttributes(); 1136 Node ggptNode = ggpa.getNamedItem("type"); 1137 if (ggptNode != null) { 1138 String ggptType = ggptNode.getNodeValue(); 1139 if (!ggptType.equals("standard")) { 1140 grandParentNodeName = ggptType; 1141 parentNodeName = ggptType + "\u200b_" + parentNodeName; 1142 } 1143 } 1144 NamedNodeMap gpa = grandParentNode.getAttributes(); 1145 Node gptNode = gpa.getNamedItem("type"); 1146 if (gptNode != null) { 1147 String gptType = gptNode.getNodeValue(); 1148 if (!gptType.equals("standard")) { 1149 parentNodeName = parentNodeName + "\u200b_" + gptType; 1150 } 1151 } 1152 NamedNodeMap pa = parentNode.getAttributes(); 1153 Node ptNode = pa.getNamedItem("type"); 1154 if (ptNode != null) { 1155 String ptType = ptNode.getNodeValue(); 1156 if (!ptType.equals("standard")) { 1157 parentNodeName = parentNodeName + "\u200b_" + ptType; 1158 } 1159 } 1160 1161 } 1162 if (childNodeName.equals("pattern") || grandParentNodeName.equals("zone")) { 1163 if (parentNodeName.indexOf("date") == -1 && parentNodeName.indexOf("time") == -1) { 1164 NamedNodeMap at = grandParentNode.getAttributes(); 1165 Node mytypeNode = at.getNamedItem("type"); 1166 if (mytypeNode != null) { 1167 String mytype = mytypeNode.getNodeValue(); 1168 if (!mytype.equals("standard")) { 1169 if (type.equals("")) { 1170 type = mytype; 1171 } else { 1172 type = type + "\u200b_" + mytype; 1173 } 1174 1175 } 1176 } 1177 } 1178 } 1179 if (grandParentNodeName.equals("special") || parentNodeName.equals("special") 1180 || childNodeName.equals("special") 1181 || grandParentNodeName.indexOf(":") > 0) { 1182 continue; 1183 } 1184 if (!nodeValue.equals("") && 1185 !childOfSource.getNodeName().equals("version")) { 1186 1187 // for country codes and language codes 1188 // replace the deprecated codes with the latest ones 1189 if (childNodeName.equals("language")) { 1190 String temp = deprecatedLanguageCodes.get(index); 1191 if (temp != null) { 1192 index = temp; 1193 } 1194 } else if (childNodeName.equals("territory")) { 1195 String temp = deprecatedCountryCodes.get(index); 1196 if (temp != null) { 1197 index = temp; 1198 } 1199 if (index != null && alt != null) { 1200 index = index + "_" + alt; 1201 } 1202 } 1203 String id = ""; 1204 if (!type.equals("")) { 1205 id = parentNodeName + "_" + childNodeName + "_" + type + "_" + getTag(childNodeName, index) 1206 + "_" + grandParentNodeName; 1207 } else { 1208 id = parentNodeName + "_" + childNodeName + "_" + getTag(childNodeName, index) + "_" 1209 + grandParentNodeName; 1210 } 1211 if (!index.equals("")) { 1212 if (!index.equals(nodeValue) && !index.equals("Fallback")) { 1213 if (!m_Vetting || subDraft) { 1214 addElement(childNodeName, parentNodeName, id, index, nodeValue, key, referenceUrl); 1215 if (altText != null) { 1216 addElement(childNodeName, parentNodeName, id, index, altText, "ALT", null /* altReferenceUrl */); 1217 } 1218 } 1219 } 1220 } else { 1221 if (!type.equals(nodeValue) && !type.equals("Fallback")) { 1222 if (!m_Vetting || subDraft) { 1223 addElement(childNodeName, parentNodeName, id, type, nodeValue, key, referenceUrl); 1224 if (altText != null) { 1225 addElement(childNodeName, parentNodeName, id, index, altText, "ALT", null /* altReferenceUrl */); 1226 } 1227 } 1228 } 1229 } 1230 } 1231 if (attr.getLength() > 0 && typeNode == null) { // TODO: make this a fcn 1232 // add an element for each attribute different for each attribute 1233 if (!m_Vetting || subDraft) { 1234 for (int i = 0; i < attr.getLength(); i++) { 1235 Node item = attr.item(i); 1236 String attrName = item.getNodeName(); 1237 if (attrName.equals("type")) { 1238 continue; 1239 } 1240 if (attrName.equals("alt")) { 1241 continue; 1242 } 1243 if (attrName.equals("draft")) { 1244 continue; 1245 } 1246 if (grandParentNodeName.equals("zone")) { 1247 parentNodeName = grandParentNodeName + "\u200b_" + parentNodeName; 1248 } 1249 String id = grandParentNodeName + "_" + parentNodeName + "_" + childNodeName + "_" + type 1250 + "_" + attrName; 1251 String subNodeValue = item.getNodeValue(); 1252 if (altForChild != null) { 1253 System.err.println(parentNodeName + "/" + childNodeName + " alt?? : " + altText); 1254 throw new IllegalArgumentException("UNKNOWN ALT SUBTAG + " + parentNodeName + "/" 1255 + childNodeName + " alt?? : " + altText + " not " + subNodeValue); 1256 } 1257 if (!index.equals("")) { 1258 addElement(childNodeName, parentNodeName, id, index, subNodeValue, key); 1259 } else if (!type.equals("")) { 1260 addElement(childNodeName, parentNodeName, id, type, subNodeValue, key); 1261 } else { 1262 if (!attrName.equals("draft")) { 1263 addElement(childNodeName, parentNodeName, id, attrName, subNodeValue, key); 1264 } 1265 } 1266 } 1267 } 1268 } 1269 } else { 1270 // the element has more children .. recurse to pick them all 1271 extractMergeData(childOfSource, key, subDraft); 1272 } 1273 } 1274 return true; 1275 } 1276 1277 // ***************************************************************************************************** 1278 // method writes the differences between xml files all to one HTML file 1279 // added by PN 1280 // ***************************************************************************************************** doBulkComparison()1281 private void doBulkComparison() { 1282 // get the output file name 1283 String fileName = destFolder + "/" + "Bulk.html"; 1284 System.out.println("INFO: Creating file named: " + fileName); 1285 String fileName_summary = destFolder + "/" + "Bulk_summary.html"; 1286 System.out.println("INFO: Creating file named: " + fileName_summary); 1287 1288 try { 1289 OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(fileName), encoding); 1290 OutputStreamWriter os_summary = new OutputStreamWriter(new FileOutputStream(fileName_summary), encoding); 1291 1292 // write the beginning of HTML page 1293 PrintWriter writer = new PrintWriter(os); 1294 PrintWriter writer_summary = new PrintWriter(os_summary); 1295 printHTMLStart(writer); 1296 printInfo(writer); 1297 printHTMLStart(writer_summary); 1298 1299 // not all platforms have files for all locales so first build a locale superset 1300 // loop thru locale files from each folder, each folder contains a certain number of locales 1301 // build a HashSet superset 1302 File localeDir = null; 1303 String[] fileList; 1304 Set<String> localeTreeSet = new TreeSet<>(); // use TreeSet for locales in alphabetical order 1305 for (int i = 0; i < m_PlatformFolderVect.size(); i++) { 1306 localeDir = new File(m_PlatformFolderVect.elementAt(i)); 1307 fileList = localeDir.list(); 1308 for (int j = 0; j < fileList.length; j++) { 1309 if (fileList[j].endsWith(".xml")) { 1310 // need to exclude root.xml and supplementalData.xml 1311 if ((fileList[j].compareTo("root.xml") == 0) 1312 || (fileList[j].compareTo("supplementalData.xml") == 0)) 1313 continue; 1314 1315 // exclude common if -diff_ref_common option chosen by user 1316 // as common will only be shown as a reference if there are differences between locales for 1317 // other platforms 1318 if ((m_iOptions & OPT_DIFF_REF_COMMON) != 0) { 1319 String platform = m_PlatformVect.elementAt(i); 1320 if (platform.compareTo(COMMON) == 0) 1321 continue; 1322 } 1323 1324 // entries are only added to TreeSets if not already there 1325 localeTreeSet.add(fileList[j]); 1326 // System.out.println (j + " adding " + fileList[j] + " to super set for platform " + (String) 1327 // m_PlatformFolderVect.elementAt(i) ); 1328 } 1329 } 1330 } 1331 1332 // System.out.println(" size of locale set = " + localeTreeSet.size()); 1333 // System.out.println(" number of platforms = " + m_PlatformFolderVect.size() + "(" + m_PlatformVect.size() 1334 // + ")"); 1335 1336 // loop thru all locales 1337 Object[] localeArray = localeTreeSet.toArray(); 1338 int i = 0; 1339 for (i = 0; i < localeArray.length; i++) { 1340 String platforms_with_this_locale = ""; 1341 1342 String localeFile = (String) localeArray[i]; // locale file name without path 1343 // class member localeStr used for writing to html 1344 localeStr = localeFile.substring(0, localeFile.indexOf('.')); 1345 System.out.println("INFO: locale : " + localeStr); 1346 1347 // add entry to CompareMap for any platforms having an xml file for the locale in question 1348 for (int j = 0; j < m_PlatformFolderVect.size(); j++) { 1349 localeDir = new File(m_PlatformFolderVect.elementAt(j)); 1350 fileList = localeDir.list(); 1351 for (int k = 0; k < fileList.length; k++) { 1352 if (fileList[k].compareTo(localeFile) == 0) // test for 2 matching xml filenames 1353 { 1354 String key = m_PlatformVect.elementAt(j); // should use hashtable to link 1355 // m_PlatformVect and 1356 // m_PlatformFolderVect 1357 String xmlFileName = localeDir + "/" + localeArray[i]; 1358 // System.out.println(i + " " + j + " " + k + " adding " + xmlFileName + 1359 // " to compareMap at key " + key); 1360 addToCompareMap(xmlFileName, key); 1361 1362 if (!(((m_iOptions & OPT_DIFF_REF_COMMON) != 0) 1363 && (key.compareTo(COMMON) == 0))) { 1364 platforms_with_this_locale += key; 1365 platforms_with_this_locale += ", "; 1366 } 1367 } 1368 } 1369 } 1370 // System.out.println("size of compareMap " + compareMap.size()); 1371 1372 // print locale info and table header for this locale 1373 printHTMLLocaleStart(writer, i, platforms_with_this_locale); 1374 printTableHeaderForDifferences(writer); 1375 1376 // now do the comparison for a specific locale 1377 walkCompareMap(writer, localeStr, platforms_with_this_locale); 1378 1379 // clear the compareMap before starting next locale 1380 compareMap.clear(); 1381 1382 // finish html table 1383 printHTMLLocaleEnd(writer); 1384 1385 } // end outer for loop on locales 1386 1387 // print summary data to html summary file 1388 printLocaleSummaryToHTML(writer_summary); 1389 printAccumulatedResultsToHTML(writer_summary); 1390 1391 printHTMLEnd(writer, i); 1392 printHTMLEnd(writer_summary, i); 1393 } catch (Exception e) { 1394 e.printStackTrace(); 1395 } 1396 System.out.println("INFO: Finished writing file named: " + fileName); 1397 System.out.println("INFO: Finished writing file named: " + fileName_summary); 1398 } 1399 1400 // added by PN printHTMLStart(PrintWriter writer)1401 private void printHTMLStart(PrintWriter writer) { 1402 // System.out.println("INFO: Creating the comparison chart "); 1403 1404 writer.print("<html>\n" + 1405 " <head>\n" + 1406 " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n" + 1407 " </head>\n" + 1408 " <style>\n" + 1409 " <!--\n" + 1410 " table { border-spacing: 0; border-collapse: collapse; width:100%; \n" + 1411 " border: 1px solid black }\n" + 1412 " td, th { border-spacing: 0; border-collapse: collapse; color: black; \n" + 1413 " vertical-align: top; border: 1px solid black }\n" + 1414 " -->\n" + 1415 " </style>" + 1416 " <body bgcolor=\"#FFFFFF\"> \n" + 1417 " <p><b>LOCALE DATA AUDIT</b></p>"); 1418 1419 writer.print(" <p>Created on: " + cal.getTime() + "</p>\n"); 1420 } 1421 printInfo(PrintWriter writer)1422 private void printInfo(PrintWriter writer) { 1423 if (((m_iOptions & OPT_DIFF_REF_COMMON) != 0) 1424 || ((m_iOptions & OPT_DIFF) != 0)) { 1425 writer 1426 .print(" <p>locale elements where there is a difference between at least two platforms are shown. \n" 1427 + 1428 "If a locale element is the same across all platforms it is not shown </p>"); 1429 } 1430 1431 if ((m_iOptions & OPT_DIFF_REF_COMMON) != 0) 1432 writer 1433 .print("<p> Common data is shown for reference purposes only and is not part of the comparison</p>\n"); 1434 1435 } 1436 1437 // added by PN printHTMLEnd(PrintWriter writer, int iTotalNumLocales)1438 private void printHTMLEnd(PrintWriter writer, int iTotalNumLocales) { 1439 writer.print("<p> </p>"); 1440 writer.print("<p> </p>"); 1441 writer.print(" <p><b>SUMMARY : </b></p>"); 1442 String platforms = ""; 1443 for (int i = 0; i < m_PlatformVect.size(); i++) { 1444 if (((m_iOptions & OPT_DIFF_REF_COMMON) != 0) 1445 && (m_PlatformVect.elementAt(i).equals(COMMON))) { 1446 continue; 1447 } 1448 platforms += m_PlatformVect.elementAt(i); 1449 platforms += ", "; 1450 } 1451 1452 writer.print(" <p><b>Platforms compared : " + platforms + "</b></p>"); 1453 writer 1454 .print(" <p><b>Total Number of locales audited : " 1455 + iTotalNumLocales 1456 + "</b></p>" 1457 + 1458 " <p><b>Total Number of conflicting locale data across all locales : " 1459 + serialNumber 1460 + "</b></p>" 1461 + 1462 " <p><b>Number of locale elements where a conflict was found for at least one locale : " 1463 + m_iTotalConflictingElements 1464 + "</b></p>" 1465 + 1466 " <p><b>Number of locale elements where no conflicts were found for any locale having this element : " 1467 + m_iTotalNonConflictingElements + "</b></p>" + 1468 " </body>\n" + 1469 "</html>\n"); 1470 writer.flush(); 1471 1472 writer.flush(); 1473 } 1474 1475 // added by PN printHTMLLocaleStart(PrintWriter writer, int iLocaleCounter, String platforms_with_this_locale)1476 private void printHTMLLocaleStart(PrintWriter writer, int iLocaleCounter, String platforms_with_this_locale) { 1477 ULocale locale = new ULocale(localeStr); 1478 String displayLang = locale.getDisplayLanguage(); 1479 String dispCountry = locale.getDisplayCountry(); 1480 String dispVariant = locale.getDisplayVariant(); 1481 String displayName = localeStr + " (" + displayLang + "_" + dispCountry; 1482 if (dispVariant.length() > 0) { 1483 displayName += "_" + dispVariant + ") "; 1484 } else { 1485 displayName += ") "; 1486 } 1487 1488 writer.print( 1489 " <p><b>" + iLocaleCounter + " " + displayName + 1490 // "<a href=\"http://oss.software.ibm.com/cgi-bin/icu/lx/en/?_="+localeStr+"\">Demo</a>, "+ 1491 // "<a href=\"../comparison_charts.html\">Cover Page</a>, "+ 1492 // "<a href=\"./index.html\">Index</a>, "+ 1493 // "<a href=\"../collation_diff/"+localeStr+"_collation.html\">Collation</a> "+ 1494 "</b>" + 1495 "<b> platforms with this locale : " + platforms_with_this_locale + "</b></p>\n" + 1496 " <table>\n"); 1497 } 1498 1499 // added by PN printHTMLLocaleEnd(PrintWriter writer)1500 private void printHTMLLocaleEnd(PrintWriter writer) { 1501 writer.print(" </table>\n"); 1502 } 1503 1504 // added by PN walkCompareMap(PrintWriter writer, String locale, String platforms)1505 private void walkCompareMap(PrintWriter writer, String locale, String platforms) { 1506 SummaryData summData = new SummaryData(); 1507 1508 // walk down the compare map and print the data 1509 Iterator<String> iter = compareMap.keySet().iterator(); 1510 while (iter.hasNext()) { 1511 Object obj = iter.next(); 1512 CompareElement element; 1513 if (obj != null) { 1514 Object value = compareMap.get(obj); 1515 if (value instanceof CompareElement) { 1516 element = (CompareElement) value; 1517 } else { 1518 throw new RuntimeException( 1519 "The object stored in the compare map is not an instance of CompareElement"); 1520 } 1521 1522 boolean bIsEqual = true; 1523 if ((m_iOptions & OPT_DIFF) != 0) { 1524 bIsEqual = printDifferentValues(element, writer); 1525 AddToAccumulatedResultsMap((String) obj, element, localeStr, bIsEqual); 1526 } else if ((m_iOptions & OPT_DIFF_REF_COMMON) != 0) { 1527 bIsEqual = printDifferentValuesWithRef(element, writer); 1528 AddToAccumulatedResultsMap((String) obj, element, localeStr, bIsEqual); 1529 } else { 1530 printValue(element, writer); 1531 } 1532 1533 if (bIsEqual == false) 1534 summData.m_iNumConflictingElements++; 1535 1536 } else { 1537 throw new RuntimeException("No objects stored in the compare map!"); 1538 } 1539 } 1540 summData.m_szPlatforms = platforms; 1541 m_LocaleSummaryDataMap.put(locale, summData); 1542 1543 } 1544 1545 // PN added AddToAccumulatedResultsMap(String id, CompareElement element, String locale, boolean bIsEqual)1546 private void AddToAccumulatedResultsMap(String id, CompareElement element, String locale, boolean bIsEqual) { 1547 if (element == null) 1548 return; 1549 1550 AccumulatedResults ad = m_AccumulatedResultsMap.get(id); 1551 if (ad == null) { 1552 // System.out.println("id = " + id); 1553 1554 // add a new entry, there's none there with this key 1555 ad = new AccumulatedResults(); 1556 ad.index = element.index; 1557 ad.node = element.node; 1558 ad.parentNode = element.parentNode; 1559 if (bIsEqual == false) 1560 ad.localeVectDiff.add(locale); 1561 else 1562 ad.localeVectSame.add(locale); 1563 m_AccumulatedResultsMap.put(id, ad); 1564 } else { 1565 if ((!ad.index.equals(element.index)) || 1566 (!ad.node.equals(element.node)) || 1567 (!ad.parentNode.equals(element.parentNode))) // || 1568 // (!ad.type.equals(element.type))) type can be null so don't ceck its value 1569 { 1570 throw new RuntimeException( 1571 "The retrieved AccumulatedResults is not the same as the one trying to be saved - " + id); 1572 } else { 1573 if (bIsEqual == false) 1574 ad.localeVectDiff.add(locale); 1575 else 1576 ad.localeVectSame.add(locale); 1577 } 1578 } 1579 } 1580 printAccumulatedResultsToHTML(PrintWriter writer)1581 private void printAccumulatedResultsToHTML(PrintWriter writer) { 1582 writer.print("<p> </p>"); 1583 writer.print("<p> </p>"); 1584 writer 1585 .print("<p><b>Table below shows the number of locales where conflicts did and didn't occur on a per locale element basis"); 1586 writer 1587 .print(" (For brevity, locale elements where no conflicts were detected for any locale are not shown) </b></p>"); 1588 writer.print("<p></p>"); 1589 writer.print(" <table width=\"700\">\n"); 1590 writer.print(" <tr>\n" + 1591 " <th width=5%>N.</th>\n" + 1592 " <th width=10%>ParentNode</th>\n" + 1593 " <th width=10%>Name</th>\n" + 1594 " <th width=10%>ID</th>\n" + 1595 " <th width=10%># of non-conflicting locales</th>" + 1596 " <th width=10%># of conflicting locales</th>" + 1597 " <th width=45%>Locales where conflicts were found</th>" + 1598 " </tr>\n"); 1599 1600 // walk down the cm_AccumulateDifferenceMap and print the data 1601 Iterator<String> iter = m_AccumulatedResultsMap.keySet().iterator(); 1602 // System.out.println ("size = " + m_AccumulateDifferenceMap.size()); 1603 1604 int iCounter = 0; 1605 while (iter.hasNext()) { 1606 Object obj = iter.next(); 1607 AccumulatedResults ad; 1608 if (obj != null) { 1609 Object value = m_AccumulatedResultsMap.get(obj); 1610 if (value instanceof AccumulatedResults) { 1611 ad = (AccumulatedResults) value; 1612 } else { 1613 throw new RuntimeException( 1614 "The object stored in the AccumulateDifferencesMap is not an instance of AccumulateDifferences"); 1615 } 1616 1617 // only print locale elements where differences occurred 1618 if (ad.localeVectDiff.size() > 0) { 1619 m_iTotalConflictingElements++; 1620 writer.print(" <tr>\n"); 1621 writer.print(" <td>" + (iCounter++) + "</td>\n"); 1622 writer.print(" <td>" + ad.parentNode + "</td>\n"); 1623 writer.print(" <td>" + ad.node + "</td>\n"); 1624 writer.print(" <td>" + ad.index + "</td>\n"); 1625 writer.print(" <td>" + ad.localeVectSame.size() + "</td>\n"); 1626 writer.print(" <td>" + ad.localeVectDiff.size() + "</td>\n"); 1627 String locales = ""; 1628 for (int i = 0; i < ad.localeVectDiff.size(); i++) { 1629 locales += ad.localeVectDiff.elementAt(i); 1630 locales += ", "; 1631 } 1632 writer.print(" <td>" + locales + "</td>\n"); 1633 writer.print(" </tr>\n"); 1634 } else { 1635 m_iTotalNonConflictingElements++; 1636 } 1637 1638 } else { 1639 throw new RuntimeException("No objects stored in the AccumulateDifferencesMap!"); 1640 } 1641 } 1642 1643 writer.print(" </table>\n"); 1644 1645 } 1646 printLocaleSummaryToHTML(PrintWriter writer)1647 private void printLocaleSummaryToHTML(PrintWriter writer) { 1648 writer.print("<p> </p>"); 1649 writer.print("<p> </p>"); 1650 writer.print("<p><b>Table below shows the number of conflicting elements on a per locale basis\n</b></p>"); 1651 writer.print("<p></p>"); 1652 writer.print(" <table width=\"700\">\n"); 1653 writer.print(" <tr>\n" + 1654 " <th width=5%>N.</th>\n" + 1655 " <th width=20%>Locale</th>\n" + 1656 " <th width=40%>Platforms With This Locale</th>\n" + 1657 " <th width=35%># of elements where a conflict was found</th>\n" + 1658 " </tr>\n"); 1659 1660 // walk down the cm_AccumulateDifferenceMap and print the data 1661 Iterator<String> iter = m_LocaleSummaryDataMap.keySet().iterator(); 1662 int iCounter = 0; 1663 while (iter.hasNext()) { 1664 Object obj = iter.next(); 1665 SummaryData summData; 1666 if (obj != null) { 1667 Object value = m_LocaleSummaryDataMap.get(obj); 1668 if (value instanceof SummaryData) { 1669 summData = (SummaryData) value; 1670 } else { 1671 throw new RuntimeException( 1672 "The object stored in the AccumulateDifferencesMap is not an instance of AccumulateDifferences"); 1673 } 1674 1675 writer.print(" <tr>\n"); 1676 writer.print(" <td>" + (iCounter++) + "</td>\n"); 1677 writer.print(" <td>" + (String) obj + "</td>\n"); 1678 writer.print(" <td>" + summData.m_szPlatforms + "</td>\n"); 1679 writer.print(" <td>" + summData.m_iNumConflictingElements + "</td>\n"); 1680 writer.print(" </tr>\n"); 1681 } else { 1682 throw new RuntimeException("No objects stored in the AccumulateDifferencesMap!"); 1683 } 1684 } 1685 1686 writer.print(" </table>\n"); 1687 } 1688 1689 } // end of class definition/declaration 1690