• 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             for (String locale : testInfo.getCldrFactory().getAvailable()) {
515                 CLDRFile file = testInfo.getCLDRFile(locale, false);
516                 NodeData nodeData = null;
517                 for (String xpath : file) {
518                     String value = file.getStringValue(xpath);
519                     String fullXpath = file.getFullXPath(xpath);
520                     XPathParts parts = XPathParts.getFrozenInstance(fullXpath);
521                     if (nodeData == null) {
522                         String root = parts.getElement(0);
523                         DtdType type = DtdType.valueOf(root);
524                         nodeData = fullNodeData.get(type);
525                         if (nodeData == null) {
fullNodeData.put(type, nodeData = new NodeData( type))526                             fullNodeData.put(type, nodeData = new NodeData(
527                                 type));
528                         }
529                     }
530                     int last = parts.size() - 1;
531                     String element = null;
532                     for (int i = 0; i <= last; ++i) {
533                         element = parts.getElement(i);
534                         Collection<String> attributes = parts
535                             .getAttributeKeys(i);
nodeData.elementToAttributes.putAll(element, attributes)536                         nodeData.elementToAttributes.putAll(element,
537                             attributes);
538                         Set<String> oldAlways = nodeData.elementToAttributesAlwaysFound
539                             .getAll(element);
540                         if (oldAlways == null) {
nodeData.elementToAttributesAlwaysFound.putAll( element, attributes)541                             nodeData.elementToAttributesAlwaysFound.putAll(
542                                 element, attributes);
543                         } else {
544                             // need retainAll, removeAll
545                             for (String old : new TreeSet<String>(oldAlways)) {
546                                 if (!attributes.contains(old)) {
547                                     nodeData.elementToAttributesAlwaysFound
remove(element, old)548                                         .remove(element, old);
549                                 }
550                             }
551                         }
552                         if (i != last) {
putIfNew(nodeData.branchNodes, element, locale, xpath)553                             putIfNew(nodeData.branchNodes, element, locale,
554                                 xpath);
555                         } else {
556                             if (value.length() > 0) {
putIfNew(nodeData.valueNodes, element, value, locale, xpath)557                                 putIfNew(nodeData.valueNodes, element,
558                                     value, locale, xpath);
559                             } else {
putIfNew(nodeData.valuelessNodes, element, locale, xpath)560                                 putIfNew(nodeData.valuelessNodes, element,
561                                     locale, xpath);
562                             }
563                         }
564                     }
565                 }
566             }
567         }
568 
putIfNew(Map<String, R2<String, String>> map, String key, String locale, String xpath)569         static void putIfNew(Map<String, R2<String, String>> map, String key,
570             String locale, String xpath) {
571             if (!map.containsKey(key)) {
572                 map.put(key, Row.of(locale, xpath));
573             }
574         }
575 
putIfNew(Map<String, R3<String, String, String>> map, String key, String value, String locale, String xpath)576         static void putIfNew(Map<String, R3<String, String, String>> map,
577             String key, String value, String locale, String xpath) {
578             if (!map.containsKey(key)) {
579                 if (value.length() > 30)
580                     value = value.substring(0, 30) + "...";
581                 value = value.replace("\n", "\\n");
582                 map.put(key, Row.of(value, locale, xpath));
583             }
584         }
585     }
586 
587     // public void TestStructure() {
588     // for (DtdType type : DtdType.values()) {
589     // logln("*= distinguished, \u2021=ordered, \u2020=default");
590     // Relation<String, String> toChildren =
591     // ElementAttributeInfo.getInstance(type).getElement2Children();
592     // Relation<String, String> toAttributes =
593     // ElementAttributeInfo.getInstance(type).getElement2Attributes();
594     // Map<R2<String, String>, R3<Set<String>, String, String>> toAttributeData
595     // = ElementAttributeInfo
596     // .getInstance(type).getElementAttribute2Data();
597     // checkStructure(type, type.toString(), 0, toChildren, toAttributes,
598     // toAttributeData);
599     // }
600     // }
601 
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)602     private void checkStructure(
603         DtdType dtdType,
604         String element,
605         int indent,
606         Relation<String, String> toChildren,
607         Relation<String, String> toAttributes,
608         Map<R2<String, String>, R3<Set<String>, String, String>> toAttributeData) {
609         Set<String> myChildren = toChildren.getAll(element);
610         String values = "";
611         boolean skipChildren = false;
612         if (myChildren != null) {
613             if (myChildren.contains("PCDATA")) {
614                 values = "\tVALUE=" + myChildren.toString();
615                 skipChildren = true;
616             } else if (myChildren.contains("EMPTY")) {
617                 // values = ";\t\tVALUE=" + myChildren.toString();
618                 skipChildren = true;
619             }
620         }
621         String elementName = element;
622         if (CLDRFile.isOrdered(element, dtdType)) {
623             elementName += "\u2021";
624         }
625         logln(Utility.repeat("\t", indent)
626             + elementName
627             + checkAttributeStructure(dtdType, element,
628                 toAttributes.getAll(element), toAttributeData)
629             + values);
630         if (myChildren == null || skipChildren)
631             return;
632         for (String child : myChildren) {
633             checkStructure(dtdType, child, indent + 1, toChildren,
634                 toAttributes, toAttributeData);
635         }
636     }
637 
checkAttributeStructure( DtdType dtdType, String element, Set<String> attributes, Map<R2<String, String>, R3<Set<String>, String, String>> toAttributeData)638     private String checkAttributeStructure(
639         DtdType dtdType, String element,
640         Set<String> attributes,
641         Map<R2<String, String>, R3<Set<String>, String, String>> toAttributeData) {
642         if (attributes == null)
643             return "";
644         String result = "";
645         for (String attribute : attributes) {
646             if (attribute.equals("alt") || attribute.equals("draft")
647                 || attribute.equals("standard")
648                 || attribute.equals("references"))
649                 continue;
650             if (result.length() != 0)
651                 result += "\t";
652             R3<Set<String>, String, String> data = toAttributeData.get(Row.of(
653                 element, attribute));
654             if (CLDRFile.isDistinguishing(dtdType, element, attribute)) {
655                 attribute += "*";
656             }
657             attribute += "="
658                 + formatForAttribute(data.get0(), data.get1(), data.get2());
659             result += attribute;
660         }
661         if (result.length() == 0)
662             return result;
663         return "\t" + result;
664         // draft, standard, references, alt
665     }
666 
formatForAttribute(Set<String> type, String mode, String value)667     private String formatForAttribute(Set<String> type, String mode,
668         String value) {
669         String first = type.iterator().next();
670         String typeName = attributeTypes.contains(first) ? first : type
671             .toString();
672         if (mode == null) {
673             if (value == null) {
674                 throw new IllegalArgumentException(type + ", " + mode + ", "
675                     + value);
676             }
677             return typeName.replace(value, value + "\u2020");
678         }
679         if (mode.equals("#FIXED"))
680             return value;
681         if (value != null) {
682             throw new IllegalArgumentException(type + ", " + mode + ", "
683                 + value);
684         }
685         if (mode.equals("#REQUIRED")) {
686             return typeName;
687         }
688         if (mode.equals("#IMPLIED")) {
689             return typeName + "?";
690         }
691         throw new IllegalArgumentException(type + ", " + mode + ", " + value);
692     }
693 
694     static Set<String> attributeTypes = new HashSet<String>(
695         Arrays.asList(new String[] { "CDATA", "ID", "IDREF", "IDREFS",
696             "ENTITY", "ENTITIES", "NMTOKEN", "NMTOKENS" }));
697 
698     static Set<String> attributeMode = new HashSet<String>(
699         Arrays.asList(new String[] { "#REQUIRED", "#IMPLIED", "#FIXED" }));
700 }
701