1 package com.thaiopensource.relaxng.parse.sax; 2 3 import com.thaiopensource.relaxng.parse.DataPatternBuilder; 4 import com.thaiopensource.relaxng.parse.Grammar; 5 import com.thaiopensource.relaxng.parse.GrammarSection; 6 import com.thaiopensource.relaxng.parse.IllegalSchemaException; 7 import com.thaiopensource.relaxng.parse.Include; 8 import com.thaiopensource.relaxng.parse.IncludedGrammar; 9 import com.thaiopensource.relaxng.parse.Location; 10 import com.thaiopensource.relaxng.parse.ParsedNameClass; 11 import com.thaiopensource.relaxng.parse.ParsedPattern; 12 import com.thaiopensource.relaxng.parse.SchemaBuilder; 13 import com.thaiopensource.relaxng.parse.Scope; 14 import com.thaiopensource.relaxng.parse.Annotations; 15 import com.thaiopensource.relaxng.parse.Context; 16 import com.thaiopensource.relaxng.parse.CommentList; 17 import com.thaiopensource.relaxng.parse.Div; 18 import com.thaiopensource.relaxng.parse.ElementAnnotationBuilder; 19 import com.thaiopensource.relaxng.parse.ParsedElementAnnotation; 20 import com.thaiopensource.relaxng.parse.ParsedPatternFuture; 21 import com.thaiopensource.util.Uri; 22 import com.thaiopensource.util.Localizer; 23 import com.thaiopensource.xml.util.Naming; 24 import com.thaiopensource.xml.util.WellKnownNamespaces; 25 import com.thaiopensource.xml.sax.XmlBaseHandler; 26 import com.thaiopensource.xml.sax.AbstractLexicalHandler; 27 import org.xml.sax.Attributes ; 28 import org.xml.sax.ContentHandler ; 29 import org.xml.sax.ErrorHandler ; 30 import org.xml.sax.Locator ; 31 import org.xml.sax.SAXException ; 32 import org.xml.sax.SAXParseException ; 33 import org.xml.sax.XMLReader ; 34 import org.xml.sax.SAXNotRecognizedException ; 35 import org.xml.sax.SAXNotSupportedException ; 36 import org.xml.sax.helpers.DefaultHandler ; 37 38 import java.util.Hashtable ; 39 import java.util.Enumeration ; 40 import java.util.Vector ; 41 import java.util.Stack ; 42 43 class SchemaParser implements ParsedPatternFuture { 44 45 private static final String relaxngURIPrefix = 46 WellKnownNamespaces.RELAX_NG.substring(0, WellKnownNamespaces.RELAX_NG.lastIndexOf('/') + 1); 47 static final String relaxng10URI = WellKnownNamespaces.RELAX_NG; 48 private static final Localizer localizer = new Localizer(SchemaParser.class); 49 50 private String relaxngURI; 51 private final XMLReader xr; 52 private final ErrorHandler eh; 53 private final SchemaBuilder schemaBuilder; 54 private ParsedPattern startPattern; 55 private Locator locator; 56 private final XmlBaseHandler xmlBaseHandler = new XmlBaseHandler(); 57 private final ContextImpl context = new ContextImpl(); 58 59 private boolean hadError = false; 60 61 private Hashtable patternTable; 62 private Hashtable nameClassTable; 63 64 static class PrefixMapping { 65 final String prefix; 66 final String uri; 67 final PrefixMapping next; 68 69 PrefixMapping(String prefix, String uri, PrefixMapping next) { 70 this.prefix = prefix; 71 this.uri = uri; 72 this.next = next; 73 } 74 } 75 76 static abstract class AbstractContext extends DtdContext implements Context { 77 PrefixMapping prefixMapping; 78 79 AbstractContext() { 80 prefixMapping = new PrefixMapping("xml", WellKnownNamespaces.XML, null); 81 } 82 83 AbstractContext(AbstractContext context) { 84 super(context); 85 prefixMapping = context.prefixMapping; 86 } 87 88 public String resolveNamespacePrefix(String prefix) { 89 for (PrefixMapping p = prefixMapping; p != null; p = p.next) 90 if (p.prefix.equals(prefix)) 91 return p.uri; 92 return null; 93 } 94 95 public Enumeration prefixes() { 96 Vector v = new Vector (); 97 for (PrefixMapping p = prefixMapping; p != null; p = p.next) { 98 if (!v.contains(p.prefix)) 99 v.addElement(p.prefix); 100 } 101 return v.elements(); 102 } 103 104 public Context copy() { 105 return new SavedContext(this); 106 } 107 } 108 109 static class SavedContext extends AbstractContext { 110 private final String baseUri; 111 SavedContext(AbstractContext context) { 112 super(context); 113 this.baseUri = context.getBaseUri(); 114 } 115 116 public String getBaseUri() { 117 return baseUri; 118 } 119 } 120 121 class ContextImpl extends AbstractContext { 122 public String getBaseUri() { 123 return xmlBaseHandler.getBaseUri(); 124 } 125 } 126 127 static interface CommentHandler { 128 void comment(String value); 129 } 130 131 abstract class Handler implements ContentHandler , CommentHandler { 132 CommentList comments; 133 134 CommentList getComments() { 135 CommentList tem = comments; 136 comments = null; 137 return tem; 138 } 139 140 public void comment(String value) { 141 if (comments == null) 142 comments = schemaBuilder.makeCommentList(); 143 comments.addComment(value, makeLocation()); 144 } 145 public void processingInstruction(String target, String date) { } 146 public void skippedEntity(String name) { } 147 public void ignorableWhitespace(char[] ch, int start, int len) { } 148 public void startDocument() { } 149 public void endDocument() { } 150 public void startPrefixMapping(String prefix, String uri) { 151 context.prefixMapping = new PrefixMapping(prefix, uri, context.prefixMapping); 152 } 153 154 public void endPrefixMapping(String prefix) { 155 context.prefixMapping = context.prefixMapping.next; 156 } 157 158 public void setDocumentLocator(Locator loc) { 159 locator = loc; 160 xmlBaseHandler.setLocator(loc); 161 } 162 } 163 164 abstract class State extends Handler { 165 State parent; 166 String nsInherit; 167 String ns; 168 String datatypeLibrary; 169 Scope scope; 170 Location startLocation; 171 Annotations annotations; 172 173 void set() { 174 xr.setContentHandler(this); 175 } 176 177 abstract State create(); 178 abstract State createChildState(String localName) throws SAXException ; 179 180 181 void setParent(State parent) { 182 this.parent = parent; 183 this.nsInherit = parent.getNs(); 184 this.datatypeLibrary = parent.datatypeLibrary; 185 this.scope = parent.scope; 186 this.startLocation = makeLocation(); 187 if (parent.comments != null) { 188 annotations = schemaBuilder.makeAnnotations(parent.comments, getContext()); 189 parent.comments = null; 190 } 191 else if (parent instanceof RootState) 192 annotations = schemaBuilder.makeAnnotations(null, getContext()); 193 } 194 195 String getNs() { 196 return ns == null ? nsInherit : ns; 197 } 198 199 boolean isRelaxNGElement(String uri) throws SAXException { 200 return uri.equals(relaxngURI); 201 } 202 203 public void startElement(String namespaceURI, 204 String localName, 205 String qName, 206 Attributes atts) throws SAXException { 207 xmlBaseHandler.startElement(); 208 if (isRelaxNGElement(namespaceURI)) { 209 State state = createChildState(localName); 210 if (state == null) { 211 xr.setContentHandler(new Skipper(this)); 212 return; 213 } 214 state.setParent(this); 215 state.set(); 216 state.attributes(atts); 217 } 218 else { 219 checkForeignElement(); 220 ForeignElementHandler feh = new ForeignElementHandler(this, getComments()); 221 feh.startElement(namespaceURI, localName, qName, atts); 222 xr.setContentHandler(feh); 223 } 224 } 225 226 public void endElement(String namespaceURI, 227 String localName, 228 String qName) throws SAXException { 229 xmlBaseHandler.endElement(); 230 parent.set(); 231 end(); 232 } 233 234 void setName(String name) throws SAXException { 235 error("illegal_name_attribute"); 236 } 237 238 void setOtherAttribute(String name, String value) throws SAXException { 239 error("illegal_attribute_ignored", name); 240 } 241 242 void endAttributes() throws SAXException { 243 } 244 245 void checkForeignElement() throws SAXException { 246 } 247 248 void attributes(Attributes atts) throws SAXException { 249 int len = atts.getLength(); 250 for (int i = 0; i < len; i++) { 251 String uri = atts.getURI(i); 252 if (uri.length() == 0) { 253 String name = atts.getLocalName(i); 254 if (name.equals("name")) 255 setName(atts.getValue(i).trim()); 256 else if (name.equals("ns")) 257 ns = atts.getValue(i); 258 else if (name.equals("datatypeLibrary")) { 259 datatypeLibrary = atts.getValue(i); 260 checkUri(datatypeLibrary); 261 if (!datatypeLibrary.equals("") 262 && !Uri.isAbsolute(datatypeLibrary)) 263 error("relative_datatype_library"); 264 if (Uri.hasFragmentId(datatypeLibrary)) 265 error("fragment_identifier_datatype_library"); 266 datatypeLibrary = Uri.escapeDisallowedChars(datatypeLibrary); 267 } 268 else 269 setOtherAttribute(name, atts.getValue(i)); 270 } 271 else if (uri.equals(relaxngURI)) 272 error("qualified_attribute", atts.getLocalName(i)); 273 else if (uri.equals(WellKnownNamespaces.XML) 274 && atts.getLocalName(i).equals("base")) 275 xmlBaseHandler.xmlBaseAttribute(atts.getValue(i)); 276 else { 277 if (annotations == null) 278 annotations = schemaBuilder.makeAnnotations(null, getContext()); 279 annotations.addAttribute(uri, atts.getLocalName(i), findPrefix(atts.getQName(i), uri), 280 atts.getValue(i), startLocation); 281 } 282 } 283 endAttributes(); 284 } 285 286 abstract void end() throws SAXException ; 287 288 void endChild(ParsedPattern pattern) { 289 } 291 292 void endChild(ParsedNameClass nc) { 293 } 295 296 public void startDocument() { } 297 public void endDocument() { 298 if (comments != null && startPattern != null) { 299 startPattern = schemaBuilder.commentAfter(startPattern, comments); 300 comments = null; 301 } 302 } 303 304 public void characters(char[] ch, int start, int len) throws SAXException { 305 for (int i = 0; i < len; i++) { 306 switch(ch[start + i]) { 307 case ' ': 308 case '\r': 309 case '\n': 310 case '\t': 311 break; 312 default: 313 error("illegal_characters_ignored"); 314 break; 315 } 316 } 317 } 318 319 boolean isPatternNamespaceURI(String s) { 320 return s.equals(relaxngURI); 321 } 322 323 void endForeignChild(ParsedElementAnnotation ea) { 324 if (annotations == null) 325 annotations = schemaBuilder.makeAnnotations(null, getContext()); 326 annotations.addElement(ea); 327 } 328 329 void mergeLeadingComments() { 330 if (comments != null) { 331 if (annotations == null) 332 annotations = schemaBuilder.makeAnnotations(comments, getContext()); 333 else 334 annotations.addLeadingComment(comments); 335 comments = null; 336 } 337 } 338 } 339 340 class ForeignElementHandler extends Handler { 341 final State nextState; 342 ElementAnnotationBuilder builder; 343 final Stack builderStack = new Stack (); 344 StringBuffer textBuf; 345 Location textLoc; 346 347 ForeignElementHandler(State nextState, CommentList comments) { 348 this.nextState = nextState; 349 this.comments = comments; 350 } 351 352 public void startElement(String namespaceURI, String localName, 353 String qName, Attributes atts) { 354 flushText(); 355 if (builder != null) 356 builderStack.push(builder); 357 Location loc = makeLocation(); 358 builder = schemaBuilder.makeElementAnnotationBuilder(namespaceURI, 359 localName, 360 findPrefix(qName, namespaceURI), 361 loc, 362 getComments(), 363 getContext()); 364 int len = atts.getLength(); 365 for (int i = 0; i < len; i++) { 366 String uri = atts.getURI(i); 367 builder.addAttribute(uri, atts.getLocalName(i), findPrefix(atts.getQName(i), uri), 368 atts.getValue(i), loc); 369 } 370 } 371 372 public void endElement(String namespaceURI, String localName, 373 String qName) { 374 flushText(); 375 if (comments != null) 376 builder.addComment(getComments()); 377 ParsedElementAnnotation ea = builder.makeElementAnnotation(); 378 if (builderStack.empty()) { 379 nextState.endForeignChild(ea); 380 nextState.set(); 381 } 382 else { 383 builder = (ElementAnnotationBuilder)builderStack.pop(); 384 builder.addElement(ea); 385 } 386 } 387 388 public void characters(char ch[], int start, int length) { 389 if (textBuf == null) 390 textBuf = new StringBuffer (); 391 textBuf.append(ch, start, length); 392 if (textLoc == null) 393 textLoc = makeLocation(); 394 } 395 396 public void comment(String value) { 397 flushText(); 398 super.comment(value); 399 } 400 401 void flushText() { 402 if (textBuf != null && textBuf.length() != 0) { 403 builder.addText(textBuf.toString(), textLoc, getComments()); 404 textBuf.setLength(0); 405 } 406 textLoc = null; 407 } 408 } 409 410 class Skipper extends DefaultHandler implements CommentHandler { 411 int level = 1; 412 final State nextState; 413 414 Skipper(State nextState) { 415 this.nextState = nextState; 416 } 417 418 public void startElement(String namespaceURI, 419 String localName, 420 String qName, 421 Attributes atts) throws SAXException { 422 ++level; 423 } 424 425 public void endElement(String namespaceURI, 426 String localName, 427 String qName) throws SAXException { 428 if (--level == 0) 429 nextState.set(); 430 } 431 432 public void comment(String value) { 433 } 434 } 435 436 abstract class EmptyContentState extends State { 437 438 State createChildState(String localName) throws SAXException { 439 error("expected_empty", localName); 440 return null; 441 } 442 443 abstract ParsedPattern makePattern() throws SAXException ; 444 445 void end() throws SAXException { 446 if (comments != null) { 447 if (annotations == null) 448 annotations = schemaBuilder.makeAnnotations(null, getContext()); 449 annotations.addComment(comments); 450 comments = null; 451 } 452 parent.endChild(makePattern()); 453 } 454 } 455 456 static private final int INIT_CHILD_ALLOC = 5; 457 458 abstract class PatternContainerState extends State { 459 ParsedPattern[] childPatterns; 460 int nChildPatterns = 0; 461 462 State createChildState(String localName) throws SAXException { 463 State state = (State)patternTable.get(localName); 464 if (state == null) { 465 error("expected_pattern", localName); 466 return null; 467 } 468 return state.create(); 469 } 470 471 ParsedPattern buildPattern(ParsedPattern[] patterns, int nPatterns, Location loc, Annotations anno) throws SAXException { 472 if (nPatterns == 1 && anno == null) 473 return patterns[0]; 474 return schemaBuilder.makeGroup(patterns, nPatterns, loc, anno); 475 } 476 477 void endChild(ParsedPattern pattern) { 478 if (childPatterns == null) 479 childPatterns = new ParsedPattern[INIT_CHILD_ALLOC]; 480 else if (nChildPatterns >= childPatterns.length) { 481 ParsedPattern[] newChildPatterns = new ParsedPattern[childPatterns.length * 2]; 482 System.arraycopy(childPatterns, 0, newChildPatterns, 0, childPatterns.length); 483 childPatterns = newChildPatterns; 484 } 485 childPatterns[nChildPatterns++] = pattern; 486 } 487 488 void endForeignChild(ParsedElementAnnotation ea) { 489 if (nChildPatterns == 0) 490 super.endForeignChild(ea); 491 else 492 childPatterns[nChildPatterns - 1] = schemaBuilder.annotateAfter(childPatterns[nChildPatterns - 1], ea); 493 } 494 495 void end() throws SAXException { 496 if (nChildPatterns == 0) { 497 error("missing_children"); 498 endChild(schemaBuilder.makeErrorPattern()); 499 } 500 if (comments != null) { 501 childPatterns[nChildPatterns - 1] = schemaBuilder.commentAfter(childPatterns[nChildPatterns - 1], comments); 502 comments = null; 503 } 504 sendPatternToParent(buildPattern(childPatterns, nChildPatterns, startLocation, annotations)); 505 } 506 507 void sendPatternToParent(ParsedPattern p) { 508 parent.endChild(p); 509 } 510 } 511 512 class GroupState extends PatternContainerState { 513 State create() { 514 return new GroupState(); 515 } 516 } 517 518 class ZeroOrMoreState extends PatternContainerState { 519 State create() { 520 return new ZeroOrMoreState(); 521 } 522 523 ParsedPattern buildPattern(ParsedPattern[] patterns, int nPatterns, Location loc, Annotations anno) throws SAXException { 524 return schemaBuilder.makeZeroOrMore(super.buildPattern(patterns, nPatterns, loc, null), loc, anno); 525 } 526 } 527 528 class OneOrMoreState extends PatternContainerState { 529 State create() { 530 return new OneOrMoreState(); 531 } 532 ParsedPattern buildPattern(ParsedPattern[] patterns, int nPatterns, Location loc, Annotations anno) throws SAXException { 533 return schemaBuilder.makeOneOrMore(super.buildPattern(patterns, nPatterns, loc, null), loc, anno); 534 } 535 } 536 537 class OptionalState extends PatternContainerState { 538 State create() { 539 return new OptionalState(); 540 } 541 ParsedPattern buildPattern(ParsedPattern[] patterns, int nPatterns, Location loc, Annotations anno) throws SAXException { 542 return schemaBuilder.makeOptional(super.buildPattern(patterns, nPatterns, loc, null), loc, anno); 543 } 544 } 545 546 class ListState extends PatternContainerState { 547 State create() { 548 return new ListState(); 549 } 550 ParsedPattern buildPattern(ParsedPattern[] patterns, int nPatterns, Location loc, Annotations anno) throws SAXException { 551 return schemaBuilder.makeList(super.buildPattern(patterns, nPatterns, loc, null), loc, anno); 552 } 553 } 554 555 class ChoiceState extends PatternContainerState { 556 State create() { 557 return new ChoiceState(); 558 } 559 ParsedPattern buildPattern(ParsedPattern[] patterns, int nPatterns, Location loc, Annotations anno) throws SAXException { 560 return schemaBuilder.makeChoice(patterns, nPatterns, loc, anno); 561 } 562 } 563 564 class InterleaveState extends PatternContainerState { 565 State create() { 566 return new InterleaveState(); 567 } 568 ParsedPattern buildPattern(ParsedPattern[] patterns, int nPatterns, Location loc, Annotations anno) { 569 return schemaBuilder.makeInterleave(patterns, nPatterns, loc, anno); 570 } 571 } 572 573 class MixedState extends PatternContainerState { 574 State create() { 575 return new MixedState(); 576 } 577 ParsedPattern buildPattern(ParsedPattern[] patterns, int nPatterns, Location loc, Annotations anno) throws SAXException { 578 return schemaBuilder.makeMixed(super.buildPattern(patterns, nPatterns, loc, null), loc, anno); 579 } 580 } 581 582 static interface NameClassRef { 583 void setNameClass(ParsedNameClass nc); 584 } 585 586 class ElementState extends PatternContainerState implements NameClassRef { 587 ParsedNameClass nameClass; 588 boolean nameClassWasAttribute; 589 String name; 590 591 void setName(String name) { 592 this.name = name; 593 } 594 595 public void setNameClass(ParsedNameClass nc) { 596 nameClass = nc; 597 } 598 599 void endAttributes() throws SAXException { 600 if (name != null) { 601 nameClass = expandName(name, getNs(), null); 602 nameClassWasAttribute = true; 603 } 604 else 605 new NameClassChildState(this, this).set(); 606 } 607 608 State create() { 609 return new ElementState(); 610 } 611 612 ParsedPattern buildPattern(ParsedPattern[] patterns, int nPatterns, Location loc, Annotations anno) throws SAXException { 613 return schemaBuilder.makeElement(nameClass, super.buildPattern(patterns, nPatterns, loc, null), loc, anno); 614 } 615 616 void endForeignChild(ParsedElementAnnotation ea) { 617 if (nameClassWasAttribute || nChildPatterns > 0 || nameClass == null) 618 super.endForeignChild(ea); 619 else 620 nameClass = schemaBuilder.annotateAfter(nameClass, ea); 621 } 622 } 623 624 class RootState extends PatternContainerState { 625 IncludedGrammar grammar; 626 627 RootState() { 628 } 629 630 RootState(IncludedGrammar grammar, Scope scope, String ns) { 631 this.grammar = grammar; 632 this.scope = scope; 633 this.nsInherit = ns; 634 this.datatypeLibrary = ""; 635 } 636 637 State create() { 638 return new RootState(); 639 } 640 641 State createChildState(String localName) throws SAXException { 642 if (grammar == null) 643 return super.createChildState(localName); 644 if (localName.equals("grammar")) 645 return new MergeGrammarState(grammar); 646 error("expected_grammar", localName); 647 return null; 648 } 649 650 void checkForeignElement() throws SAXException { 651 error("root_bad_namespace_uri", WellKnownNamespaces.RELAX_NG); 652 } 653 654 void endChild(ParsedPattern pattern) { 655 startPattern = pattern; 656 } 657 658 boolean isRelaxNGElement(String uri) throws SAXException { 659 if (!uri.startsWith(relaxngURIPrefix)) 660 return false; 661 if (!uri.equals(WellKnownNamespaces.RELAX_NG)) 662 warning("wrong_uri_version", 663 WellKnownNamespaces.RELAX_NG.substring(relaxngURIPrefix.length()), 664 uri.substring(relaxngURIPrefix.length())); 665 relaxngURI = uri; 666 return true; 667 } 668 669 } 670 671 class NotAllowedState extends EmptyContentState { 672 State create() { 673 return new NotAllowedState(); 674 } 675 676 ParsedPattern makePattern() { 677 return schemaBuilder.makeNotAllowed(startLocation, annotations); 678 } 679 } 680 681 class EmptyState extends EmptyContentState { 682 State create() { 683 return new EmptyState(); 684 } 685 686 ParsedPattern makePattern() { 687 return schemaBuilder.makeEmpty(startLocation, annotations); 688 } 689 } 690 691 class TextState extends EmptyContentState { 692 State create() { 693 return new TextState(); 694 } 695 696 ParsedPattern makePattern() { 697 return schemaBuilder.makeText(startLocation, annotations); 698 } 699 } 700 701 class ValueState extends EmptyContentState { 702 final StringBuffer buf = new StringBuffer (); 703 String type; 704 705 State create() { 706 return new ValueState(); 707 } 708 709 void setOtherAttribute(String name, String value) throws SAXException { 710 if (name.equals("type")) 711 type = checkNCName(value.trim()); 712 else 713 super.setOtherAttribute(name, value); 714 } 715 716 public void characters(char[] ch, int start, int len) { 717 buf.append(ch, start, len); 718 } 719 720 void checkForeignElement() throws SAXException { 721 error("value_contains_foreign_element"); 722 } 723 724 ParsedPattern makePattern() throws SAXException { 725 if (type == null) 726 return makePattern("", "token"); 727 else 728 return makePattern(datatypeLibrary, type); 729 } 730 731 void end() throws SAXException { 732 mergeLeadingComments(); 733 super.end(); 734 } 735 736 ParsedPattern makePattern(String datatypeLibrary, String type) { 737 return schemaBuilder.makeValue(datatypeLibrary, 738 type, 739 buf.toString(), 740 getContext(), 741 getNs(), 742 startLocation, 743 annotations); 744 } 745 746 } 747 748 class DataState extends State { 749 String type; 750 ParsedPattern except = null; 751 DataPatternBuilder dpb = null; 752 753 State create() { 754 return new DataState(); 755 } 756 757 State createChildState(String localName) throws SAXException { 758 if (localName.equals("param")) { 759 if (except != null) 760 error("param_after_except"); 761 return new ParamState(dpb); 762 } 763 if (localName.equals("except")) { 764 if (except != null) 765 error("multiple_except"); 766 return new ChoiceState(); 767 } 768 error("expected_param_except", localName); 769 return null; 770 } 771 772 void setOtherAttribute(String name, String value) throws SAXException { 773 if (name.equals("type")) 774 type = checkNCName(value.trim()); 775 else 776 super.setOtherAttribute(name, value); 777 } 778 779 void endAttributes() throws SAXException { 780 if (type == null) 781 error("missing_type_attribute"); 782 else 783 dpb = schemaBuilder.makeDataPatternBuilder(datatypeLibrary, type, startLocation); 784 } 785 786 void endForeignChild(ParsedElementAnnotation ea) { 787 dpb.annotation(ea); 788 } 789 790 void end() throws SAXException { 791 ParsedPattern p; 792 if (dpb != null) { 793 if (except != null) 794 p = dpb.makePattern(except, startLocation, annotations); 795 else 796 p = dpb.makePattern(startLocation, annotations); 797 } 798 else 799 p = schemaBuilder.makeErrorPattern(); 800 parent.endChild(p); 802 } 803 804 void endChild(ParsedPattern pattern) { 805 except = pattern; 806 } 807 808 } 809 810 class ParamState extends State { 811 private final StringBuffer buf = new StringBuffer (); 812 private final DataPatternBuilder dpb; 813 private String name; 814 815 ParamState(DataPatternBuilder dpb) { 816 this.dpb = dpb; 817 } 818 819 State create() { 820 return new ParamState(null); 821 } 822 823 void setName(String name) throws SAXException { 824 this.name = checkNCName(name); 825 } 826 827 void endAttributes() throws SAXException { 828 if (name == null) 829 error("missing_name_attribute"); 830 } 831 832 State createChildState(String localName) throws SAXException { 833 error("expected_empty", localName); 834 return null; 835 } 836 837 public void characters(char[] ch, int start, int len) { 838 buf.append(ch, start, len); 839 } 840 841 void checkForeignElement() throws SAXException { 842 error("param_contains_foreign_element"); 843 } 844 845 void end() throws SAXException { 846 if (name == null) 847 return; 848 if (dpb == null) 849 return; 850 mergeLeadingComments(); 851 dpb.addParam(name, buf.toString(), getContext(), getNs(), startLocation, annotations); 852 } 853 } 854 855 class AttributeState extends PatternContainerState implements NameClassRef { 856 ParsedNameClass nameClass; 857 boolean nameClassWasAttribute; 858 String name; 859 860 State create() { 861 return new AttributeState(); 862 } 863 864 void setName(String name) { 865 this.name = name; 866 } 867 868 public void setNameClass(ParsedNameClass nc) { 869 nameClass = nc; 870 } 871 872 void endAttributes() throws SAXException { 873 if (name != null) { 874 String nsUse; 875 if (ns != null) 876 nsUse = ns; 877 else 878 nsUse = ""; 879 nameClass = expandName(name, nsUse, null); 880 nameClassWasAttribute = true; 881 } 882 else 883 new NameClassChildState(this, this).set(); 884 } 885 886 void endForeignChild(ParsedElementAnnotation ea) { 887 if (nameClassWasAttribute || nChildPatterns > 0 || nameClass == null) 888 super.endForeignChild(ea); 889 else 890 nameClass = schemaBuilder.annotateAfter(nameClass, ea); 891 } 892 893 void end() throws SAXException { 894 if (nChildPatterns == 0) 895 endChild(schemaBuilder.makeText(startLocation, null)); 896 super.end(); 897 } 898 899 ParsedPattern buildPattern(ParsedPattern[] patterns, int nPatterns, Location loc, Annotations anno) throws SAXException { 900 return schemaBuilder.makeAttribute(nameClass, super.buildPattern(patterns, nPatterns, loc, null), loc, anno); 901 } 902 903 State createChildState(String localName) throws SAXException { 904 State tem = super.createChildState(localName); 905 if (tem != null && nChildPatterns != 0) 906 error("attribute_multi_pattern"); 907 return tem; 908 } 909 910 } 911 912 abstract class SinglePatternContainerState extends PatternContainerState { 913 State createChildState(String localName) throws SAXException { 914 if (nChildPatterns == 0) 915 return super.createChildState(localName); 916 error("too_many_children"); 917 return null; 918 } 919 } 920 921 class GrammarSectionState extends State { 922 GrammarSection section; 923 924 GrammarSectionState() { } 925 926 GrammarSectionState(GrammarSection section) { 927 this.section = section; 928 } 929 930 State create() { 931 return new GrammarSectionState(null); 932 } 933 934 State createChildState(String localName) throws SAXException { 935 if (localName.equals("define")) 936 return new DefineState(section); 937 if (localName.equals("start")) 938 return new StartState(section); 939 if (localName.equals("include")) { 940 Include include = section.makeInclude(); 941 if (include != null) 942 return new IncludeState(include); 943 } 944 if (localName.equals("div")) 945 return new DivState(section.makeDiv()); 946 error("expected_define", localName); 947 return null; 949 } 950 951 void end() throws SAXException { 952 if (comments != null) { 953 section.topLevelComment(comments); 954 comments = null; 955 } 956 } 957 958 void endForeignChild(ParsedElementAnnotation ea) { 959 section.topLevelAnnotation(ea); 960 } 961 } 962 963 class DivState extends GrammarSectionState { 964 final Div div; 965 DivState(Div div) { 966 super(div); 967 this.div = div; 968 } 969 970 void end() throws SAXException { 971 super.end(); 972 div.endDiv(startLocation, annotations); 973 } 974 } 975 976 class IncludeState extends GrammarSectionState { 977 String href; 978 final Include include; 979 980 IncludeState(Include include) { 981 super(include); 982 this.include = include; 983 } 984 985 void setOtherAttribute(String name, String value) throws SAXException { 986 if (name.equals("href")) { 987 href = value; 988 checkUri(href); 989 } 990 else 991 super.setOtherAttribute(name, value); 992 } 993 994 void endAttributes() throws SAXException { 995 if (href == null) 996 error("missing_href_attribute"); 997 else 998 href = resolve(href); 999 } 1000 1001 void end() throws SAXException { 1002 super.end(); 1003 if (href != null) { 1004 try { 1005 include.endInclude(href, getNs(), startLocation, annotations); 1006 } 1007 catch (IllegalSchemaException e) { 1008 } 1009 } 1010 } 1011 } 1012 1013 class MergeGrammarState extends GrammarSectionState { 1014 final IncludedGrammar grammar; 1015 MergeGrammarState(IncludedGrammar grammar) { 1016 super(grammar); 1017 this.grammar = grammar; 1018 } 1019 1020 void end() throws SAXException { 1021 super.end(); 1022 parent.endChild(grammar.endIncludedGrammar(startLocation, annotations)); 1023 } 1024 } 1025 1026 class GrammarState extends GrammarSectionState { 1027 Grammar grammar; 1028 1029 void setParent(State parent) { 1030 super.setParent(parent); 1031 grammar = schemaBuilder.makeGrammar(scope); 1032 section = grammar; 1033 scope = grammar; 1034 } 1035 1036 State create() { 1037 return new GrammarState(); 1038 } 1039 1040 void end() throws SAXException { 1041 super.end(); 1042 parent.endChild(grammar.endGrammar(startLocation, annotations)); 1043 } 1044 } 1045 1046 class RefState extends EmptyContentState { 1047 String name; 1048 1049 State create() { 1050 return new RefState(); 1051 } 1052 1053 void endAttributes() throws SAXException { 1054 if (name == null) 1055 error("missing_name_attribute"); 1056 } 1057 1058 void setName(String name) throws SAXException { 1059 this.name = checkNCName(name); 1060 } 1061 1062 ParsedPattern makePattern() { 1063 if (name == null) 1064 return schemaBuilder.makeErrorPattern(); 1065 return scope.makeRef(name, startLocation, annotations); 1066 } 1067 } 1068 1069 class ParentRefState extends RefState { 1070 State create() { 1071 return new ParentRefState(); 1072 } 1073 1074 ParsedPattern makePattern() { 1075 if (name == null) 1076 return schemaBuilder.makeErrorPattern(); 1077 return scope.makeParentRef(name, startLocation, annotations); 1078 } 1079 } 1080 1081 class ExternalRefState extends EmptyContentState { 1082 String href; 1083 ParsedPattern includedPattern; 1084 1085 State create() { 1086 return new ExternalRefState(); 1087 } 1088 1089 void setOtherAttribute(String name, String value) throws SAXException { 1090 if (name.equals("href")) { 1091 href = value; 1092 checkUri(href); 1093 } 1094 else 1095 super.setOtherAttribute(name, value); 1096 } 1097 1098 void endAttributes() throws SAXException { 1099 if (href == null) 1100 error("missing_href_attribute"); 1101 else 1102 href = resolve(href); 1103 } 1104 1105 ParsedPattern makePattern() { 1106 if (href != null) { 1107 try { 1108 return schemaBuilder.makeExternalRef(href, 1109 getNs(), 1110 scope, 1111 startLocation, 1112 annotations); 1113 } 1114 catch (IllegalSchemaException e) { } 1115 } 1116 return schemaBuilder.makeErrorPattern(); 1117 } 1118 } 1119 1120 abstract class DefinitionState extends PatternContainerState { 1121 GrammarSection.Combine combine = null; 1122 final GrammarSection section; 1123 1124 DefinitionState(GrammarSection section) { 1125 this.section = section; 1126 } 1127 1128 void setOtherAttribute(String name, String value) throws SAXException { 1129 if (name.equals("combine")) { 1130 value = value.trim(); 1131 if (value.equals("choice")) 1132 combine = GrammarSection.COMBINE_CHOICE; 1133 else if (value.equals("interleave")) 1134 combine = GrammarSection.COMBINE_INTERLEAVE; 1135 else 1136 error("combine_attribute_bad_value", value); 1137 } 1138 else 1139 super.setOtherAttribute(name, value); 1140 } 1141 1142 ParsedPattern buildPattern(ParsedPattern[] patterns, int nPatterns, Location loc, Annotations anno) throws SAXException { 1143 return super.buildPattern(patterns, nPatterns, loc, null); 1144 } 1145 } 1146 1147 class DefineState extends DefinitionState { 1148 String name; 1149 1150 DefineState(GrammarSection section) { 1151 super(section); 1152 } 1153 1154 State create() { 1155 return new DefineState(null); 1156 } 1157 1158 void setName(String name) throws SAXException { 1159 this.name = checkNCName(name); 1160 } 1161 1162 void endAttributes() throws SAXException { 1163 if (name == null) 1164 error("missing_name_attribute"); 1165 } 1166 1167 void sendPatternToParent(ParsedPattern p) { 1168 if (name != null) 1169 section.define(name, combine, p, startLocation, annotations); 1170 } 1171 1172 } 1173 1174 class StartState extends DefinitionState { 1175 1176 StartState(GrammarSection section) { 1177 super(section); 1178 } 1179 1180 State create() { 1181 return new StartState(null); 1182 } 1183 1184 void sendPatternToParent(ParsedPattern p) { 1185 section.define(GrammarSection.START, combine, p, startLocation, annotations); 1186 } 1187 1188 State createChildState(String localName) throws SAXException { 1189 State tem = super.createChildState(localName); 1190 if (tem != null && nChildPatterns != 0) 1191 error("start_multi_pattern"); 1192 return tem; 1193 } 1194 1195 } 1196 1197 abstract class NameClassContainerState extends State { 1198 State createChildState(String localName) throws SAXException { 1199 State state = (State)nameClassTable.get(localName); 1200 if (state == null) { 1201 error("expected_name_class", localName); 1202 return null; 1203 } 1204 return state.create(); 1205 } 1206 } 1207 1208 class NameClassChildState extends NameClassContainerState { 1209 final State prevState; 1210 final NameClassRef nameClassRef; 1211 1212 State create() { 1213 return null; 1214 } 1215 1216 NameClassChildState(State prevState, NameClassRef nameClassRef) { 1217 this.prevState = prevState; 1218 this.nameClassRef = nameClassRef; 1219 setParent(prevState.parent); 1220 this.ns = prevState.ns; 1221 } 1222 1223 void endChild(ParsedNameClass nameClass) { 1224 nameClassRef.setNameClass(nameClass); 1225 prevState.set(); 1226 } 1227 1228 void endForeignChild(ParsedElementAnnotation ea) { 1229 prevState.endForeignChild(ea); 1230 } 1231 1232 void end() throws SAXException { 1233 nameClassRef.setNameClass(schemaBuilder.makeErrorNameClass()); 1234 error("missing_name_class"); 1235 prevState.set(); 1236 prevState.end(); 1237 } 1238 } 1239 1240 abstract class NameClassBaseState extends State { 1241 1242 abstract ParsedNameClass makeNameClass() throws SAXException ; 1243 1244 void end() throws SAXException { 1245 parent.endChild(makeNameClass()); 1246 } 1247 } 1248 1249 class NameState extends NameClassBaseState { 1250 final StringBuffer buf = new StringBuffer (); 1251 1252 State createChildState(String localName) throws SAXException { 1253 error("expected_name", localName); 1254 return null; 1255 } 1256 1257 State create() { 1258 return new NameState(); 1259 } 1260 1261 public void characters(char[] ch, int start, int len) { 1262 buf.append(ch, start, len); 1263 } 1264 1265 void checkForeignElement() throws SAXException { 1266 error("name_contains_foreign_element"); 1267 } 1268 1269 ParsedNameClass makeNameClass() throws SAXException { 1270 mergeLeadingComments(); 1271 return expandName(buf.toString().trim(), getNs(), annotations); 1272 } 1273 1274 } 1275 1276 private static final int PATTERN_CONTEXT = 0; 1277 private static final int ANY_NAME_CONTEXT = 1; 1278 private static final int NS_NAME_CONTEXT = 2; 1279 1280 class AnyNameState extends NameClassBaseState { 1281 ParsedNameClass except = null; 1282 1283 State create() { 1284 return new AnyNameState(); 1285 } 1286 1287 State createChildState(String localName) throws SAXException { 1288 if (localName.equals("except")) { 1289 if (except != null) 1290 error("multiple_except"); 1291 return new NameClassChoiceState(getContext()); 1292 } 1293 error("expected_except", localName); 1294 return null; 1295 } 1296 1297 int getContext() { 1298 return ANY_NAME_CONTEXT; 1299 } 1300 1301 ParsedNameClass makeNameClass() { 1302 if (except == null) 1303 return makeNameClassNoExcept(); 1304 else 1305 return makeNameClassExcept(except); 1306 } 1307 1308 ParsedNameClass makeNameClassNoExcept() { 1309 return schemaBuilder.makeAnyName(startLocation, annotations); 1310 } 1311 1312 ParsedNameClass makeNameClassExcept(ParsedNameClass except) { 1313 return schemaBuilder.makeAnyName(except, startLocation, annotations); 1314 } 1315 1316 void endChild(ParsedNameClass nameClass) { 1317 except = nameClass; 1318 } 1319 1320 } 1321 1322 class NsNameState extends AnyNameState { 1323 State create() { 1324 return new NsNameState(); 1325 } 1326 1327 ParsedNameClass makeNameClassNoExcept() { 1328 return schemaBuilder.makeNsName(getNs(), null, null); 1329 } 1330 1331 ParsedNameClass makeNameClassExcept(ParsedNameClass except) { 1332 return schemaBuilder.makeNsName(getNs(), except, null, null); 1333 } 1334 1335 int getContext() { 1336 return NS_NAME_CONTEXT; 1337 } 1338 1339 } 1340 1341 class NameClassChoiceState extends NameClassContainerState { 1342 private ParsedNameClass[] nameClasses; 1343 private int nNameClasses; 1344 private int context; 1345 1346 NameClassChoiceState() { 1347 this.context = PATTERN_CONTEXT; 1348 } 1349 1350 NameClassChoiceState(int context) { 1351 this.context = context; 1352 } 1353 1354 void setParent(State parent) { 1355 super.setParent(parent); 1356 if (parent instanceof NameClassChoiceState) 1357 this.context = ((NameClassChoiceState)parent).context; 1358 } 1359 1360 State create() { 1361 return new NameClassChoiceState(); 1362 } 1363 1364 State createChildState(String localName) throws SAXException { 1365 if (localName.equals("anyName")) { 1366 if (context >= ANY_NAME_CONTEXT) { 1367 error(context == ANY_NAME_CONTEXT 1368 ? "any_name_except_contains_any_name" 1369 : "ns_name_except_contains_any_name"); 1370 return null; 1371 } 1372 } 1373 else if (localName.equals("nsName")) { 1374 if (context == NS_NAME_CONTEXT) { 1375 error("ns_name_except_contains_ns_name"); 1376 return null; 1377 } 1378 } 1379 return super.createChildState(localName); 1380 } 1381 1382 void endChild(ParsedNameClass nc) { 1383 if (nameClasses == null) 1384 nameClasses = new ParsedNameClass[INIT_CHILD_ALLOC]; 1385 else if (nNameClasses >= nameClasses.length) { 1386 ParsedNameClass[] newNameClasses = new ParsedNameClass[nameClasses.length * 2]; 1387 System.arraycopy(nameClasses, 0, newNameClasses, 0, nameClasses.length); 1388 nameClasses = newNameClasses; 1389 } 1390 nameClasses[nNameClasses++] = nc; 1391 } 1392 1393 void endForeignChild(ParsedElementAnnotation ea) { 1394 if (nNameClasses == 0) 1395 super.endForeignChild(ea); 1396 else 1397 nameClasses[nNameClasses - 1] = schemaBuilder.annotateAfter(nameClasses[nNameClasses - 1], ea); 1398 } 1399 1400 void end() throws SAXException { 1401 if (nNameClasses == 0) { 1402 error("missing_name_class"); 1403 parent.endChild(schemaBuilder.makeErrorNameClass()); 1404 return; 1405 } 1406 if (comments != null) { 1407 nameClasses[nNameClasses - 1] = schemaBuilder.commentAfter(nameClasses[nNameClasses - 1], comments); 1408 comments = null; 1409 } 1410 parent.endChild(schemaBuilder.makeChoice(nameClasses, nNameClasses, startLocation, annotations)); 1411 } 1412 } 1413 1414 private void initPatternTable() { 1415 patternTable = new Hashtable (); 1416 patternTable.put("zeroOrMore", new ZeroOrMoreState()); 1417 patternTable.put("oneOrMore", new OneOrMoreState()); 1418 patternTable.put("optional", new OptionalState()); 1419 patternTable.put("list", new ListState()); 1420 patternTable.put("choice", new ChoiceState()); 1421 patternTable.put("interleave", new InterleaveState()); 1422 patternTable.put("group", new GroupState()); 1423 patternTable.put("mixed", new MixedState()); 1424 patternTable.put("element", new ElementState()); 1425 patternTable.put("attribute", new AttributeState()); 1426 patternTable.put("empty", new EmptyState()); 1427 patternTable.put("text", new TextState()); 1428 patternTable.put("value", new ValueState()); 1429 patternTable.put("data", new DataState()); 1430 patternTable.put("notAllowed", new NotAllowedState()); 1431 patternTable.put("grammar", new GrammarState()); 1432 patternTable.put("ref", new RefState()); 1433 patternTable.put("parentRef", new ParentRefState()); 1434 patternTable.put("externalRef", new ExternalRefState()); 1435 } 1436 1437 private void initNameClassTable() { 1438 nameClassTable = new Hashtable (); 1439 nameClassTable.put("name", new NameState()); 1440 nameClassTable.put("anyName", new AnyNameState()); 1441 nameClassTable.put("nsName", new NsNameState()); 1442 nameClassTable.put("choice", new NameClassChoiceState()); 1443 } 1444 1445 public ParsedPattern getParsedPattern() throws IllegalSchemaException { 1446 if (hadError) 1447 throw new IllegalSchemaException(); 1448 return startPattern; 1449 } 1450 1451 private void error(String key) throws SAXException { 1452 error(key, locator); 1453 } 1454 1455 private void error(String key, String arg) throws SAXException { 1456 error(key, arg, locator); 1457 } 1458 1459 void error(String key, String arg1, String arg2) throws SAXException { 1460 error(key, arg1, arg2, locator); 1461 } 1462 1463 private void error(String key, Locator loc) throws SAXException { 1464 error(new SAXParseException (localizer.message(key), loc)); 1465 } 1466 1467 private void error(String key, String arg, Locator loc) throws SAXException { 1468 error(new SAXParseException (localizer.message(key, arg), loc)); 1469 } 1470 1471 private void error(String key, String arg1, String arg2, Locator loc) 1472 throws SAXException { 1473 error(new SAXParseException (localizer.message(key, arg1, arg2), loc)); 1474 } 1475 1476 private void error(SAXParseException e) throws SAXException { 1477 hadError = true; 1478 if (eh != null) 1479 eh.error(e); 1480 } 1481 1482 void warning(String key) throws SAXException { 1483 warning(key, locator); 1484 } 1485 1486 private void warning(String key, String arg) throws SAXException { 1487 warning(key, arg, locator); 1488 } 1489 1490 private void warning(String key, String arg1, String arg2) throws SAXException { 1491 warning(key, arg1, arg2, locator); 1492 } 1493 1494 private void warning(String key, Locator loc) throws SAXException { 1495 warning(new SAXParseException (localizer.message(key), loc)); 1496 } 1497 1498 private void warning(String key, String arg, Locator loc) throws SAXException { 1499 warning(new SAXParseException (localizer.message(key, arg), loc)); 1500 } 1501 1502 private void warning(String key, String arg1, String arg2, Locator loc) 1503 throws SAXException { 1504 warning(new SAXParseException (localizer.message(key, arg1, arg2), loc)); 1505 } 1506 1507 private void warning(SAXParseException e) throws SAXException { 1508 if (eh != null) 1509 eh.warning(e); 1510 } 1511 1512 SchemaParser(XMLReader xr, 1513 ErrorHandler eh, 1514 SchemaBuilder schemaBuilder, 1515 IncludedGrammar grammar, 1516 Scope scope) throws SAXException { 1517 this.xr = xr; 1518 this.eh = eh; 1519 this.schemaBuilder = schemaBuilder; 1520 if (eh != null) 1521 xr.setErrorHandler(eh); 1522 xr.setDTDHandler(context); 1523 if (schemaBuilder.usesComments()) { 1524 try { 1525 xr.setProperty("http://xml.org/sax/properties/lexical-handler", new LexicalHandlerImpl()); 1526 } 1527 catch (SAXNotRecognizedException e) { 1528 warning("no_comment_support", xr.getClass().getName()); 1529 } 1530 catch (SAXNotSupportedException e) { 1531 warning("no_comment_support", xr.getClass().getName()); 1532 } 1533 } 1534 initPatternTable(); 1535 initNameClassTable(); 1536 new RootState(grammar, scope, SchemaBuilder.INHERIT_NS).set(); 1537 } 1538 1539 1540 private Context getContext() { 1541 return context; 1542 } 1543 1544 class LexicalHandlerImpl extends AbstractLexicalHandler { 1545 private boolean inDtd = false; 1546 1547 public void startDTD(String s, String s1, String s2) throws SAXException { 1548 inDtd = true; 1549 } 1550 1551 public void endDTD() throws SAXException { 1552 inDtd = false; 1553 } 1554 1555 public void comment(char[] chars, int start, int length) throws SAXException { 1556 if (!inDtd) 1557 ((CommentHandler)xr.getContentHandler()).comment(new String (chars, start, length)); 1558 } 1559 } 1560 1561 private ParsedNameClass expandName(String name, String ns, Annotations anno) throws SAXException { 1562 int ic = name.indexOf(':'); 1563 if (ic == -1) 1564 return schemaBuilder.makeName(ns, checkNCName(name), null, null, anno); 1565 String prefix = checkNCName(name.substring(0, ic)); 1566 String localName = checkNCName(name.substring(ic + 1)); 1567 for (PrefixMapping tem = context.prefixMapping; tem != null; tem = tem.next) 1568 if (tem.prefix.equals(prefix)) 1569 return schemaBuilder.makeName(tem.uri, localName, prefix, null, anno); 1570 error("undefined_prefix", prefix); 1571 return schemaBuilder.makeName("", localName, null, null, anno); 1572 } 1573 1574 private String findPrefix(String qName, String uri) { 1575 String prefix = null; 1576 if (qName == null || qName.equals("")) { 1577 for (PrefixMapping p = context.prefixMapping; p != null; p = p.next) 1578 if (p.uri.equals(uri)) { 1579 prefix = p.prefix; 1580 break; 1581 } 1582 } 1583 else { 1584 int off = qName.indexOf(':'); 1585 if (off > 0) 1586 prefix = qName.substring(0, off); 1587 } 1588 return prefix; 1589 } 1590 private String checkNCName(String str) throws SAXException { 1591 if (!Naming.isNcname(str)) 1592 error("invalid_ncname", str); 1593 return str; 1594 } 1595 1596 private String resolve(String systemId) throws SAXException { 1597 if (Uri.hasFragmentId(systemId)) 1598 error("href_fragment_id"); 1599 systemId = Uri.escapeDisallowedChars(systemId); 1600 return Uri.resolve(xmlBaseHandler.getBaseUri(), systemId); 1601 } 1602 1603 private Location makeLocation() { 1604 if (locator == null) 1605 return null; 1606 return schemaBuilder.makeLocation(locator.getSystemId(), 1607 locator.getLineNumber(), 1608 locator.getColumnNumber()); 1609 } 1610 1611 private void checkUri(String s) throws SAXException { 1612 if (!Uri.isValid(s)) 1613 error("invalid_uri", s); 1614 } 1615} 1616 | Popular Tags |