1 22 23 package org.xquark.schema; 24 25 import java.util.*; 26 27 import org.xquark.schema.datatypes.PrimitiveType; 28 import org.xquark.schema.loader.Loader; 29 import org.xquark.schema.validation.*; 30 31 53 public final class ComplexType extends Type implements SchemaScope { 54 private static final String RCSRevision = "$Revision: 1.1 $"; 55 private static final String RCSName = "$Name: $"; 56 57 private boolean extension = false; 58 private boolean abs = false; 59 private int block = 0; 60 private ContentModel contentModel = null; 61 private HashMap elementDeclarations = new HashMap(); 62 private HashMap attributes = new HashMap(); 63 private ArrayList requiredAndDefaultAttributes = null; 64 private Wildcard attributeWildcard = null; 65 private AttributeDeclaration idAttr = null; 66 private AttributeDeclaration notationAttr = null; 67 68 75 public ComplexType(Schema schema, String name, Type baseType) { 76 super(schema, name, baseType); 77 } 78 79 public void accept(SchemaVisitor visitor) throws SchemaException { 80 visitor.visit(this); 81 } 82 83 89 public boolean isExtension() { 90 return extension; 91 } 92 93 99 public boolean isRestriction() { 100 return !extension; 101 } 102 103 public int getDerivationMethod() { 104 return extension ? EXTENSION : RESTRICTION; 105 } 106 107 110 111 public String checkTypeDerivationOK(Type ancestor, int exclusions, boolean useBlock) { 112 if (this == ancestor) 113 return null; 114 if ((getDerivationMethod() & exclusions) != 0) 115 return "cos-ct-derived-ok.1"; 116 Type parent = getBaseType(); 117 if (parent == null) 118 return "cos-ct-derived-ok.2.3.1"; 119 if (useBlock) 120 exclusions |= parent.getBlock(); 121 return parent.checkTypeDerivationOK(ancestor, exclusions, useBlock); 122 } 123 124 public int getBlock() { 125 return block; 126 } 127 128 public String normalizedValue(String value) { 129 switch (getContentType()) { 130 case EMPTY : 131 case ELEMENT_ONLY : 132 return null; 133 case MIXED : 134 return value; 135 case TEXT_ONLY : 136 default : 137 return getValueType().normalizedValue(value); 138 } 139 } 140 141 public StringBuffer normalizedValue(StringBuffer value) { 142 switch (getContentType()) { 143 case EMPTY : 144 case ELEMENT_ONLY : 145 return null; 146 case MIXED : 147 return value; 148 case TEXT_ONLY : 149 default : 150 return getValueType().normalizedValue(value); 151 } 152 } 153 154 public StringBuffer normalizedValue(StringBuffer value, StringBuffer out) { 155 switch (getContentType()) { 156 case EMPTY : 157 case ELEMENT_ONLY : 158 return null; 159 case MIXED : 160 if (out == null) 161 out = new StringBuffer (); 162 out.append(value.toString()); 163 return out; 164 case TEXT_ONLY : 165 default : 166 return getValueType().normalizedValue(value, out); 167 } 168 } 169 170 public String toXMLString(Object value, ValidationContextProvider context) { 171 switch (getContentType()) { 172 case EMPTY : 173 case ELEMENT_ONLY : 174 case MIXED : 175 return value.toString(); 176 case TEXT_ONLY : 177 default : 178 return getValueType().toXMLString(value, context); 179 } 180 } 181 182 public ValidationInfo validate(String value, boolean normalize, ValidationContextProvider context) 183 throws SchemaException { 184 switch (getContentType()) { 185 case EMPTY : 186 throw new SchemaException( 187 "cvc-complex-type.2.1", 188 "Empty element cannot contain characters or children"); 189 case ELEMENT_ONLY : 190 boolean bWhitespaceOnly = true; 191 for (int i = 0; i < value.length(); i++) { 192 if (!PrimitiveType.isXMLWhitespace(value.charAt(i))) 193 bWhitespaceOnly = false; 194 } 195 if (!bWhitespaceOnly) 196 throw new SchemaException( 197 "cvc-complex-type.2.3", 198 "Illegal non-whitespace characters in element-only content type"); 199 else 200 return null; 201 case MIXED : 202 return null; 203 case TEXT_ONLY : 204 default : 205 return getValueType().validate(value, normalize, context); 206 } 207 } 208 209 public ValidationInfo validate(StringBuffer value, boolean normalize, ValidationContextProvider context) 210 throws SchemaException { 211 switch (getContentType()) { 212 case EMPTY : 213 throw new SchemaException( 214 "cvc-complex-type.2.1", 215 "Empty element cannot contain characters or children"); 216 case ELEMENT_ONLY : 217 boolean bWhitespaceOnly = true; 218 for (int i = 0; i < value.length(); i++) { 219 if (!PrimitiveType.isXMLWhitespace(value.charAt(i))) 220 bWhitespaceOnly = false; 221 } 222 if (!bWhitespaceOnly) 223 throw new SchemaException( 224 "cvc-complex-type.2.3", 225 "Illegal non-whitespace characters in element-only content type"); 226 else 227 return null; 228 case MIXED : 229 return null; 230 case TEXT_ONLY : 231 default : 232 return getValueType().validate(value, normalize, context); 233 } 234 } 235 236 public Object convert(String value, boolean normalize, ValidationContextProvider context) throws SchemaException { 237 switch (getContentType()) { 238 case EMPTY : 239 throw new SchemaException( 240 "cvc-complex-type.2.1", 241 "Empty element cannot contain characters or children"); 242 case ELEMENT_ONLY : 243 boolean bWhitespaceOnly = true; 244 for (int i = 0; i < value.length(); i++) { 245 if (!PrimitiveType.isXMLWhitespace(value.charAt(i))) 246 bWhitespaceOnly = false; 247 } 248 if (bWhitespaceOnly) 249 throw new SchemaException( 250 "cvc-complex-type.2.3", 251 "Empty element cannot contain characters or children"); 252 else 253 return ""; 254 case MIXED : 255 return value; 256 case TEXT_ONLY : 257 default : 258 return getValueType().convert(value, normalize, context); 259 } 260 } 261 262 public Object convert(StringBuffer value, boolean normalize, ValidationContextProvider context) 263 throws SchemaException { 264 switch (getContentType()) { 265 case EMPTY : 266 throw new SchemaException( 267 "cvc-complex-type.2.1", 268 "Empty element cannot contain characters or children"); 269 case ELEMENT_ONLY : 270 boolean bWhitespaceOnly = true; 271 for (int i = 0; i < value.length(); i++) { 272 if (!PrimitiveType.isXMLWhitespace(value.charAt(i))) 273 bWhitespaceOnly = false; 274 } 275 if (bWhitespaceOnly) 276 throw new SchemaException( 277 "cvc-complex-type.2.3", 278 "Empty element cannot contain characters or children"); 279 else 280 return ""; 281 case MIXED : 282 return value; 283 case TEXT_ONLY : 284 default : 285 return getValueType().convert(value, normalize, context); 286 } 287 } 288 289 public String toCanonicalForm(String value, ValidationContextProvider context) throws SchemaException { 290 switch (getContentType()) { 291 case EMPTY : 292 case ELEMENT_ONLY : 293 case MIXED : 294 return value; 295 case TEXT_ONLY : 296 default : 297 return getValueType().toCanonicalForm(value, context); 298 } 299 } 300 301 public String validateDefault(String value, ValidationContextProvider context) throws SchemaException { 302 switch (getContentType()) { 303 case EMPTY : 304 case ELEMENT_ONLY : 305 throw new SchemaException("cos-valid-default.2.1", this); 306 case MIXED : 307 if (getContentModel().getModel() != null && !((Particle) getContentModel().getModel()).isEmptiable()) { 308 throw new SchemaException("cos-valid-default.2.2.2", this); 309 } 310 return value; 311 case TEXT_ONLY : 312 default : 313 try { 314 return getValueType().toCanonicalForm(value, context); 315 } catch (SchemaException ex) { 316 throw new SchemaException("cos-valid-default.2.2.1", this, ex); 317 } 318 } 319 } 320 321 328 public ContentModel getContentModel() { 329 return contentModel; 330 } 331 332 338 public boolean isAbstract() { 339 return abs; 340 } 341 342 349 public int getContentType() { 350 return contentModel.getContentType(); 351 } 352 353 public SimpleType getValueType() { 354 if (getContentType() == TEXT_ONLY) 355 return (SimpleType) contentModel.getModel(); 356 else 357 return null; 358 } 359 360 365 public Wildcard getAttributeWildcard() { 366 return attributeWildcard; 367 } 368 369 public AttributeDeclaration getIDAttribute() { 370 return idAttr; 371 } 372 373 public AttributeDeclaration getNotationAttribute() { 374 return notationAttr; 375 } 376 377 public ContentIterator childIterator() { 378 switch (getContentType()) { 379 case ELEMENT_ONLY : 380 case MIXED : 381 Particle particle = (Particle) contentModel.getModel(); 382 if (particle == null) 383 return null; 384 return ContentIteratorFactory.createIterator(particle); 385 default : 386 return null; 387 } 388 } 389 390 public ContentIterator contentIterator() { 391 switch (getContentType()) { 392 case ELEMENT_ONLY : 393 case MIXED : 394 return new ElementTreeContentIterator(this); 395 default : 396 return null; 397 } 398 } 399 400 public boolean isGlobalScope() { 401 return false; 402 } 403 404 411 public ElementDeclaration getElementDeclaration(String namespace, String name) { 412 if (namespace == null) 413 return (ElementDeclaration) elementDeclarations.get(name); 414 else 415 return (ElementDeclaration) elementDeclarations.get("{" + namespace + "}" + name); 416 } 417 418 423 public Collection getElementDeclarations() { 424 return elementDeclarations.values(); 425 } 426 427 434 public AttributeDeclaration getAttributeDeclaration(String namespace, String name) { 435 if (namespace == null) 436 return (AttributeDeclaration) attributes.get(name); 437 else 438 return (AttributeDeclaration) attributes.get("{" + namespace + "}" + name); 439 } 440 441 446 public Collection getAttributeDeclarations() { 447 return attributes.values(); 448 } 449 450 Set getAttributeEntries() { 451 return attributes.entrySet(); 452 } 453 454 public List getRequiredAndDefaultAttributes() { 455 return requiredAndDefaultAttributes; 456 } 457 458 public void setExtension(boolean extension) { 459 this.extension = extension; 460 } 461 462 public void setAbstract(boolean abs) { 463 this.abs = abs; 464 } 465 466 public void setBlock(int block) { 467 this.block = block; 468 } 469 470 public void setContentModel(ContentModel contentModel) { 471 this.contentModel = contentModel; 472 } 473 474 void setIDAttribute(AttributeDeclaration decl) { 475 idAttr = decl; 476 } 477 478 void setNotationAttribute(AttributeDeclaration decl) { 479 notationAttr = decl; 480 } 481 482 public int[] getDeclarationOccurrence(String namespace, String name) { 483 if (getContentType() == EMPTY || getContentType() == TEXT_ONLY || getContentModel().getModel() == null) 484 return null; 485 ComplexType.OccurrenceVisitor visitor = new ComplexType.OccurrenceVisitor(); 486 return visitor.getOccurrenceCount((Particle)getContentModel().getModel(), namespace, name); 487 } 488 489 public void register(SchemaComponent decl) throws SchemaException { 490 if (decl instanceof ElementDeclaration) 491 register((ElementDeclaration) decl); 492 else if (decl instanceof AttributeDeclaration) 493 register((AttributeDeclaration) decl); 494 else { 495 attributes.put(decl, decl); 498 } 499 } 500 501 private Object buildDeclarationKey(SchemaComponent comp) { 502 if (comp.getNamespace() == null) 503 return comp.getName(); 504 else 505 return "{" + comp.getNamespace() + "}" + comp.getName(); 506 } 507 508 public void register(AttributeDeclaration decl) throws SchemaException { 509 Object nsName = buildDeclarationKey(decl); 510 if (attributes.put(nsName, decl) != null) { 511 throw new SchemaException("ct-props-correct.4", decl); 513 } 514 } 515 516 public void register(ElementDeclaration decl) throws SchemaException { 517 Object nsName = buildDeclarationKey(decl); 518 ElementDeclaration prev = (ElementDeclaration) elementDeclarations.put(nsName, decl); 519 if (prev != null && decl.getType() != prev.getType()) { 523 throw new SchemaException("cos-element-consistent.2", decl); 525 } 526 List substitutionList = decl.getSubstitutionElementList(); 527 if (substitutionList != null) { 528 Iterator it = substitutionList.iterator(); 529 while (it.hasNext()) { 530 ElementDeclaration d = (ElementDeclaration) it.next(); 531 ElementDeclaration existing = getElementDeclaration(d.getNamespace(), d.getName()); 532 if (existing != null && d.getType() != existing.getType()) { 534 throw new SchemaException("cos-element-consistent.2", d); 536 } 537 } 538 } 539 } 540 541 public void setAttributeWildcard(Wildcard wildcard) { 542 attributeWildcard = wildcard; 543 } 544 545 public void setRequiredAndDefaultAttributes(ArrayList list) { 546 requiredAndDefaultAttributes = list; 547 } 548 549 public boolean isSimpleType() { 551 return false; 552 } 553 554 void checkUniqueParticleAttribution() throws SchemaException { 555 if (this.getContentType() == EMPTY) 556 return; 557 if (this.getContentModel().getModel() instanceof SimpleType) 558 return; 559 Particle p = (Particle) this.getContentModel().getModel(); 560 if (p == null) 561 return; 562 Particle overLapParticle = p.uniqueParticleAttribution(); 563 if (overLapParticle == null) 564 return; 565 throw new SchemaException("cos-nonambig", overLapParticle); 567 } 568 569 void checkDerivationValidRestriction(Loader loader) throws SchemaException { 570 Type baseType = this.getBaseType(); 571 if (this.isExtension() || baseType == null || baseType.isSimpleType()) 572 return; ComplexType base = (ComplexType) baseType; 574 575 if ((base.getFinal() & RESTRICTION) != 0) { 576 throw new SchemaException("derivation-ok-restriction.1", this); 578 } 579 580 Iterator it = this.getAttributeDeclarations().iterator(); 581 while (it.hasNext()) { 582 AttributeDeclaration decl = (AttributeDeclaration) it.next(); 583 AttributeDeclaration baseDecl = base.getAttributeDeclaration(decl.getNamespace(), decl.getName()); 584 if (baseDecl != null) { 585 if (!(baseDecl.getUse() != REQUIRED || decl.getUse() == REQUIRED)) { 586 throw new SchemaException("derivation-ok-restriction.2.1.1", decl); 588 } 589 String errCode02 = 590 decl.getType().checkTypeDerivationOK(baseDecl.getType(), baseDecl.getType().getFinal(), false); 591 if (errCode02 != null) { 592 throw new SchemaException( 594 "derivation-ok-restriction.2.1.2", 595 decl, 596 new SchemaException(errCode02, decl)); 597 } 598 if (!(baseDecl.getFixedValue() == null || baseDecl.getFixedValue().equals(decl.getFixedValue()))) { 599 throw new SchemaException("derivation-ok-restriction.2.1.3", decl); 601 } 602 } else if ( 603 base.getAttributeWildcard() == null 604 || base.getAttributeWildcard().isAllowed(decl.getNamespace()) == false) { 605 throw new SchemaException("derivation-ok-restriction.2.2", decl); 607 } 608 } 609 610 it = base.getAttributeDeclarations().iterator(); 612 while (it.hasNext()) { 613 AttributeDeclaration baseDecl = (AttributeDeclaration) it.next(); 614 if (baseDecl.getUse() == REQUIRED) { 615 AttributeDeclaration decl = this.getAttributeDeclaration(baseDecl.getNamespace(), baseDecl.getName()); 616 if (decl == null || decl.getUse() != REQUIRED) { 617 Object obj = decl; 619 if (obj == null) 620 obj = this; 621 throw new SchemaException("derivation-ok-restriction.3", obj); 622 } 623 } 624 } 625 626 Wildcard w = this.getAttributeWildcard(); 627 if (w != null) { 628 Wildcard baseW = base.getAttributeWildcard(); 629 if (baseW == null) { 630 throw new SchemaException("derivation-ok-restriction.4.1", this); 632 } else { 633 String errCode02 = w.validWildcardSubset(baseW); 634 if (errCode02 != null) { 635 throw new SchemaException("derivation-ok-restriction.4.2", this, new SchemaException(errCode02, w)); 637 } 638 } 639 } 640 641 switch (this.getContentType()) { 642 case TEXT_ONLY : 643 switch (base.getContentType()) { 644 case EMPTY : 645 case ELEMENT_ONLY : 646 throw new SchemaException("derivation-ok-restriction.5.1", this); 648 case TEXT_ONLY : 649 SimpleType st = (SimpleType) this.getContentModel().getModel(); 650 SimpleType stBase = (SimpleType) base.getContentModel().getModel(); 651 String errCode02 = st.checkTypeDerivationOK(stBase, stBase.getFinal(), false); 652 if (errCode02 != null) { 653 throw new SchemaException( 655 "derivation-ok-restriction.5.1.1", 656 this, 657 new SchemaException(errCode02, st)); 658 } 659 break; 660 case MIXED : 661 Particle p = (Particle) base.getContentModel().getModel(); 662 if (p == null || p.isEmptiable() == false) { 663 throw new SchemaException("derivation-ok-restriction.5.1.2", this); 665 } 666 break; 667 } 668 break; 669 670 case EMPTY : 671 switch (base.getContentType()) { 672 case EMPTY : 673 break; 674 case ELEMENT_ONLY : 675 case MIXED : 676 Particle p = (Particle) base.getContentModel().getModel(); 677 if (p == null || p.isEmptiable() == false) { 678 throw new SchemaException("derivation-ok-restriction.5.2.2", this); 680 } 681 break; 682 case TEXT_ONLY : 683 throw new SchemaException("derivation-ok-restriction.5.2", this); 685 } 686 break; 687 688 case ELEMENT_ONLY : 689 switch (base.getContentType()) { 690 case EMPTY : 691 case TEXT_ONLY : 692 throw new SchemaException("derivation-ok-restriction.5.3", this); 695 case ELEMENT_ONLY : 696 case MIXED : 697 Particle p = null; 698 try { 699 p = (Particle) this.getContentModel().getModel(); 700 Particle pBase = (Particle) base.getContentModel().getModel(); 701 if (p != null) 702 p.checkParticleValidRestriction(pBase); 703 } catch (SchemaException se) { 704 if (se.getInvalidObject() != null 705 && loader != null 706 && loader.getComponentLocaltor(se.getInvalidObject()) != null) 707 throw new SchemaException("derivation-ok-restriction.5.3", se.getInvalidObject(), se); 708 else 709 throw new SchemaException("derivation-ok-restriction.5.3", p, se); 710 } 711 break; 712 } 713 break; 714 715 case MIXED : 716 switch (base.getContentType()) { 717 case EMPTY : 718 case TEXT_ONLY : 719 case ELEMENT_ONLY : 720 throw new SchemaException("derivation-ok-restriction.5.3", this); 722 case MIXED : 723 Particle p = null; 724 try { 725 p = (Particle) this.getContentModel().getModel(); 726 Particle pBase = (Particle) base.getContentModel().getModel(); 727 if (p != null) 728 p.checkParticleValidRestriction(pBase); 729 } catch (SchemaException se) { 730 throw new SchemaException("derivation-ok-restriction.5.3", p, se); 731 } 732 break; 733 } 734 break; 735 } 736 } 737 738 static class OccurrenceVisitor extends DefaultSchemaVisitor { 739 private static final String RCSRevision = "$Revision: 1.1 $"; 740 private static final String RCSName = "$Name: $"; 741 private int[] occurs = null; 742 private String namespace = null; 743 private String name = null; 744 745 public int[] getOccurrenceCount(Particle particle, String namespace, String name) { 746 occurs = new int[2]; 747 occurs[0] = occurs[1] = 0; 748 this.namespace = namespace; 749 this.name = name; 750 try { 751 particle.accept(this); 752 } catch (SchemaException ex) { 753 } 755 return occurs; 756 } 757 758 private void setValues(long min, long max) { 759 if (max > Integer.MAX_VALUE) 760 max = Integer.MAX_VALUE; 761 occurs[0] = (int) min; 762 occurs[1] = (int) max; 763 } 764 765 public void visit(Particle particle) throws SchemaException { 766 ((SchemaVisitable) particle.getTerm()).accept(this); 767 long min = occurs[0] * particle.getMinOccurs(); 768 long max = occurs[1] * particle.getMaxOccurs(); 769 setValues(min, max); 770 } 771 772 public void visit(ModelGroup group) throws SchemaException { 773 long min = 0; 774 long max = 0; 775 Iterator it = group.iterator(); 776 while (it.hasNext()) { 777 occurs[0] = occurs[1] = 0; 778 ((SchemaVisitable) it.next()).accept(this); 779 min += occurs[0]; 780 max += occurs[1]; 781 } 782 setValues(min, max); 783 } 784 785 public void visit(ChoiceModelGroup group) throws SchemaException { 786 long min = Integer.MAX_VALUE; 787 long max = 0; 788 Iterator it = group.iterator(); 789 while (it.hasNext()) { 790 occurs[0] = occurs[1] = 0; 791 ((SchemaVisitable) it.next()).accept(this); 792 if (occurs[0] < min) 793 min = occurs[0]; 794 if (occurs[1] > max) 795 max = occurs[1]; 796 } 797 setValues(min, max); 798 } 799 800 public void visit(ElementDeclaration decl) throws SchemaException { 801 if (decl.hasName(namespace, name) || decl.getSubstitutionElement(namespace, name) != null) 802 occurs[0] = occurs[1] = 1; 803 } 804 805 public void visit(Wildcard wildcard) throws SchemaException { 806 if (wildcard.isAllowed(namespace)) { 807 occurs[0] = occurs[1] = 1; 808 } 809 } 810 811 } 812 813 } 814 | Popular Tags |