Home | History | Annotate | Download | only in util
      1 package org.unicode.cldr.util;
      2 
      3 import java.io.BufferedReader;
      4 import java.io.File;
      5 import java.io.FileInputStream;
      6 import java.io.IOException;
      7 import java.io.InputStreamReader;
      8 import java.io.PrintWriter;
      9 import java.util.ArrayList;
     10 import java.util.Arrays;
     11 import java.util.Collection;
     12 import java.util.Collections;
     13 import java.util.HashSet;
     14 import java.util.Iterator;
     15 import java.util.LinkedHashSet;
     16 import java.util.List;
     17 import java.util.Map;
     18 import java.util.Set;
     19 import java.util.TreeMap;
     20 import java.util.TreeSet;
     21 
     22 import org.unicode.cldr.draft.FileUtilities;
     23 import org.xml.sax.Attributes;
     24 import org.xml.sax.ContentHandler;
     25 import org.xml.sax.ErrorHandler;
     26 import org.xml.sax.InputSource;
     27 import org.xml.sax.Locator;
     28 import org.xml.sax.SAXException;
     29 import org.xml.sax.SAXParseException;
     30 import org.xml.sax.XMLReader;
     31 import org.xml.sax.ext.DeclHandler;
     32 
     33 import com.ibm.icu.impl.Relation;
     34 import com.ibm.icu.text.UTF16;
     35 
     36 /**
     37  * @deprecated
     38  */
     39 public class FindDTDOrder implements DeclHandler, ContentHandler, ErrorHandler {
     40     static final boolean SHOW_PROGRESS = CldrUtility.getProperty("verbose", false);
     41     static final boolean SHOW_ALL = CldrUtility.getProperty("show_all", false);
     42     private static final boolean DEBUG = false;
     43 
     44     private static FindDTDOrder INSTANCE;
     45 
     46     private boolean recordingAttributeElements;
     47 
     48     public static void main(String[] args) throws IOException {
     49         System.out.println("Outdated, no longer used");
     50         FindDTDOrder me = getInstance();
     51         me.showData();
     52     }
     53 
     54     public static FindDTDOrder getInstance() {
     55         synchronized (FindDTDOrder.class) {
     56             if (INSTANCE == null) {
     57                 try {
     58                     FindDTDOrder me = new FindDTDOrder();
     59                     XMLReader xmlReader = CLDRFile.createXMLReader(true);
     60                     xmlReader.setContentHandler(me);
     61                     xmlReader.setErrorHandler(me);
     62                     xmlReader.setProperty(
     63                         "http://xml.org/sax/properties/declaration-handler", me);
     64 
     65                     FileInputStream fis;
     66                     InputSource is;
     67                     me.recordingAttributeElements = true;
     68                     String filename = CLDRPaths.MAIN_DIRECTORY + "/root.xml";
     69                     File file = new File(filename);
     70                     if (DEBUG) {
     71                         System.out.println("Opening " + file.getCanonicalFile());
     72                     }
     73                     File dtd = new File(file.getCanonicalPath() + "/../" + "../../common/dtd/ldml.dtd");
     74                     if (DEBUG) {
     75                         System.out.println("Opening " + dtd.getCanonicalFile());
     76                     }
     77 
     78                     fis = new FileInputStream(filename);
     79                     if (DEBUG) {
     80                         BufferedReader b = new BufferedReader(new InputStreamReader(fis));
     81                         for (int i = 0; i < 30; ++i) {
     82                             String line = b.readLine();
     83                             System.out.println(line);
     84                         }
     85                         throw new IllegalArgumentException("just testing");
     86                     }
     87                     is = new InputSource(fis);
     88                     is.setSystemId(file.getCanonicalPath() + "/../");
     89                     xmlReader.parse(is);
     90                     fis.close();
     91 
     92                     me.recordingAttributeElements = false;
     93                     filename = CLDRPaths.DEFAULT_SUPPLEMENTAL_DIRECTORY
     94                         + "/supplementalData.xml";
     95                     File file2 = new File(filename);
     96                     if (DEBUG) {
     97                         System.out.println("Opening " + file2.getCanonicalFile());
     98                     }
     99 
    100                     fis = new FileInputStream(filename);
    101                     is = new InputSource(fis);
    102                     is.setSystemId(file.getCanonicalPath() + "/../");
    103                     xmlReader.parse(is);
    104                     fis.close();
    105                     // Then Attributes
    106                     List<String> rawDtdAttributeOrder = Collections.unmodifiableList(new ArrayList<String>(me.attributeSet));
    107                     List<String> cldrFileAttributeOrder = CLDRFile.getAttributeOrder();
    108 
    109                     LinkedHashSet<String> modifiedDtdOrder = new LinkedHashSet<String>(cldrFileAttributeOrder);
    110                     // add items, keeping the ordering stable
    111                     modifiedDtdOrder.retainAll(rawDtdAttributeOrder); // remove any superfluous stuff
    112                     modifiedDtdOrder.addAll(rawDtdAttributeOrder);
    113 
    114                     // certain stuff always goes at the end
    115                     modifiedDtdOrder.removeAll(me.getCommonAttributes());
    116                     modifiedDtdOrder.addAll(me.getCommonAttributes());
    117 
    118                     // now make a list for comparison
    119                     List<String> dtdAttributeOrder = new ArrayList<String>(modifiedDtdOrder);
    120 
    121                     // fix to and from
    122                     dtdAttributeOrder.remove("from");
    123                     dtdAttributeOrder.add(dtdAttributeOrder.indexOf("to"), "from");
    124 
    125                     me.attributeList = Collections.unmodifiableList(dtdAttributeOrder);
    126                     me.checkData();
    127                     me.orderingList = Collections.unmodifiableList(me.orderingList);
    128 
    129                     // me.writeAttributeElements();
    130                     INSTANCE = me;
    131                 } catch (Exception e) {
    132                     throw (IllegalArgumentException) new IllegalArgumentException().initCause(e);
    133                 }
    134             }
    135         }
    136         return INSTANCE;
    137     }
    138 
    139     public void writeAttributeElements() {
    140         System.out.println(CldrUtility.LINE_SEPARATOR + "======== Start Attributes to Elements (unblocked) "
    141             + CldrUtility.LINE_SEPARATOR);
    142         for (String attribute : attributeToElements.keySet()) {
    143             Set<String> filtered = new TreeSet<String>();
    144             for (String element : attributeToElements.getAll(attribute)) {
    145                 if (!isBlocked(element)) {
    146                     filtered.add(element);
    147                 }
    148             }
    149             System.out.println(attribute + "\t" + CldrUtility.join(filtered, " "));
    150         }
    151         System.out.println(CldrUtility.LINE_SEPARATOR + "======== End Attributes to Elements"
    152             + CldrUtility.LINE_SEPARATOR);
    153         System.out.println(CldrUtility.LINE_SEPARATOR + "======== Start Elements to Children (skipping alias, special)"
    154             + CldrUtility.LINE_SEPARATOR);
    155         showElementTree("ldml", "", new HashSet<String>());
    156         System.out.println(CldrUtility.LINE_SEPARATOR + "======== End Elements to Children"
    157             + CldrUtility.LINE_SEPARATOR);
    158     }
    159 
    160     private void showElementTree(String element, String indent, HashSet<String> seenSoFar) {
    161         // skip blocking elements
    162         if (isBlocked(element)) {
    163             return;
    164         }
    165         Set<String> children = elementToChildren.getAll(element);
    166         if (seenSoFar.contains(element)) {
    167             System.out.println(indent + element
    168                 + (children == null || children.size() == 0 ? "" : "\t*dup*\t" + children));
    169             return;
    170         }
    171         System.out.println(indent + element);
    172         seenSoFar.add(element);
    173         if (children != null) {
    174             indent += "\t";
    175             for (String child : children) {
    176                 showElementTree(child, indent, seenSoFar);
    177             }
    178         }
    179     }
    180 
    181     private boolean isBlocked(String element) {
    182         return isAncestorOf("supplementalData", element)
    183             || isAncestorOf("collation", element)
    184             || isAncestorOf("cldrTest", element)
    185             || isAncestorOf("transform", element);
    186     }
    187 
    188     Relation<String, String> ancestorToDescendant = null;
    189 
    190     private boolean isAncestorOf(String possibleAncestor, String possibleDescendent) {
    191         if (ancestorToDescendant == null) {
    192             ancestorToDescendant = Relation.of(new TreeMap<String, Set<String>>(), TreeSet.class);
    193             buildPairwiseRelations(new ArrayList<String>(), "ldml");
    194         }
    195         Set<String> possibleDescendents = ancestorToDescendant.getAll(possibleAncestor);
    196         if (possibleDescendents == null) return false;
    197         return possibleDescendents.contains(possibleDescendent);
    198     }
    199 
    200     private void buildPairwiseRelations(List<String> parents, String current) {
    201         Set<String> children = elementToChildren.getAll(current);
    202         if (children == null || children.size() == 0) return;
    203 
    204         // we make a new list, since otherwise the iteration fails in recursion (because of the modification)
    205         // if this were performance-sensitive we'd do it differently
    206         ArrayList<String> newParents = new ArrayList<String>(parents);
    207         newParents.add(current);
    208 
    209         for (String child : children) {
    210             for (String ancestor : newParents) {
    211                 ancestorToDescendant.put(ancestor, child);
    212                 buildPairwiseRelations(newParents, child);
    213             }
    214         }
    215     }
    216 
    217     PrintWriter log = null;
    218 
    219     Set elementOrderings = new LinkedHashSet(); // set of orderings
    220 
    221     Set<String> allDefinedElements = new LinkedHashSet<String>();
    222 
    223     boolean showReason = false;
    224 
    225     Object DONE = new Object(); // marker
    226 
    227     Relation<String, String> elementToChildren = Relation.of(new TreeMap<String, Set<String>>(),
    228         TreeSet.class);
    229 
    230     FindDTDOrder() {
    231         log = new PrintWriter(System.out);
    232     }
    233 
    234     private List<String> orderingList = new ArrayList<String>();
    235 
    236     public void checkData() {
    237         // verify that the ordering is the consistent for all child elements
    238         // do this by building an ordering from the lists.
    239         // The first item has no greater item in any set. So find an item that is
    240         // only first
    241         MergeLists<String> mergeLists = new MergeLists<String>(new TreeSet<String>(new UTF16.StringComparator(true,
    242             false, 0)))
    243                 .add(Arrays.asList("ldml"))
    244                 .addAll(elementOrderings); //
    245         List<String> result = mergeLists.merge();
    246         Collection badOrder = MergeLists.hasConsistentOrderWithEachOf(result, elementOrderings);
    247         if (badOrder != null) {
    248             throw new IllegalArgumentException("Failed to find good order: " + badOrder);
    249         }
    250 
    251         showReason = false;
    252         orderingList.add("ldml");
    253         if (SHOW_PROGRESS) {
    254             log.println("SHOW_PROGRESS ");
    255             for (Iterator it = elementOrderings.iterator(); it.hasNext();) {
    256                 Object value = it.next();
    257                 log.println(value);
    258             }
    259         }
    260         while (true) {
    261             Object first = getFirst();
    262             if (first == DONE)
    263                 break;
    264             if (first != null) {
    265                 // log.println("Adding:\t" + first);
    266                 if (orderingList.contains(first)) {
    267                     throw new IllegalArgumentException("Already present: " + first);
    268                 }
    269                 orderingList.add(first.toString());
    270             } else {
    271                 showReason = true;
    272                 getFirst();
    273                 if (SHOW_PROGRESS)
    274                     log.println();
    275                 if (SHOW_PROGRESS)
    276                     log.println("Failed ordering. So far:");
    277                 for (Iterator<String> it = orderingList.iterator(); it.hasNext();)
    278                     if (SHOW_PROGRESS)
    279                         log.print("\t" + it.next());
    280                 if (SHOW_PROGRESS)
    281                     log.println();
    282                 if (SHOW_PROGRESS)
    283                     log.println("Items:");
    284                 // for (Iterator it = element_childComparator.keySet().iterator();
    285                 // it.hasNext();) showRow(it.next(), true);
    286                 if (SHOW_PROGRESS)
    287                     log.println();
    288                 break;
    289             }
    290         }
    291 
    292         if (DEBUG) {
    293             System.out.println("New code in CLDRFile:\n" + result);
    294             System.out.println("Old code in CLDRFile:\n" + orderingList);
    295         }
    296         // System.out.println("New code2: " + CldrUtility.breakLines(CldrUtility.join(result, " "), sep,
    297         // FIRST_LETTER_CHANGE.matcher(""), 80));
    298 
    299         Set<String> missing = new TreeSet<String>(allDefinedElements);
    300         missing.removeAll(orderingList);
    301         orderingList.addAll(missing);
    302 
    303         attributeEquivalents = new XEquivalenceClass(null);
    304         for (Iterator it = attribEquiv.keySet().iterator(); it.hasNext();) {
    305             Object ename = it.next();
    306             Set s = attribEquiv.get(ename);
    307             Iterator it2 = s.iterator();
    308             Object first = it2.next();
    309             while (it2.hasNext()) {
    310                 attributeEquivalents.add(first, it2.next(), ename);
    311             }
    312         }
    313 
    314     }
    315 
    316     String sep = CldrUtility.LINE_SEPARATOR + "\t\t\t";
    317 
    318     private void showData() throws IOException {
    319 
    320         // finish up
    321         String oldAttributeOrder = breakLines(CLDRFile.getAttributeOrder());
    322         log.println("Successful Ordering...");
    323         log.println();
    324         log.println("Old Attribute Ordering: ");
    325         log.println(oldAttributeOrder);
    326 
    327         String newAttributeOrder = breakLines(attributeList);
    328 
    329         if (newAttributeOrder.equals(oldAttributeOrder)) {
    330             log.println("*** New Attribute Ordering: <same>");
    331             log.println("*** No changes required...");
    332         } else {
    333             log.println("*** New Attribute Ordering: ");
    334             log.println(newAttributeOrder);
    335             log.println("*** Replace in CLDRFile elementOrdering  & supplementalMetadata ***");
    336         }
    337 
    338         log.println("Attribute Eq: ");
    339         for (Iterator it = attributeEquivalents.getSamples().iterator(); it.hasNext();) {
    340             log.println("\t"
    341                 + getJavaList(new TreeSet(attributeEquivalents.getEquivalences(it.next()))));
    342         }
    343         if (SHOW_PROGRESS) {
    344             for (Iterator it = attributeEquivalents.getEquivalenceSets().iterator(); it.hasNext();) {
    345                 Object last = null;
    346                 Set s = (Set) it.next();
    347                 for (Iterator it2 = s.iterator(); it2.hasNext();) {
    348                     Object temp = it2.next();
    349                     if (last != null)
    350                         log.println(last + " ~ " + temp + "\t" + attributeEquivalents.getReasons(last, temp));
    351                     last = temp;
    352                 }
    353                 log.println();
    354             }
    355         }
    356 
    357         String oldOrder = getJavaList(CLDRFile.getElementOrder());
    358         log.println("Old Element Ordering:\n"
    359             + oldOrder);
    360 
    361         String newOrder = '"' + breakLines(orderingList) + '"';
    362         if (newOrder.equals(oldOrder)) {
    363             log.println("*** New Element Ordering: <same>");
    364             log.println("*** No changes required...");
    365         } else {
    366             log.println("*** New Element Ordering:\n" + newOrder);
    367             log.println("*** Replace in CLDRFile elementOrdering  & supplementalMetadata ***");
    368         }
    369 
    370         if (SHOW_ALL) {
    371             log.println("Old Size: " + CLDRFile.getElementOrder().size());
    372             Set temp = new HashSet(CLDRFile.getElementOrder());
    373             temp.removeAll(orderingList);
    374             log.println("Old - New: " + temp);
    375             log.println("New Size: " + orderingList.size());
    376             temp = new HashSet(orderingList);
    377             temp.removeAll(CLDRFile.getElementOrder());
    378             log.println("New - Old: " + temp);
    379 
    380             Differ differ = new Differ(200, 1);
    381             Iterator oldIt = CLDRFile.getElementOrder().iterator();
    382             Iterator newIt = orderingList.iterator();
    383             while (oldIt.hasNext() || newIt.hasNext()) {
    384                 if (oldIt.hasNext())
    385                     differ.addA(oldIt.next());
    386                 if (newIt.hasNext())
    387                     differ.addB(newIt.next());
    388                 differ.checkMatch(!oldIt.hasNext() && !newIt.hasNext());
    389 
    390                 if (differ.getACount() != 0 || differ.getBCount() != 0) {
    391                     log.println("Same: " + differ.getA(-1));
    392                     for (int i = 0; i < differ.getACount(); ++i) {
    393                         log.println("\tOld: " + differ.getA(i));
    394                     }
    395                     for (int i = 0; i < differ.getBCount(); ++i) {
    396                         log.println("\t\tNew: " + differ.getB(i));
    397                     }
    398                     log.println("Same: " + differ.getA(differ.getACount()));
    399                 }
    400             }
    401             log.println("Done with differences");
    402         }
    403 
    404         log.flush();
    405 
    406         writeNewSupplemental(CLDRPaths.SUPPLEMENTAL_DIRECTORY, "supplementalMetadata.xml",
    407             "<attributeOrder>", "</attributeOrder>",
    408             "<elementOrder>", "</elementOrder>", "\t\t\t", CldrUtility.LINE_SEPARATOR + "\t\t");
    409         writeNewSupplemental(CLDRPaths.BASE_DIRECTORY + "/tools/java/org/unicode/cldr/util/",
    410             "CLDRFile.java",
    411             "// START MECHANICALLY attributeOrdering GENERATED BY FindDTDOrder",
    412             "// END MECHANICALLY attributeOrdering GENERATED BY FindDTDOrder",
    413             "// START MECHANICALLY elementOrdering GENERATED BY FindDTDOrder",
    414             "// END MECHANICALLY elementOrdering GENERATED BY FindDTDOrder",
    415             "\t\t\t\t\t\"",
    416             '"' + CldrUtility.LINE_SEPARATOR + "\t\t\t\t\t");
    417     }
    418 
    419     private void writeNewSupplemental(String dir, String filename, String startAttributeTag, String endAttributeTag,
    420         String startElementTag, String endElementTag, String startSep, String endSep) throws IOException {
    421         BufferedReader oldFile = FileUtilities.openUTF8Reader(dir, filename);
    422         Log.setLogNoBOM(CLDRPaths.GEN_DIRECTORY + "/DTDOrder/" + filename);
    423 
    424         // CldrUtility.copyUpTo(oldFile, PatternCache.get("\\s*" +
    425         // startAttributeTag +
    426         // "\\s*"), Log.getLog(), true);
    427         // Log.println(startSep + breakLines(attributeSet) + endSep + endAttributeTag);
    428         // CldrUtility.copyUpTo(oldFile, PatternCache.get("\\s*" +
    429         // endAttributeTag +
    430         // "\\s*"), null, true);
    431 
    432         CldrUtility.copyUpTo(oldFile, PatternCache.get("\\s*" +
    433             startElementTag +
    434             "\\s*"), Log.getLog(), true);
    435         Log.println(startSep + breakLines(orderingList) + endSep + endElementTag);
    436         CldrUtility.copyUpTo(oldFile, PatternCache.get("\\s*" +
    437             endElementTag +
    438             "\\s*"), null, true);
    439 
    440         CldrUtility.copyUpTo(oldFile, null, Log.getLog(), false); // copy to end
    441 
    442         Log.close();
    443         oldFile.close();
    444     }
    445 
    446     private String breakLines(Collection orderingList) {
    447         final String joined = CldrUtility.join(orderingList, " ");
    448         return joined; // return Utility.breakLines(joined, sep, FIRST_LETTER_CHANGE.matcher(""), 80);
    449     }
    450 
    451     private String getJavaList(Collection orderingList) {
    452         boolean first2 = true;
    453         StringBuffer result = new StringBuffer();
    454         result.append('"');
    455         for (Iterator it = orderingList.iterator(); it.hasNext();) {
    456             if (first2)
    457                 first2 = false;
    458             else
    459                 result.append(" ");
    460             result.append(it.next().toString());
    461         }
    462         result.append('"');
    463         return result.toString();
    464     }
    465 
    466     /**
    467      * @param parent
    468      * @param skipEmpty
    469      *            TODO
    470      */
    471     // private void showRow(Object parent, boolean skipEmpty) {
    472     // List items = (List) element_childComparator.get(parent);
    473     // if (skipEmpty && items.size() == 0) return;
    474     // if (SHOW_PROGRESS) log.print(parent);
    475     // for (Iterator it2 = items.iterator(); it2.hasNext();) if (SHOW_PROGRESS)
    476     // log.print("\t" + it2.next());
    477     // if (SHOW_PROGRESS) log.println();
    478     // }
    479     /**
    480      * @param orderingList
    481      */
    482     private Object getFirst() {
    483         Set firstItems = new TreeSet();
    484         Set nonFirstItems = new TreeSet();
    485         for (Iterator it = elementOrderings.iterator(); it.hasNext();) {
    486             List list = (List) it.next();
    487             if (list.size() != 0) {
    488                 firstItems.add(list.get(0));
    489                 for (int i = 1; i < list.size(); ++i) {
    490                     nonFirstItems.add(list.get(i));
    491                 }
    492             }
    493         }
    494         if (firstItems.size() == 0 && nonFirstItems.size() == 0)
    495             return DONE;
    496         firstItems.removeAll(nonFirstItems);
    497         if (firstItems.size() == 0)
    498             return null; // failure
    499         Object result = firstItems.iterator().next();
    500         removeEverywhere(result);
    501         return result;
    502     }
    503 
    504     /**
    505      * @param possibleFirst
    506      */
    507     private void removeEverywhere(Object possibleFirst) {
    508         // and remove from all the lists
    509         for (Iterator it2 = elementOrderings.iterator(); it2.hasNext();) {
    510             List list2 = (List) it2.next();
    511             if (SHOW_PROGRESS && list2.contains(possibleFirst)) {
    512                 log.println("Removing " + possibleFirst + " from " + list2);
    513             }
    514             while (list2.remove(possibleFirst))
    515                 ; // repeat until returns false
    516         }
    517     }
    518 
    519     // private boolean isNeverNotFirst(Object possibleFirst) {
    520     // if (showReason) if (SHOW_PROGRESS) log.println("Trying: " + possibleFirst);
    521     // for (Iterator it2 = element_childComparator.keySet().iterator();
    522     // it2.hasNext();) {
    523     // Object key = it2.next();
    524     // List list2 = (List) element_childComparator.get(key);
    525     // int pos = list2.indexOf(possibleFirst);
    526     // if (pos > 0) {
    527     // if (showReason) {
    528     // if (SHOW_PROGRESS) log.print("Failed at:\t");
    529     // showRow(key, false);
    530     // }
    531     // return false;
    532     // }
    533     // }
    534     // return true;
    535     // }
    536 
    537     static final Set<String> ELEMENT_SKIP_LIST = new HashSet<String>(Arrays.asList(new String[] {
    538         "collation", "base", "settings", "suppress_contractions", "optimize",
    539         "rules", "reset", "context", "p", "pc", "s", "sc", "t", "tc",
    540         "i", "ic", "extend", "x" }));
    541 
    542     static final Set<String> SUBELEMENT_SKIP_LIST = new HashSet<String>(Arrays
    543         .asList(new String[] { "PCDATA", "EMPTY", "ANY" }));
    544 
    545     // refine later; right now, doesn't handle multiple elements well.
    546     public void elementDecl(String name, String model) throws SAXException {
    547         // if (ELEMENT_SKIP_LIST.contains(name)) return;
    548         if (name.indexOf("contractions") >= 0
    549             || model
    550                 .indexOf("[alias, base, settings, suppress, contractions, optimize, rules, special]") >= 0) {
    551         }
    552         allDefinedElements.add(name);
    553         if (SHOW_PROGRESS) {
    554             log.println("Element\t" + name + "\t" + model);
    555         }
    556         String[] list = model.split("[^-_A-Z0-9a-z]+");
    557         List<String> mc = new ArrayList<String>();
    558         /*
    559          * if (name.equals("currency")) { mc.add("alias"); mc.add("symbol");
    560          * mc.add("pattern"); }
    561          */
    562         for (int i = 0; i < list.length; ++i) {
    563             if (list[i].length() == 0)
    564                 continue;
    565             if (list[i].equals("ANY") && !name.equals("special")) {
    566                 System.err.println("WARNING- SHOULD NOT HAVE 'ANY': " + name + "\t"
    567                     + model);
    568             }
    569             if (SUBELEMENT_SKIP_LIST.contains(list[i]))
    570                 continue;
    571             // if (SHOW_PROGRESS) log.print("\t" + list[i]);
    572             if (mc.contains(list[i])) {
    573                 if (name.equals("currency") && list[i].equals("displayName") || list[i].equals("symbol")
    574                     || list[i].equals("pattern")) {
    575                     // do nothing, exception
    576                 } else if (name.equals("rules") && (list[i].equals("reset") || list[i].equals("import"))) {
    577                     // do nothing, exception
    578                 } else {
    579                     throw new IllegalArgumentException("Duplicate element in definition of  " + name
    580                         + ":\t" + list[i] + ":\t" + Arrays.asList(list) + ":\t" + mc);
    581                 }
    582             } else {
    583                 mc.add(list[i]);
    584             }
    585         }
    586         if (recordingAttributeElements) {
    587             Set<String> children = new TreeSet<String>(mc);
    588             children.remove("alias");
    589             children.remove("special");
    590             children.remove("cp");
    591             elementToChildren.putAll(name, children);
    592         }
    593         allDefinedElements.addAll(mc);
    594 
    595         if (mc.size() < 1) {
    596             if (SHOW_PROGRESS) {
    597                 log.println("\tSKIPPING\t" + name + "\t" + mc);
    598             }
    599         } else {
    600             if (SHOW_PROGRESS) {
    601                 log.println("\t" + name + "\t" + mc);
    602             }
    603             elementOrderings.add(mc);
    604         }
    605 
    606         // if (SHOW_PROGRESS) log.println();
    607     }
    608 
    609     Set<String> skipCommon = new LinkedHashSet<String>(Arrays.asList(new String[] { "validSubLocales",
    610         "standard", "references",
    611         "alt", "draft",
    612     }));
    613 
    614     Set<String> attributeSet = new TreeSet<String>();
    615     {
    616         attributeSet.add("_q");
    617         attributeSet.addAll(skipCommon);
    618     }
    619     List<String> attributeList;
    620 
    621     Map<String, Set<String>> attribEquiv = new TreeMap<String, Set<String>>();
    622 
    623     Relation<String, String> attributeToElements = Relation.of(new TreeMap<String, Set<String>>(),
    624         TreeSet.class);
    625     private XEquivalenceClass attributeEquivalents;
    626 
    627     public void attributeDecl(String eName, String aName, String type,
    628         String mode, String value) throws SAXException {
    629         if (SHOW_ALL)
    630             log.println("attributeDecl");
    631         // if (SHOW_ALL) log.println("Attribute\t" + eName + "\t" +
    632         // aName + "\t" + type + "\t" + mode + "\t" + value);
    633         if (SHOW_PROGRESS) System.out.println("Attribute\t" + eName + "\t" + aName + "\t" + type
    634             + "\t" + mode + "\t" + value);
    635         if (!skipCommon.contains(aName)) {
    636             attributeSet.add(aName);
    637             Set<String> l = attribEquiv.get(eName);
    638             if (l == null)
    639                 attribEquiv.put(eName, l = new TreeSet<String>());
    640             l.add(aName);
    641         }
    642         if (recordingAttributeElements) {
    643             attributeToElements.put(aName, eName);
    644         }
    645     }
    646 
    647     public void internalEntityDecl(String name, String value) throws SAXException {
    648         if (SHOW_ALL)
    649             log.println("internalEntityDecl");
    650         // if (SHOW_ALL) log.println("Internal Entity\t" + name +
    651         // "\t" + value);
    652     }
    653 
    654     public void externalEntityDecl(String name, String publicId, String systemId)
    655         throws SAXException {
    656         if (SHOW_ALL)
    657             log.println("externalEntityDecl");
    658         // if (SHOW_ALL) log.println("Internal Entity\t" + name +
    659         // "\t" + publicId + "\t" + systemId);
    660     }
    661 
    662     /*
    663      * (non-Javadoc)
    664      *
    665      * @see org.xml.sax.ContentHandler#endDocument()
    666      */
    667     public void endDocument() throws SAXException {
    668         if (SHOW_ALL)
    669             log.println("endDocument");
    670     }
    671 
    672     /*
    673      * (non-Javadoc)
    674      *
    675      * @see org.xml.sax.ContentHandler#startDocument()
    676      */
    677     public void startDocument() throws SAXException {
    678         if (SHOW_ALL)
    679             log.println("startDocument");
    680     }
    681 
    682     /*
    683      * (non-Javadoc)
    684      *
    685      * @see org.xml.sax.ContentHandler#characters(char[], int, int)
    686      */
    687     public void characters(char[] ch, int start, int length) throws SAXException {
    688         if (SHOW_ALL)
    689             log.println("characters");
    690     }
    691 
    692     /*
    693      * (non-Javadoc)
    694      *
    695      * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
    696      */
    697     public void ignorableWhitespace(char[] ch, int start, int length)
    698         throws SAXException {
    699         if (SHOW_ALL)
    700             log.println("ignorableWhitespace");
    701     }
    702 
    703     /*
    704      * (non-Javadoc)
    705      *
    706      * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
    707      */
    708     public void endPrefixMapping(String prefix) throws SAXException {
    709         if (SHOW_ALL)
    710             log.println("endPrefixMapping");
    711     }
    712 
    713     /*
    714      * (non-Javadoc)
    715      *
    716      * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
    717      */
    718     public void skippedEntity(String name) throws SAXException {
    719         if (SHOW_ALL)
    720             log.println("skippedEntity");
    721     }
    722 
    723     /*
    724      * (non-Javadoc)
    725      *
    726      * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
    727      */
    728     public void setDocumentLocator(Locator locator) {
    729         if (SHOW_ALL)
    730             log.println("setDocumentLocator");
    731     }
    732 
    733     /*
    734      * (non-Javadoc)
    735      *
    736      * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String,
    737      * java.lang.String)
    738      */
    739     public void processingInstruction(String target, String data)
    740         throws SAXException {
    741         if (SHOW_ALL)
    742             log.println("processingInstruction");
    743     }
    744 
    745     /*
    746      * (non-Javadoc)
    747      *
    748      * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String,
    749      * java.lang.String)
    750      */
    751     public void startPrefixMapping(String prefix, String uri) throws SAXException {
    752         if (SHOW_ALL)
    753             log.println("startPrefixMapping");
    754     }
    755 
    756     /*
    757      * (non-Javadoc)
    758      *
    759      * @see org.xml.sax.ContentHandler#endElement(java.lang.String,
    760      * java.lang.String, java.lang.String)
    761      */
    762     public void endElement(String namespaceURI, String localName, String qName)
    763         throws SAXException {
    764         if (SHOW_ALL)
    765             log.println("endElement");
    766     }
    767 
    768     /*
    769      * (non-Javadoc)
    770      *
    771      * @see org.xml.sax.ContentHandler#startElement(java.lang.String,
    772      * java.lang.String, java.lang.String, org.xml.sax.Attributes)
    773      */
    774     public void startElement(String namespaceURI, String localName, String qName,
    775         Attributes atts) throws SAXException {
    776         if (SHOW_ALL)
    777             log.println("startElement");
    778     }
    779 
    780     /*
    781      * (non-Javadoc)
    782      *
    783      * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
    784      */
    785     public void error(SAXParseException exception) throws SAXException {
    786         if (SHOW_ALL)
    787             log.println("error");
    788         throw exception;
    789     }
    790 
    791     /*
    792      * (non-Javadoc)
    793      *
    794      * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
    795      */
    796     public void fatalError(SAXParseException exception) throws SAXException {
    797         if (SHOW_ALL)
    798             log.println("fatalError");
    799         throw exception;
    800     }
    801 
    802     /*
    803      * (non-Javadoc)
    804      *
    805      * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
    806      */
    807     public void warning(SAXParseException exception) throws SAXException {
    808         if (SHOW_ALL)
    809             log.println("warning");
    810         throw exception;
    811     }
    812 
    813     public List<String> getAttributeOrder() {
    814         return attributeList;
    815     }
    816 
    817     public List<String> getElementOrder() {
    818         return orderingList;
    819     }
    820 
    821     public Set<String> getCommonAttributes() {
    822         return skipCommon;
    823     }
    824 
    825 }
    826