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