• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.unittest;
2 
3 import java.util.Arrays;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.LinkedHashSet;
9 import java.util.Map;
10 import java.util.Set;
11 import java.util.TreeMap;
12 import java.util.TreeSet;
13 
14 import org.unicode.cldr.util.CLDRConfig;
15 import org.unicode.cldr.util.CLDRFile;
16 import org.unicode.cldr.util.DtdType;
17 import org.unicode.cldr.util.ElementAttributeInfo;
18 import org.unicode.cldr.util.XPathParts;
19 
20 import com.ibm.icu.impl.Relation;
21 import com.ibm.icu.impl.Row;
22 import com.ibm.icu.impl.Row.R2;
23 import com.ibm.icu.impl.Row.R3;
24 import com.ibm.icu.impl.Utility;
25 
26 public class TestDTDAttributes extends TestFmwkPlus {
27 
28     static CLDRConfig testInfo = CLDRConfig.getInstance();
29 
30     /**
31      * Simple test that loads each file in the cldr directory, thus verifying
32      * that the DTD works, and also checks that the PrettyPaths work.
33      *
34      * @author markdavis
35      */
36 
main(String[] args)37     public static void main(String[] args) {
38         new TestDTDAttributes().run(args);
39     }
40 
TestOrdering()41     public void TestOrdering() { // Not deemed to be a useful test at this time
42         // - JCE
43         return;
44         // for (DtdType type : DtdType.values()) {
45         // checkOrdering(type);
46         // }
47     }
48 
checkOrdering(DtdType type)49     private void checkOrdering(DtdType type) {
50         Relation<String, String> toChildren = ElementAttributeInfo.getInstance(
51             type).getElement2Children();
52         // Relation<String, String> toParents =
53         // ElementAttributeInfo.getElement2Parents(type);
54         Set<String> containsOrdered = new LinkedHashSet<String>();
55         for (String element : toChildren.keySet()) {
56             int ordered = 0;
57             Set<String> containedElements = toChildren.getAll(element);
58             for (String contained : containedElements) {
59                 if (contained.equals("cp"))
60                     continue;
61                 int currentOrdered = CLDRFile.isOrdered(contained, null) ? 1
62                     : -1;
63                 if (currentOrdered > 0) {
64                     containsOrdered.add(element);
65                 }
66                 if (ordered == 0) {
67                     ordered = currentOrdered;
68                 } else {
69                     if (ordered != currentOrdered) {
70                         String error = type + "\tMixed ordering inside\t"
71                             + element + ":\tordered:\t";
72                         for (String contained2 : containedElements) {
73                             if (contained.equals("cp")
74                                 || !CLDRFile.isOrdered(contained2, null))
75                                 continue;
76                             error += " " + contained2;
77                         }
78                         error += ":\tunordered:\t";
79                         for (String contained2 : containedElements) {
80                             if (contained.equals("cp")
81                                 || CLDRFile.isOrdered(contained2, null))
82                                 continue;
83                             error += " " + contained2;
84                         }
85                         errln(error);
86                         break;
87                     }
88                 }
89             }
90         }
91         if (containsOrdered.size() != 0) {
92             logln("                  " + "// DTD: " + type);
93             for (String element : containsOrdered) {
94                 logln("                  " + "// <" + element + "> children");
95                 StringBuilder line = new StringBuilder("                  ");
96                 for (String contained : toChildren.getAll(element)) {
97                     line.append("\"" + contained + "\", ");
98                 }
99                 logln(line.toString());
100             }
101         }
102     }
103 
TestDistinguishing()104     public void TestDistinguishing() {
105         for (DtdType type : DtdType.values()) {
106             if (type == DtdType.ldmlICU) {
107                 continue;
108             }
109             showDistinguishing(type);
110         }
111     }
112 
showDistinguishing(DtdType dtdType)113     private void showDistinguishing(DtdType dtdType) {
114         Relation<String, String> elementToAttributes = ElementAttributeInfo
115             .getInstance(dtdType).getElement2Attributes();
116         Relation<String, String> distinguishingAttributeToElements = Relation
117             .<String, String> of(new TreeMap<String, Set<String>>(),
118                 TreeSet.class);
119         Relation<String, String> nondistinguishingAttributeToElements = Relation
120             .<String, String> of(new TreeMap<String, Set<String>>(),
121                 TreeSet.class);
122         Relation<String, String> orderedAttributeToElements = Relation
123             .<String, String> of(new TreeMap<String, Set<String>>(),
124                 TreeSet.class);
125         Map<R2<String, String>, R3<Set<String>, String, String>> attributeData = ElementAttributeInfo
126             .getInstance(dtdType).getElementAttribute2Data();
127 
128         for (String element : elementToAttributes.keySet()) {
129             boolean isOrdered = CLDRFile.isOrdered(element, dtdType);
130             Set<String> attributes = elementToAttributes.getAll(element);
131             for (String attribute : attributes) {
132                 if (isOrdered) {
133                     orderedAttributeToElements.put(attribute, element);
134                 }
135                 if (CLDRFile.isDistinguishing(dtdType, element, attribute)) {
136                     distinguishingAttributeToElements.put(attribute, element);
137                 } else {
138                     nondistinguishingAttributeToElements
139                         .put(attribute, element);
140                 }
141             }
142         }
143 
144         // distinguishing elements should be required
145         // make exception for alt
146         for (String attribute : distinguishingAttributeToElements.keySet()) {
147             if (attribute.equals("alt"))
148                 continue;
149             for (String element : distinguishingAttributeToElements
150                 .getAll(attribute)) {
151                 R3<Set<String>, String, String> attributeInfo = attributeData
152                     .get(Row.of(element, attribute));
153                 if (!"REQUIRED".equals(attributeInfo.get1())) {
154                     logln(dtdType
155                         + "\t"
156                         + element
157                         + "\t"
158                         + attribute
159                         + "\tDistinguishing attribute, but not REQUIRED in DTD");
160                 }
161             }
162         }
163 
164         Set<String> nondistinguishing = new TreeSet<String>(
165             nondistinguishingAttributeToElements.keySet());
166         nondistinguishing.removeAll(distinguishingAttributeToElements.keySet());
167         logln("// " + dtdType + "\tnondistinguishing: " + nondistinguishing);
168 
169         Set<String> distinguishing = new TreeSet<String>(
170             distinguishingAttributeToElements.keySet());
171         nondistinguishing.removeAll(nondistinguishingAttributeToElements
172             .keySet());
173         logln("// " + dtdType + "\tdistinguishing: " + distinguishing);
174 
175         Set<String> both = new TreeSet<String>(
176             distinguishingAttributeToElements.keySet());
177         both.retainAll(nondistinguishingAttributeToElements.keySet());
178         logln("// " + dtdType + "\tboth: " + both);
179 
180         for (String attribute : distinguishing) {
181             logln("{\"" + "dist" + "\", \"" + dtdType + "\", \"" + "*"
182                 + "\", \"" + attribute + "\"},");
183         }
184         for (String attribute : both) {
185             for (String element : nondistinguishingAttributeToElements
186                 .getAll(attribute)) {
187                 logln("{\"" + "nondist" + "\", \"" + dtdType + "\", \""
188                     + element + "\", \"" + attribute + "\"},");
189             }
190         }
191     }
192 
TestAttributes()193     public void TestAttributes() {
194         checkAttributes(DtdType.ldml, DtdType.supplementalData);
195         checkAttributes(DtdType.ldml, DtdType.ldmlBCP47);
196         checkAttributes(DtdType.ldmlBCP47, DtdType.supplementalData);
197     }
198 
checkAttributes(DtdType dtdType1, DtdType dtdType2)199     private void checkAttributes(DtdType dtdType1, DtdType dtdType2) {
200         Map<R2<String, String>, R3<Set<String>, String, String>> mainData = ElementAttributeInfo
201             .getInstance(dtdType1).getElementAttribute2Data();
202         Map<R2<String, String>, R3<Set<String>, String, String>> suppData = ElementAttributeInfo
203             .getInstance(dtdType2).getElementAttribute2Data();
204         Set<R2<String, String>> commonKeys = getCommon(mainData.keySet(),
205             suppData.keySet(), new TreeSet<R2<String, String>>());
206         Set<R2<String, String>> same = new TreeSet<R2<String, String>>();
207         for (R2<String, String> key : commonKeys) {
208             R3<Set<String>, String, String> mainValue = mainData.get(key);
209             R3<Set<String>, String, String> suppValue = suppData.get(key);
210             if (mainValue.equals(suppValue)) {
211                 same.add(key);
212             } else {
213                 errln("Different attribute properties across DTDs"
214                     + key.toString() + "\t" + dtdType1.toString() + ":\t"
215                     + mainValue.toString() + "\t" + dtdType2.toString()
216                     + ":\t" + suppValue.toString());
217             }
218         }
219         for (R2<String, String> key : same) {
220             logln(dtdType1 + " and " + dtdType2 + ":\t" + key + "\t"
221                 + mainData.get(key));
222         }
223         for (R2<String, String> key : mainData.keySet()) {
224             if (commonKeys.contains(key))
225                 continue;
226             logln(dtdType1 + ":\t" + key + "\t" + mainData.get(key));
227         }
228         for (R2<String, String> key : suppData.keySet()) {
229             if (commonKeys.contains(key))
230                 continue;
231             logln(dtdType2 + ":\t" + key + "\t" + suppData.get(key));
232         }
233     }
234 
235     @SuppressWarnings({ "rawtypes", "unchecked" })
getCommon(T a, T b, T result)236     private <T extends Collection> T getCommon(T a, T b, T result) {
237         result.addAll(a);
238         result.retainAll(b);
239         return result;
240     }
241 
TestElements()242     public void TestElements() { // Not deemed to be a useful test at this time
243         // - JCE
244         // checkElements(DtdType.ldml, DtdType.supplementalData);
245         // checkElements(DtdType.ldml, DtdType.ldmlBCP47);
246         // checkElements(DtdType.ldmlBCP47, DtdType.supplementalData);
247     }
248 
checkElements(DtdType dtdType1, DtdType dtdType2)249     private void checkElements(DtdType dtdType1, DtdType dtdType2) {
250         Relation<String, String> mainData = ElementAttributeInfo.getInstance(
251             dtdType1).getElement2Children();
252         Relation<String, String> suppData = ElementAttributeInfo.getInstance(
253             dtdType2).getElement2Children();
254         Set<String> commonKeys = getCommon(mainData.keySet(),
255             suppData.keySet(), new TreeSet<String>());
256         Set<String> same = new TreeSet<String>();
257         for (String key : commonKeys) {
258             Set<String> mainValues = mainData.getAll(key);
259             Set<String> suppValues = suppData.getAll(key);
260             if (mainValues.equals(suppValues)) {
261                 same.add(key);
262                 continue;
263             }
264             errln("DTD elements have different children\t" + key + "\t"
265                 + dtdType1 + ":\t" + mainValues + "\t" + dtdType2 + ":\t"
266                 + suppValues);
267         }
268         for (String key : same) {
269             logln(dtdType1 + " and " + dtdType2 + ":\t" + key + "\t"
270                 + mainData.getAll(key));
271         }
272         for (String key : mainData.keySet()) {
273             if (commonKeys.contains(key))
274                 continue;
275             logln(dtdType1 + ":\t" + key + "\t" + mainData.getAll(key));
276         }
277         for (String key : suppData.keySet()) {
278             if (commonKeys.contains(key))
279                 continue;
280             logln(dtdType2 + ":\t" + key + "\t" + suppData.getAll(key));
281         }
282     }
283 
TestEmpty()284     public void TestEmpty() { // not deemed to be a useful test at this time -
285         // JCE
286         // for (DtdType type : DtdType.values()) {
287         // checkEmpty(type);
288         // }
289     }
290 
291     static final Set<String> COLLATION_SINGLETONS = new HashSet<String>(
292         Arrays.asList(new String[] { "first_non_ignorable",
293             "first_primary_ignorable", "first_secondary_ignorable",
294             "first_tertiary_ignorable", "first_trailing",
295             "first_variable", "last_non_ignorable",
296             "last_primary_ignorable", "last_secondary_ignorable",
297             "last_tertiary_ignorable", "last_trailing last_variable",
298             "last_trailing", "last_variable" }));
299 
checkEmpty(DtdType type)300     private void checkEmpty(DtdType type) {
301         Relation<String, String> mainData = ElementAttributeInfo.getInstance(
302             type).getElement2Parents();
303         Relation<String, String> elementToAttributes = ElementAttributeInfo
304             .getInstance(type).getElement2Attributes();
305         Map<R2<String, String>, R3<Set<String>, String, String>> eaData = ElementAttributeInfo
306             .getInstance(type).getElementAttribute2Data();
307 
308         Set<String> empties = mainData.getAll("EMPTY");
309         for (String empty : empties) {
310             if (COLLATION_SINGLETONS.contains(empty))
311                 continue;
312             Set<String> attributes = elementToAttributes.getAll(empty);
313             if (attributes == null) {
314                 errln("Is EMPTY but no attributes:\t" + type + ", " + empty);
315                 continue;
316             }
317             for (String attribute : attributes) {
318                 if (attribute.equals("draft") || attribute.equals("references"))
319                     continue;
320                 logln(type + ", " + empty + ", " + attribute + ", "
321                     + eaData.get(Row.of(empty, attribute)));
322             }
323         }
324     }
325 
TestLeaf()326     public void TestLeaf() { // Not deemed to be a useful test at this time -
327         // JCE
328         // for (DtdType type : DtdType.values()) {
329         // checkLeaf(type, "PCDATA");
330         // }
331     }
332 
checkLeaf(DtdType type, String contained)333     private void checkLeaf(DtdType type, String contained) {
334         Relation<String, String> mainData = ElementAttributeInfo.getInstance(
335             type).getElement2Parents();
336         Relation<String, String> elementToAttributes = ElementAttributeInfo
337             .getInstance(type).getElement2Attributes();
338         Map<R2<String, String>, R3<Set<String>, String, String>> eaData = ElementAttributeInfo
339             .getInstance(type).getElementAttribute2Data();
340 
341         Set<String> data = mainData.getAll(contained);
342         if (data == null)
343             return;
344         for (String element : data) {
345             Set<String> attributes = elementToAttributes.getAll(element);
346             if (attributes == null) {
347                 logln(type + ", " + contained + ", " + element
348                     + ", No attributes!");
349                 continue;
350             }
351             for (String attribute : attributes) {
352                 if (attribute.equals("draft") || attribute.equals("references"))
353                     continue;
354                 logln(type + ", " + contained + ", " + element + ", "
355                     + attribute + ", "
356                     + eaData.get(Row.of(element, attribute)));
357             }
358         }
359     }
360 
TestZNodeData()361     public void TestZNodeData() { // Not deemed to be a useful test at this time
362         // - JCE
363         // for (DtdType type : DtdType.values()) {
364         // checkNodeData(type);
365         // }
366     }
367 
checkNodeData(DtdType type)368     public void checkNodeData(DtdType type) {
369         CurrentData.NodeData data = CurrentData.fullNodeData.get(type);
370         Relation<String, String> element2Parents = ElementAttributeInfo
371             .getInstance(type).getElement2Parents();
372         Relation<String, String> element2Children = ElementAttributeInfo
373             .getInstance(type).getElement2Children();
374         Relation<String, String> elementToAttributes = data.elementToAttributes;
375 
376         Relation<String, String> dtdElementToAttributes = ElementAttributeInfo
377             .getInstance(type).getElement2Attributes();
378         Map<R2<String, String>, R3<Set<String>, String, String>> attributeData = ElementAttributeInfo
379             .getInstance(type).getElementAttribute2Data();
380 
381         Set<String> possibleElements = dtdElementToAttributes.keySet();
382         Set<String> foundElements = elementToAttributes.keySet();
383         if (!foundElements.equals(possibleElements)) {
384             Set<String> missing = new TreeSet<String>(possibleElements);
385             missing.removeAll(foundElements);
386             errln(type + "\t" + "Elements defined but not in data:\t" + missing);
387         }
388 
389         // attributes not found
390         for (String element : dtdElementToAttributes.keySet()) {
391             Set<String> dtdAttributes = dtdElementToAttributes.getAll(element);
392             Set<String> actualAttributes = remove_q(elementToAttributes
393                 .getAll(element));
394             Set<String> attributesAlwaysFound = remove_q(data.elementToAttributesAlwaysFound
395                 .getAll(element));
396 
397             if (!dtdAttributes.containsAll(actualAttributes)
398                 || !dtdAttributes.containsAll(attributesAlwaysFound)) {
399                 errln(type + "\t"
400                     + "Actual attributes exceed DTD attributes:\t" + type
401                     + ", " + element + ", " + dtdAttributes + ", "
402                     + actualAttributes + ", " + attributesAlwaysFound);
403             }
404 
405             Set<String> notFound = new TreeSet<String>(dtdAttributes);
406             notFound.removeAll(actualAttributes);
407             notFound.remove("draft");
408             notFound.remove("references");
409             notFound.remove("standard");
410             notFound.remove("alt");
411             notFound.remove("validSubLocales");
412             if (notFound.size() != 0) {
413                 warnln(type + "\tAttributes not found for:\t" + element
414                     + "\tnotFound:\t" + notFound + "\tfound:\t"
415                     + actualAttributes);
416             }
417 
418             for (String attributeAlwaysFound : attributesAlwaysFound) {
419                 // make sure REQUIRED; not really an error, but for now...
420                 R3<Set<String>, String, String> attributeDatum = attributeData
421                     .get(Row.of(element, attributeAlwaysFound));
422                 if (attributeDatum == null) {
423                     errln(type + "\tData not found for " + type + ", "
424                         + element + ", " + attributeAlwaysFound);
425                     continue;
426                 }
427                 if (!"#REQUIRED".equals(attributeDatum.get1())) {
428                     if (attributeDatum.get1() == null) {
429                         warnln(type
430                             + "\tAttribute not REQUIRED but ALWAYS found, element:\t"
431                             + element + "\tattribute:\t"
432                             + attributeAlwaysFound);
433                     }
434                 }
435             }
436         }
437 
438         Set<String> empties = element2Parents.getAll("EMPTY");
439 
440         Set<String> overlap = getCommon(data.valueNodes.keySet(),
441             data.branchNodes.keySet(), new TreeSet<String>());
442         for (String s : overlap) {
443             warnln(type + "\tOverlap in value and branch!!\t" + s
444                 + "\tvalue:\t" + data.valueNodes.get(s) + "\tbranch:\t"
445                 + data.branchNodes.get(s));
446         }
447         for (String s : data.valueNodes.keySet()) {
448             if (overlap.contains(s))
449                 continue;
450             logln(type + "\tLeaf:\t" + s + "\t\t" + data.valueNodes.get(s));
451         }
452         for (String s : data.branchNodes.keySet()) {
453             if (overlap.contains(s))
454                 continue;
455             logln(type + "\tBranch:\t" + s + "\t\t" + data.branchNodes.get(s));
456         }
457 
458         overlap = getCommon(data.valueNodes.keySet(),
459             data.valuelessNodes.keySet(), new TreeSet<String>());
460         for (String s : overlap) {
461             warnln(type + "\tOverlap in value and valueless!!\t" + s
462                 + "\tvalue:\t" + data.valueNodes.get(s) + "\tvalueless:\t"
463                 + data.valuelessNodes.get(s));
464         }
465 
466         for (String s : data.valueNodes.keySet()) {
467             if (overlap.contains(s))
468                 continue;
469             logln(type + "\tValue:\t" + s + "\t\t" + data.valueNodes.get(s));
470         }
471         for (String s : data.valuelessNodes.keySet()) {
472             if (overlap.contains(s))
473                 continue;
474             logln(type + "\tValueless:\t" + s + "\t\t"
475                 + data.valuelessNodes.get(s));
476             Set<String> containing = element2Children.getAll(s);
477             if (!empties.contains(s) && containing.contains("PCDATA")) {
478                 errln(type + "\t***Should be empty in DTD but isn't:\t" + s
479                     + "\t" + containing);
480             }
481         }
482     }
483 
remove_q(Set<String> actualAttributes)484     private Set<String> remove_q(Set<String> actualAttributes) {
485         if (actualAttributes == null) {
486             actualAttributes = Collections.emptySet();
487         } else if (actualAttributes.contains("_q")) {
488             actualAttributes = new LinkedHashSet<String>(actualAttributes);
489             actualAttributes.remove("_q");
490         }
491         return actualAttributes;
492     }
493 
494     static class CurrentData {
495         static class NodeData {
496             final DtdType myType;
497             Map<String, R2<String, String>> branchNodes = new TreeMap<String, R2<String, String>>();
498             Map<String, R3<String, String, String>> valueNodes = new TreeMap<String, R3<String, String, String>>();
499             Map<String, R2<String, String>> valuelessNodes = new TreeMap<String, R2<String, String>>();
500             Relation<String, String> elementToAttributes = Relation
501                 .<String, String> of(new TreeMap<String, Set<String>>(),
502                     TreeSet.class);
503             Relation<String, String> elementToAttributesAlwaysFound = Relation
504                 .<String, String> of(new TreeMap<String, Set<String>>(),
505                     TreeSet.class);
506 
NodeData(DtdType type)507             NodeData(DtdType type) {
508                 myType = type;
509             }
510         }
511 
512         static Map<DtdType, NodeData> fullNodeData = new HashMap<DtdType, NodeData>();
513         static {
514             XPathParts parts = new XPathParts();
515             for (String locale : testInfo.getCldrFactory().getAvailable()) {
516                 CLDRFile file = testInfo.getCLDRFile(locale, false);
517                 NodeData nodeData = null;
518                 for (String xpath : file) {
519                     String value = file.getStringValue(xpath);
520                     String fullXpath = file.getFullXPath(xpath);
521                     parts.set(fullXpath);
522                     if (nodeData == null) {
523                         String root = parts.getElement(0);
524                         DtdType type = DtdType.valueOf(root);
525                         nodeData = fullNodeData.get(type);
526                         if (nodeData == null) {
fullNodeData.put(type, nodeData = new NodeData( type))527                             fullNodeData.put(type, nodeData = new NodeData(
528                                 type));
529                         }
530                     }
531                     int last = parts.size() - 1;
532                     String element = null;
533                     for (int i = 0; i <= last; ++i) {
534                         element = parts.getElement(i);
535                         Collection<String> attributes = parts
536                             .getAttributeKeys(i);
nodeData.elementToAttributes.putAll(element, attributes)537                         nodeData.elementToAttributes.putAll(element,
538                             attributes);
539                         Set<String> oldAlways = nodeData.elementToAttributesAlwaysFound
540                             .getAll(element);
541                         if (oldAlways == null) {
nodeData.elementToAttributesAlwaysFound.putAll( element, attributes)542                             nodeData.elementToAttributesAlwaysFound.putAll(
543                                 element, attributes);
544                         } else {
545                             // need retainAll, removeAll
546                             for (String old : new TreeSet<String>(oldAlways)) {
547                                 if (!attributes.contains(old)) {
548                                     nodeData.elementToAttributesAlwaysFound
remove(element, old)549                                         .remove(element, old);
550                                 }
551                             }
552                         }
553                         if (i != last) {
putIfNew(nodeData.branchNodes, element, locale, xpath)554                             putIfNew(nodeData.branchNodes, element, locale,
555                                 xpath);
556                         } else {
557                             if (value.length() > 0) {
putIfNew(nodeData.valueNodes, element, value, locale, xpath)558                                 putIfNew(nodeData.valueNodes, element,
559                                     value, locale, xpath);
560                             } else {
putIfNew(nodeData.valuelessNodes, element, locale, xpath)561                                 putIfNew(nodeData.valuelessNodes, element,
562                                     locale, xpath);
563                             }
564                         }
565                     }
566                 }
567             }
568         }
569 
putIfNew(Map<String, R2<String, String>> map, String key, String locale, String xpath)570         static void putIfNew(Map<String, R2<String, String>> map, String key,
571             String locale, String xpath) {
572             if (!map.containsKey(key)) {
573                 map.put(key, Row.of(locale, xpath));
574             }
575         }
576 
putIfNew(Map<String, R3<String, String, String>> map, String key, String value, String locale, String xpath)577         static void putIfNew(Map<String, R3<String, String, String>> map,
578             String key, String value, String locale, String xpath) {
579             if (!map.containsKey(key)) {
580                 if (value.length() > 30)
581                     value = value.substring(0, 30) + "...";
582                 value = value.replace("\n", "\\n");
583                 map.put(key, Row.of(value, locale, xpath));
584             }
585         }
586     }
587 
588     // public void TestStructure() {
589     // for (DtdType type : DtdType.values()) {
590     // logln("*= distinguished, \u2021=ordered, \u2020=default");
591     // Relation<String, String> toChildren =
592     // ElementAttributeInfo.getInstance(type).getElement2Children();
593     // Relation<String, String> toAttributes =
594     // ElementAttributeInfo.getInstance(type).getElement2Attributes();
595     // Map<R2<String, String>, R3<Set<String>, String, String>> toAttributeData
596     // = ElementAttributeInfo
597     // .getInstance(type).getElementAttribute2Data();
598     // checkStructure(type, type.toString(), 0, toChildren, toAttributes,
599     // toAttributeData);
600     // }
601     // }
602 
checkStructure( DtdType dtdType, String element, int indent, Relation<String, String> toChildren, Relation<String, String> toAttributes, Map<R2<String, String>, R3<Set<String>, String, String>> toAttributeData)603     private void checkStructure(
604         DtdType dtdType,
605         String element,
606         int indent,
607         Relation<String, String> toChildren,
608         Relation<String, String> toAttributes,
609         Map<R2<String, String>, R3<Set<String>, String, String>> toAttributeData) {
610         Set<String> myChildren = toChildren.getAll(element);
611         String values = "";
612         boolean skipChildren = false;
613         if (myChildren != null) {
614             if (myChildren.contains("PCDATA")) {
615                 values = "\tVALUE=" + myChildren.toString();
616                 skipChildren = true;
617             } else if (myChildren.contains("EMPTY")) {
618                 // values = ";\t\tVALUE=" + myChildren.toString();
619                 skipChildren = true;
620             }
621         }
622         String elementName = element;
623         if (CLDRFile.isOrdered(element, dtdType)) {
624             elementName += "\u2021";
625         }
626         logln(Utility.repeat("\t", indent)
627             + elementName
628             + checkAttributeStructure(dtdType, element,
629                 toAttributes.getAll(element), toAttributeData)
630             + values);
631         if (myChildren == null || skipChildren)
632             return;
633         for (String child : myChildren) {
634             checkStructure(dtdType, child, indent + 1, toChildren,
635                 toAttributes, toAttributeData);
636         }
637     }
638 
checkAttributeStructure( DtdType dtdType, String element, Set<String> attributes, Map<R2<String, String>, R3<Set<String>, String, String>> toAttributeData)639     private String checkAttributeStructure(
640         DtdType dtdType, String element,
641         Set<String> attributes,
642         Map<R2<String, String>, R3<Set<String>, String, String>> toAttributeData) {
643         if (attributes == null)
644             return "";
645         String result = "";
646         for (String attribute : attributes) {
647             if (attribute.equals("alt") || attribute.equals("draft")
648                 || attribute.equals("standard")
649                 || attribute.equals("references"))
650                 continue;
651             if (result.length() != 0)
652                 result += "\t";
653             R3<Set<String>, String, String> data = toAttributeData.get(Row.of(
654                 element, attribute));
655             if (CLDRFile.isDistinguishing(dtdType, element, attribute)) {
656                 attribute += "*";
657             }
658             attribute += "="
659                 + formatForAttribute(data.get0(), data.get1(), data.get2());
660             result += attribute;
661         }
662         if (result.length() == 0)
663             return result;
664         return "\t" + result;
665         // draft, standard, references, alt
666     }
667 
formatForAttribute(Set<String> type, String mode, String value)668     private String formatForAttribute(Set<String> type, String mode,
669         String value) {
670         String first = type.iterator().next();
671         String typeName = attributeTypes.contains(first) ? first : type
672             .toString();
673         if (mode == null) {
674             if (value == null) {
675                 throw new IllegalArgumentException(type + ", " + mode + ", "
676                     + value);
677             }
678             return typeName.replace(value, value + "\u2020");
679         }
680         if (mode.equals("#FIXED"))
681             return value;
682         if (value != null) {
683             throw new IllegalArgumentException(type + ", " + mode + ", "
684                 + value);
685         }
686         if (mode.equals("#REQUIRED")) {
687             return typeName;
688         }
689         if (mode.equals("#IMPLIED")) {
690             return typeName + "?";
691         }
692         throw new IllegalArgumentException(type + ", " + mode + ", " + value);
693     }
694 
695     static Set<String> attributeTypes = new HashSet<String>(
696         Arrays.asList(new String[] { "CDATA", "ID", "IDREF", "IDREFS",
697             "ENTITY", "ENTITIES", "NMTOKEN", "NMTOKENS" }));
698 
699     static Set<String> attributeMode = new HashSet<String>(
700         Arrays.asList(new String[] { "#REQUIRED", "#IMPLIED", "#FIXED" }));
701 }
702