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