1 package org.unicode.cldr.tool; 2 3 import java.io.FileNotFoundException; 4 import java.util.Arrays; 5 import java.util.Collections; 6 import java.util.EnumMap; 7 import java.util.EnumSet; 8 import java.util.HashSet; 9 import java.util.LinkedHashSet; 10 import java.util.Map; 11 import java.util.Set; 12 13 import org.unicode.cldr.util.CLDRConfig; 14 import org.unicode.cldr.util.DtdData; 15 import org.unicode.cldr.util.DtdData.Attribute; 16 import org.unicode.cldr.util.DtdData.Element; 17 import org.unicode.cldr.util.DtdType; 18 import org.unicode.cldr.util.SupplementalDataInfo; 19 20 import com.ibm.icu.dev.util.CollectionUtilities; 21 22 public class ShowDtdDiffs { 23 static final SupplementalDataInfo SDI = CLDRConfig.getInstance().getSupplementalDataInfo(); 24 25 static Set<DtdType> TYPES = EnumSet.allOf(DtdType.class); 26 static { 27 TYPES.remove(DtdType.ldmlICU); 28 } 29 30 static final Map<DtdType, String> FIRST_VERSION = new EnumMap<>(DtdType.class); 31 static { FIRST_VERSION.put(DtdType.ldmlBCP47, "1.7.2")32 FIRST_VERSION.put(DtdType.ldmlBCP47, "1.7.2"); FIRST_VERSION.put(DtdType.keyboard, "22.1")33 FIRST_VERSION.put(DtdType.keyboard, "22.1"); FIRST_VERSION.put(DtdType.platform, "22.1")34 FIRST_VERSION.put(DtdType.platform, "22.1"); 35 } 36 main(String[] args)37 public static void main(String[] args) { 38 String last = null; 39 for (String current : ToolConstants.CLDR_VERSIONS) { 40 String currentName = current == null ? "trunk" : current; 41 for (DtdType type : TYPES) { 42 String firstVersion = FIRST_VERSION.get(type); 43 if (firstVersion != null && current != null && current.compareTo(firstVersion) < 0) { 44 continue; 45 } 46 DtdData dtdCurrent = null; 47 try { 48 dtdCurrent = DtdData.getInstance(type, current); 49 } catch (Exception e) { 50 if (!(e.getCause() instanceof FileNotFoundException)) { 51 throw e; 52 } 53 System.out.println(e.getMessage() + ", " + e.getCause().getMessage()); 54 continue; 55 } 56 DtdData dtdLast = null; 57 if (last != null) { 58 try { 59 dtdLast = DtdData.getInstance(type, last); 60 } catch (Exception e) { 61 if (!(e.getCause() instanceof FileNotFoundException)) { 62 throw e; 63 } 64 } 65 } 66 diff(currentName + "\t" + type, dtdLast, dtdCurrent); 67 } 68 last = current; 69 } 70 } 71 diff(String prefix, DtdData dtdLast, DtdData dtdCurrent)72 private static void diff(String prefix, DtdData dtdLast, DtdData dtdCurrent) { 73 Map<String, Element> oldNameToElement = dtdLast == null ? Collections.EMPTY_MAP : dtdLast.getElementFromName(); 74 checkNames(prefix, dtdCurrent, oldNameToElement, "/", dtdCurrent.ROOT, new HashSet<Element>()); 75 } 76 checkNames(String prefix, DtdData dtdCurrent, Map<String, Element> oldNameToElement, String path, Element element, HashSet<Element> seen)77 private static void checkNames(String prefix, DtdData dtdCurrent, Map<String, Element> oldNameToElement, String path, Element element, 78 HashSet<Element> seen) { 79 if (seen.contains(element)) { 80 return; 81 } 82 seen.add(element); 83 String name = element.getName(); 84 if (SKIP_ELEMENTS.contains(name)) { 85 return; 86 } 87 88 if (isDeprecated(dtdCurrent.dtdType, name, "*")) { // SDI.isDeprecated(dtdCurrent.dtdType, name, "*", "*")) { 89 return; 90 } 91 String newPath = path + "/" + element.name; 92 if (!oldNameToElement.containsKey(name)) { 93 String attributeNames = getAttributeNames(dtdCurrent, name, Collections.EMPTY_MAP, element.getAttributes()); 94 System.out.println(prefix + "\tElement\t" + newPath + "\t" + attributeNames); 95 } else { 96 Element oldElement = oldNameToElement.get(name); 97 String attributeNames = getAttributeNames(dtdCurrent, name, oldElement.getAttributes(), element.getAttributes()); 98 if (!attributeNames.isEmpty()) { 99 System.out.println(prefix + "\tAttribute\t" + newPath + "\t" + attributeNames); 100 } 101 } 102 for (Element child : element.getChildren().keySet()) { 103 checkNames(prefix, dtdCurrent, oldNameToElement, newPath, child, seen); 104 } 105 } 106 107 // static class Parents { 108 // final DtdData dtd; 109 // final Relation<String,String> childToParents = Relation.of(new HashMap(), HashSet.class); 110 // static Map<DtdData,Parents> cache = new ConcurrentHashMap<>(); 111 // 112 // public Parents(DtdData dtd) { 113 // this.dtd = dtd; 114 // } 115 // 116 // static Parents getInstance(DtdData dtd) { 117 // Parents result = cache.get(dtd); 118 // if (result == null) { 119 // result = new Parents(dtd); 120 // result.addParents(dtd.ROOT, new HashSet<Element>()); 121 // result.childToParents.freeze(); 122 // } 123 // return result; 124 // } 125 // 126 // private void addParents(Element element, HashSet<Element> seen) { 127 // if (!seen.contains(element)) { 128 // for (Element child : element.getChildren().keySet()) { 129 // childToParents.put(child.name, element.name); 130 // addParents(child, seen); 131 // } 132 // } 133 // } 134 // } 135 136 static final Set<String> SKIP_ELEMENTS = new HashSet<>(Arrays.asList("generation", "identity", "alias", "special", "telephoneCodeData")); 137 static final Set<String> SKIP_ATTRIBUTES = new HashSet<>(Arrays.asList("references", "standard", "draft", "alt")); 138 getAttributeNames(DtdData dtdCurrent, String elementName, Map<Attribute, Integer> attributesOld, Map<Attribute, Integer> attributes)139 private static String getAttributeNames(DtdData dtdCurrent, String elementName, Map<Attribute, Integer> attributesOld, Map<Attribute, Integer> attributes) { 140 Set<String> names = new LinkedHashSet<>(); 141 main: for (Attribute attribute : attributes.keySet()) { 142 String name = attribute.getName(); 143 if (SKIP_ATTRIBUTES.contains(name)) { 144 continue; 145 } 146 if (isDeprecated(dtdCurrent.dtdType, elementName, name)) { // SDI.isDeprecated(dtdCurrent, elementName, name, "*")) { 147 continue; 148 } 149 for (Attribute attributeOld : attributesOld.keySet()) { 150 if (attributeOld.name.equals(name)) { 151 continue main; 152 } 153 } 154 names.add(name); 155 } 156 return names.isEmpty() ? "" : CollectionUtilities.join(names, ", "); 157 } 158 isDeprecated(DtdType dtdType, String elementName, String attributeName)159 private static boolean isDeprecated(DtdType dtdType, String elementName, String attributeName) { 160 try { 161 return DtdData.getInstance(dtdType).isDeprecated(elementName, attributeName, "*"); 162 } catch (DtdData.IllegalByDtdException e) { 163 return true; 164 } 165 } 166 }