1 package net.sf.saxon.query; 2 3 import net.sf.saxon.Configuration; 4 import net.sf.saxon.Err; 5 import net.sf.saxon.StandardURIResolver; 6 import net.sf.saxon.event.PipelineConfiguration; 7 import net.sf.saxon.expr.*; 8 import net.sf.saxon.functions.*; 9 import net.sf.saxon.instruct.*; 10 import net.sf.saxon.om.*; 11 import net.sf.saxon.pattern.NodeTest; 12 import net.sf.saxon.sort.FixedSortKeyDefinition; 13 import net.sf.saxon.sort.TupleExpression; 14 import net.sf.saxon.sort.TupleSorter; 15 import net.sf.saxon.style.AttributeValueTemplate; 16 import net.sf.saxon.style.StandardNames; 17 import net.sf.saxon.trace.Location; 18 import net.sf.saxon.trans.IndependentContext; 19 import net.sf.saxon.trans.StaticError; 20 import net.sf.saxon.trans.XPathException; 21 import net.sf.saxon.trans.DynamicError; 22 import net.sf.saxon.type.ItemType; 23 import net.sf.saxon.type.Type; 24 import net.sf.saxon.value.*; 25 26 import javax.xml.transform.OutputKeys ; 27 import javax.xml.transform.TransformerConfigurationException ; 28 import javax.xml.transform.TransformerException ; 29 import javax.xml.transform.stream.StreamSource ; 30 import java.util.*; 31 import java.net.URISyntaxException ; 32 33 37 class QueryParser extends ExpressionParser { 38 39 private boolean preserveSpace = false; 40 private boolean defaultEmptyLeast = true; 41 42 private int errorCount = 0; 43 44 protected Executable executable; 45 46 private boolean foundCopyNamespaces = false; 47 private boolean foundBoundarySpaceDeclaration = false; 48 private boolean foundOrderingDeclaration = false; 49 private boolean foundEmptyOrderingDeclaration = false; 50 private boolean foundDefaultCollation = false; 51 private boolean foundConstructionDeclaration = false; 52 private boolean foundDefaultFunctionNamespace = false; 53 private boolean foundDefaultElementNamespace = false; 54 private boolean foundBaseURIDeclaration = false; 55 56 public Set importedModules = new HashSet(5); 57 58 private Expression defaultValue = null; 59 60 63 64 protected QueryParser() {}; 65 66 69 70 public XQueryExpression makeXQueryExpression(String query, 71 StaticQueryContext staticContext, 72 Configuration config) throws XPathException { 73 try { 74 query = normalizeLineEndings(query); 75 Executable exec = new Executable(); 76 77 Properties outputProps = new Properties(); 78 outputProps.setProperty(OutputKeys.METHOD, "xml"); 79 outputProps.setProperty(OutputKeys.INDENT, "yes"); 80 exec.setDefaultOutputProperties(outputProps); 81 82 exec.setLocationMap(new LocationMap()); 83 exec.setConfiguration(config); 84 exec.setFunctionLibrary(new ExecutableFunctionLibrary(config)); 85 exec.setHostLanguage(Configuration.XQUERY); 87 setExecutable(exec); 88 staticContext.setExecutable(exec); 89 Expression exp = parseQuery(query, 0, Token.EOF, staticContext); 90 if (exp instanceof ComputedExpression) { 91 int loc = env.getLocationMap().allocateLocationId(env.getSystemId(), 1); 92 ((ComputedExpression)exp).setParentExpression(new TemporaryContainer(staticContext.getLocationMap(), loc)); 93 } 94 exec.fixupQueryModules(staticContext); 95 XQueryExpression queryExp = new XQueryExpression(exp, exec, staticContext, config); 96 exp = queryExp.getExpression(); 97 DocumentInstr docInstruction; 98 if (exp instanceof DocumentInstr) { 99 docInstruction = (DocumentInstr) exp; 100 } else { 101 docInstruction = new DocumentInstr(false, null, staticContext.getSystemId()); 102 docInstruction.setContentExpression(exp); 103 setLocation(docInstruction, 1); 104 } 106 queryExp.setDocumentInstruction(docInstruction); 107 108 111 FunctionLibrary userlib = exec.getFunctionLibrary(); 112 FunctionLibraryList lib = new FunctionLibraryList(); 113 lib.addFunctionLibrary(new SystemFunctionLibrary(SystemFunctionLibrary.XPATH_ONLY)); 114 lib.addFunctionLibrary(config.getVendorFunctionLibrary()); 115 lib.addFunctionLibrary(new ConstructorFunctionLibrary(config)); 116 if (config.isAllowExternalFunctions()) { 117 lib.addFunctionLibrary(config.getExtensionBinder()); 118 } 119 lib.addFunctionLibrary(userlib); 120 exec.setFunctionLibrary(lib); 121 122 return queryExp; 123 } catch (XPathException e) { 124 if (!e.hasBeenReported()) { 125 e = StaticError.makeStaticError(e); 126 reportError((StaticError)e); 127 } 128 throw e; 129 } 130 } 131 132 135 136 private static String normalizeLineEndings(String in) { 137 if (in.indexOf((char)0xa) < 0 && in.indexOf((char)0x85) < 0 && in.indexOf((char)0x2028) < 0) { 138 return in; 139 } 140 FastStringBuffer sb = new FastStringBuffer(in.length()); 141 for (int i=0; i<in.length(); i++) { 142 char ch = in.charAt(i); 143 switch (ch) { 144 case 0x85: 145 case 0x2028: 146 sb.append((char)0xa); 147 break; 148 case 0xd: 149 if (i<in.length()-1 && (in.charAt(i+1)==(char)0xa || in.charAt(i+1)==(char)0x85)) { 150 sb.append((char)0xa); 151 i++; 152 } else { 153 sb.append((char)0xa); 154 } 155 break; 156 default: 157 sb.append(ch); 158 } 159 } 160 return sb.toString(); 161 } 162 163 166 167 public Executable getExecutable() { 168 return executable; 169 } 170 171 174 175 public void setExecutable(Executable exec) { 176 executable = exec; 177 } 178 179 180 190 191 private Expression parseQuery(String queryString, 192 int start, 193 int terminator, 194 StaticQueryContext env) throws XPathException { 195 this.env = env; 196 this.language = XQUERY; 197 t = new Tokenizer(); 198 try { 199 t.tokenize(queryString, start, -1, 1); 200 } catch (StaticError err) { 201 grumble(err.getMessage()); 202 } 203 parseVersionDeclaration(); 204 parseProlog(); 205 Expression exp = parseExpression(); 206 if (t.currentToken != terminator) { 207 grumble("Unexpected token " + currentTokenDisplay() + " beyond end of query"); 208 } 209 setLocation(exp); 210 if (errorCount == 0) { 211 } 228 if (errorCount == 0) { 229 return exp; 230 } else { 231 StaticError err = new StaticError("One or more static errors were reported during query analysis"); 232 err.setHasBeenReported(); 233 throw err; 234 } 235 } 236 237 247 248 public final void parseLibraryModule(String queryString, StaticQueryContext env) 249 throws StaticError { 250 this.env = env; 251 this.executable = env.getExecutable(); 252 t = new Tokenizer(); 253 try { 254 t.tokenize(queryString, 0, -1, 1); 255 } catch (StaticError err) { 256 grumble(err.getMessage()); 257 } 258 parseVersionDeclaration(); 259 parseModuleDeclaration(); 260 parseProlog(); 261 if (t.currentToken != Token.EOF) { 262 grumble("Unrecognized content found after the variable and function declarations in a library module"); 263 } 264 if (errorCount != 0) { 274 throw new StaticError("Static errors were reported in the imported library module"); 275 } 276 } 277 278 285 286 protected void grumble(String message, String errorCode) throws StaticError { 287 String s = t.recentText(); 288 ExpressionLocation loc = makeLocator(); 289 String prefix = getLanguage() + 290 ("XPST0003".equals(errorCode) ? " syntax error " : " static error ") + 291 (message.startsWith("...") ? "near" : "in") + 292 " #" + s + "#:\n "; 293 StaticError exception = new StaticError(prefix + message); 294 exception.setErrorCode(errorCode); 295 exception.setLocator(loc); 296 reportError(exception); 297 } 298 299 private void reportError(StaticError exception) throws StaticError { 300 errorCount++; 301 try { 302 env.getConfiguration().getErrorListener().fatalError(exception); 303 } catch (TransformerException err) { 304 if (err instanceof StaticError) { 305 throw (StaticError) err; 306 } else { 307 throw new StaticError(err); 308 } 309 } 310 throw exception; 311 } 312 313 317 private ExpressionLocation makeLocator() { 318 int line = t.getLineNumber(); 319 int column = t.getColumnNumber(); 320 321 ExpressionLocation loc = new ExpressionLocation(); 322 loc.setSystemId(env.getSystemId()); 323 loc.setLineNumber(line); 324 loc.setColumnNumber(column); 325 return loc; 326 } 327 328 332 private void parseVersionDeclaration() throws StaticError { 333 if (t.currentToken == Token.XQUERY_VERSION) { 334 nextToken(); 335 expect(Token.STRING_LITERAL); 336 if (!("1.0".equals(t.currentTokenValue))) { 337 grumble("XQuery version must be 1.0", "XQST0031"); 338 } 339 nextToken(); 340 if ("encoding".equals(t.currentTokenValue)) { 341 nextToken(); 342 expect(Token.STRING_LITERAL); 343 nextToken(); 345 } 346 expect(Token.SEMICOLON); 347 nextToken(); 348 } 349 } 350 351 356 357 private void parseModuleDeclaration() throws StaticError { 358 expect(Token.MODULE_NAMESPACE); 359 nextToken(); 360 expect(Token.NAME); 361 String prefix = t.currentTokenValue; 362 checkProhibitedPrefixes(prefix); 363 nextToken(); 364 expect(Token.EQUALS); 365 nextToken(); 366 expect(Token.STRING_LITERAL); 367 String uri = t.currentTokenValue; 368 nextToken(); 369 expect(Token.SEMICOLON); 370 nextToken(); 371 try { 372 ((StaticQueryContext) env).declarePassiveNamespace(prefix, uri, true); 373 } catch (StaticError err) { 374 err.setLocator(makeLocator()); 375 reportError(err); 376 } 377 ((StaticQueryContext) env).setModuleNamespace(uri); 378 } 379 380 387 388 private void parseProlog() throws StaticError { 389 boolean allowSetters = true; 390 boolean allowModuleDecl = true; 391 boolean allowDeclarations = true; 392 while (true) { 393 try { 394 if (t.currentToken == Token.MODULE_NAMESPACE) { 395 String uri = ((StaticQueryContext) env).getModuleNamespace(); 396 if (uri == null) { 397 grumble("Module declaration must not be used in a main module"); 398 } else { 399 grumble("Module declaration appears more than once"); 400 } 401 if (!allowModuleDecl) { 402 grumble("Module declaration must precede other declarations in the query prolog"); 403 } 404 } 405 allowModuleDecl = false; 406 if (t.currentToken == Token.DECLARE_NAMESPACE) { 407 if (!allowDeclarations) { 408 grumble("Namespace declarations cannot follow variables, functions, or options"); 409 } 410 allowSetters = false; 411 parseNamespaceDeclaration(); 412 } else if (t.currentToken == Token.DECLARE_DEFAULT) { 413 nextToken(); 414 expect(Token.NAME); 415 if (t.currentTokenValue == "element") { 416 if (!allowDeclarations) { 417 grumble("Namespace declarations cannot follow variables, functions, or options"); 418 } 419 allowSetters = false; 420 parseDefaultElementNamespace(); 421 } else if (t.currentTokenValue == "function") { 422 if (!allowDeclarations) { 423 grumble("Namespace declarations cannot follow variables, functions, or options"); 424 } 425 allowSetters = false; 426 parseDefaultFunctionNamespace(); 427 } else if (t.currentTokenValue == "collation") { 428 if (!allowDeclarations) { 429 grumble("Collation declarations must appear earlier in the prolog"); 430 } 431 parseDefaultCollation(); 432 } else if (t.currentTokenValue == "order") { 433 if (!allowDeclarations) { 434 grumble("Order declarations must appear earlier in the prolog"); 435 } 436 parseDefaultOrder(); 437 } else { 438 grumble("After 'declare default', expected 'element', 'function', or 'collation'"); 439 } 440 } else if (t.currentToken == Token.DECLARE_BOUNDARY_SPACE) { 441 if (!allowSetters) { 442 grumble("'declare boundary-space' must appear earlier in the query prolog"); 443 } 444 parseBoundarySpaceDeclaration(); 445 } else if (t.currentToken == Token.DECLARE_ORDERING) { 446 if (!allowSetters) { 447 grumble("'declare ordering' must appear earlier in the query prolog"); 448 } 449 parseOrderingDeclaration(); 450 } else if (t.currentToken == Token.DECLARE_COPY_NAMESPACES) { 451 if (!allowSetters) { 452 grumble("'declare copy-namespaces' must appear earlier in the query prolog"); 453 } 454 parseCopyNamespacesDeclaration(); 455 } else if (t.currentToken == Token.DECLARE_BASEURI) { 456 if (!allowSetters) { 457 grumble("'declare base-uri' must appear earlier in the query prolog"); 458 } 459 parseBaseURIDeclaration(); 460 } else if (t.currentToken == Token.IMPORT_SCHEMA) { 461 allowSetters = false; 462 if (!allowDeclarations) { 463 grumble("Import schema must appear earlier in the prolog"); 464 } 465 parseSchemaImport(); 466 } else if (t.currentToken == Token.IMPORT_MODULE) { 467 allowSetters = false; 468 if (!allowDeclarations) { 469 grumble("Import module must appear earlier in the prolog"); 470 } 471 parseModuleImport(); 472 } else if (t.currentToken == Token.DECLARE_VARIABLE) { 473 allowSetters = false; 474 allowDeclarations = false; 475 parseVariableDeclaration(); 476 } else if (t.currentToken == Token.DECLARE_FUNCTION) { 477 allowSetters = false; 478 allowDeclarations = false; 479 parseFunctionDeclaration(); 480 } else if (t.currentToken == Token.DECLARE_OPTION) { 481 allowSetters = false; 482 allowDeclarations = false; 483 parseOptionDeclaration(); 484 } else if (t.currentToken == Token.DECLARE_CONSTRUCTION) { 485 if (!allowSetters) { 486 grumble("'declare construction' must appear earlier in the query prolog"); 487 } 488 parseConstructionDeclaration(); 489 } else { 490 break; 491 } 492 expect(Token.SEMICOLON); 493 nextToken(); 494 } catch (StaticError err) { 495 if (err.getLocator() == null) { 496 err.setLocator(makeLocator()); 497 } 498 if (!err.hasBeenReported()) { 499 errorCount++; 500 try { 501 env.getConfiguration().getErrorListener().fatalError(err); 502 } catch (TransformerException err2) { 503 if (err2 instanceof StaticError) { 504 throw (StaticError) err2; 505 } else { 506 throw new StaticError(err); 507 } 508 } 509 } 510 while (t.currentToken != Token.SEMICOLON) { 513 nextToken(); 514 if (t.currentToken == Token.EOF) { 515 return; 516 } else if (t.currentToken == Token.RCURLY) { 517 t.lookAhead(); 518 } else if (t.currentToken == Token.TAG) { 519 parsePseudoXML(true); 520 } 521 } 522 nextToken(); 523 } 524 } 525 } 526 527 private void parseDefaultCollation() throws StaticError { 528 if (foundDefaultCollation) { 530 grumble("default collation appears more than once", "XQST0038"); 531 } 532 foundDefaultCollation = true; 533 nextToken(); 534 expect(Token.STRING_LITERAL); 535 String uri = t.currentTokenValue; 536 try { 537 ((StaticQueryContext) env).declareDefaultCollation(uri); 538 } catch (XPathException err) { 539 grumble(err.getMessage()); 540 } 541 nextToken(); 542 } 543 544 547 private void parseDefaultOrder() throws StaticError { 548 if (foundEmptyOrderingDeclaration) { 549 grumble("empty ordering declaration appears more than once", "XQST0069"); 550 } 551 foundEmptyOrderingDeclaration = true; 552 nextToken(); 553 if (!isKeyword("empty")) { 554 grumble("After 'declare default order', expected keyword 'empty'"); 555 } 556 nextToken(); 557 if (isKeyword("least")) { 558 defaultEmptyLeast = true; 559 } else if (isKeyword("greatest")) { 560 defaultEmptyLeast = false; 561 } else { 562 grumble("After 'declare default order empty', expected keyword 'least' or 'greatest'"); 563 } 564 nextToken(); 565 } 566 567 572 573 private void parseBoundarySpaceDeclaration() throws StaticError { 574 if (foundBoundarySpaceDeclaration) { 575 grumble("'declare boundary-space' appears more than once", "XQST0068"); 576 } 577 foundBoundarySpaceDeclaration = true; 578 nextToken(); 579 expect(Token.NAME); 580 if ("preserve".equals(t.currentTokenValue)) { 581 preserveSpace = true; 582 } else if ("strip".equals(t.currentTokenValue)) { 583 preserveSpace = false; 584 } else { 585 grumble("boundary-space must be 'preserve' or 'strip'"); 586 } 587 nextToken(); 588 } 589 590 595 596 private void parseOrderingDeclaration() throws StaticError { 597 if (foundOrderingDeclaration) { 598 grumble("ordering mode declaration appears more than once", "XQST0065"); 599 } 600 foundOrderingDeclaration = true; 601 nextToken(); 602 expect(Token.NAME); 603 if ("ordered".equals(t.currentTokenValue)) { 604 } else if ("unordered".equals(t.currentTokenValue)) { 606 } else { 608 grumble("ordering mode must be 'ordered' or 'unordered'"); 609 } 610 nextToken(); 611 } 612 613 618 619 private void parseCopyNamespacesDeclaration() throws StaticError { 620 if (foundCopyNamespaces) { 621 grumble("declare inherit-namespaces appears more than once", "XQST0055"); 622 } 623 foundCopyNamespaces = true; 624 nextToken(); 625 expect(Token.NAME); 626 if ("preserve".equals(t.currentTokenValue)) { 627 ((StaticQueryContext)env).setPreserveNamespaces(true); 628 } else if ("no-preserve".equals(t.currentTokenValue)) { 629 ((StaticQueryContext)env).setPreserveNamespaces(false); 630 } else { 631 grumble("copy-namespaces must be followed by 'preserve' or 'no-preserve'"); 632 } 633 nextToken(); 634 expect(Token.COMMA); 635 nextToken(); 636 expect(Token.NAME); 637 if ("inherit".equals(t.currentTokenValue)) { 638 ((StaticQueryContext)env).setInheritNamespaces(true); 639 } else if ("no-inherit".equals(t.currentTokenValue)) { 640 ((StaticQueryContext)env).setInheritNamespaces(false); 641 } else { 642 grumble("After the comma in the copy-namespaces declaration, expected 'inherit' or 'no-inherit'"); 643 } 644 nextToken(); 645 } 646 647 648 653 654 private void parseConstructionDeclaration() throws StaticError { 655 if (foundConstructionDeclaration) { 656 grumble("declare construction appears more than once", "XQST0067"); 657 } 658 foundConstructionDeclaration = true; 659 nextToken(); 660 expect(Token.NAME); 661 int val; 662 if ("preserve".equals(t.currentTokenValue)) { 663 val = Validation.PRESERVE; 664 } else if ("strip".equals(t.currentTokenValue)) { 665 val = Validation.STRIP; 666 } else { 667 grumble("construction mode must be 'preserve' or 'strip'"); 668 val = Validation.STRIP; 669 } 670 ((StaticQueryContext) env).setConstructionMode(val); 671 nextToken(); 672 } 673 674 679 680 private void parseSchemaImport() throws StaticError { 681 if (!env.getConfiguration().isSchemaAware(Configuration.XQUERY)) { 682 grumble("To import a schema, you need the schema-aware version of Saxon", "XQST0009"); 683 } 684 String prefix = null; 685 String namespaceURI = null; 686 List locationURIs = new ArrayList(5); 687 nextToken(); 688 if (isKeyword("namespace")) { 689 nextToken(); 690 expect(Token.NAME); 691 prefix = t.currentTokenValue; 692 checkProhibitedPrefixes(prefix); 693 nextToken(); 694 expect(Token.EQUALS); 695 nextToken(); 696 } else if (isKeyword("default")) { 697 nextToken(); 698 if (!isKeyword("element")) { 699 grumble("In 'import schema', expected 'element namespace'"); 700 } 701 nextToken(); 702 if (!isKeyword("namespace")) { 703 grumble("In 'import schema', expected keyword 'namespace'"); 704 } 705 nextToken(); 706 prefix = ""; 707 } 708 if (t.currentToken == Token.STRING_LITERAL) { 709 namespaceURI = t.currentTokenValue; 710 nextToken(); 711 if (isKeyword("at")) { 712 nextToken(); 713 expect(Token.STRING_LITERAL); 714 locationURIs.add(t.currentTokenValue); 715 nextToken(); 716 while (t.currentToken == Token.COMMA) { 717 nextToken(); 718 expect(Token.STRING_LITERAL); 719 locationURIs.add(t.currentTokenValue); 720 nextToken(); 721 } 722 } else if (t.currentToken != Token.SEMICOLON) { 723 grumble("After the target namespace URI, expected 'at' or ';'"); 724 } 725 } else { 726 grumble("After 'import schema', expected 'namespace', 'default', or a string-literal"); 727 } 728 if (prefix != null) { 729 if (namespaceURI==null || "".equals(namespaceURI)) { 730 grumble("A prefix cannot be bound to the null namespace", "XQST0057"); 731 } 732 try { 733 if ("".equals(prefix)) { 734 ((StaticQueryContext) env).setDefaultElementNamespace(namespaceURI); 735 } else { 736 ((StaticQueryContext) env).declarePassiveNamespace(prefix, namespaceURI, true); 737 } 738 } catch (StaticError err) { 739 err.setLocator(makeLocator()); 740 reportError(err); 741 } 742 } 743 744 746 Configuration config = env.getConfiguration(); 747 if (config.getSchema(namespaceURI) == null) { 748 if (locationURIs.size() > 0) { 749 try { 750 PipelineConfiguration pipe = config.makePipelineConfiguration(); 751 config.readMultipleSchemas(pipe, env.getBaseURI(), locationURIs, namespaceURI); 752 } catch (TransformerConfigurationException err) { 753 grumble("Error in schema. " + err.getMessage(), "XQST0059"); 754 } 755 } else { 756 grumble("Unable to locate requested schema", "XQST0059"); 757 } 758 } 759 ((StaticQueryContext) env).addImportedSchema(namespaceURI); 760 } 761 762 766 767 private void parseModuleImport() throws StaticError { 768 StaticQueryContext thisModule = (StaticQueryContext) env; 769 String prefix = null; 770 String moduleURI = null; 771 List locationURIs = new ArrayList(5); 772 nextToken(); 773 if (t.currentToken == Token.NAME && t.currentTokenValue == "namespace") { 774 nextToken(); 775 expect(Token.NAME); 776 prefix = t.currentTokenValue; 777 checkProhibitedPrefixes(prefix); 778 nextToken(); 779 expect(Token.EQUALS); 780 nextToken(); 781 } 782 if (t.currentToken == Token.STRING_LITERAL) { 783 moduleURI = t.currentTokenValue; 784 if (importedModules.contains(moduleURI)) { 785 grumble("Two 'import module' declarations specify the same module namespace", "XQST0047"); 786 } 787 importedModules.add(moduleURI); 788 ((StaticQueryContext)env).addImportedNamespace(moduleURI); 789 nextToken(); 790 if (isKeyword("at")) { 791 do { 792 nextToken(); 793 expect(Token.STRING_LITERAL); 794 String uri = t.currentTokenValue; 795 try { 796 uri = StandardURIResolver.makeAbsolute(uri, env.getBaseURI()).toString(); 797 } catch (DynamicError dynamicError) { 798 grumble(dynamicError.getMessage()); 799 } catch (URISyntaxException e) { 800 grumble("Invalid URI " + uri + ": " + e.getMessage()); 801 } 802 locationURIs.add(uri); 803 nextToken(); 804 } while (t.currentToken == Token.COMMA); 805 } 806 } else { 807 grumble("After 'import module', expected 'namespace' or a string-literal"); 808 } 809 if (prefix != null) { 810 try { 811 thisModule.declarePassiveNamespace(prefix, moduleURI, true); 812 } catch (StaticError err) { 813 err.setLocator(makeLocator()); 814 reportError(err); 815 } 816 } 817 String thisModuleNS = thisModule.getModuleNamespace(); 818 819 if (!moduleURI.equals(((StaticQueryContext)env).getModuleNamespace())) { 821 StaticQueryContext parent = (StaticQueryContext)env; 822 while (parent != null) { 823 if (moduleURI.equals(parent.getModuleNamespace())) { 824 StaticError err = new StaticError( 825 "A module cannot import itself directly or indirectly, unless all modules in the cycle are in the same namespace"); 826 err.setErrorCode("XQST0073"); 827 throw err; 828 } 829 parent = parent.getImporter(); 830 } 831 } 832 833 boolean foundOne = false; 834 835 List existingModules = executable.getQueryLibraryModules(moduleURI); 837 if (existingModules != null) { 838 for (int m=0; m<existingModules.size(); m++) { 839 StaticQueryContext importedModule = (StaticQueryContext)existingModules.get(m); 840 if (!importedModule.getLocationURI().equals(((StaticQueryContext)env).getLocationURI())) { 841 foundOne = true; 843 } 844 for (int h=locationURIs.size()-1; h>=0; h--) { 845 if (locationURIs.get(h).equals(importedModule.getLocationURI())) { 846 locationURIs.remove(h); 847 } 848 } 849 } 850 } 851 852 854 if (locationURIs.size() == 0 && foundOne) { 855 return; 856 } 857 858 860 ModuleURIResolver resolver = env.getConfiguration().getModuleURIResolver(); 861 862 String [] hints = new String [locationURIs.size()]; 863 hints = (String [])locationURIs.toArray(hints); 864 StreamSource [] sources = null; 865 try { 866 if (resolver != null) { 867 sources = resolver.resolve(moduleURI, env.getBaseURI(), hints); 868 } 869 if (sources == null) { 870 if (hints.length == 0) { 871 if (existingModules == null) { 872 grumble("Cannot locate module for namespace " + moduleURI, "XQST0059"); 873 } 874 } 875 resolver = env.getConfiguration().getStandardModuleURIResolver(); 876 sources = resolver.resolve(moduleURI, env.getBaseURI(), hints); 877 } 878 } catch (XPathException e) { 879 throw StaticError.makeStaticError(e); 880 } 881 882 for (int m=0; m<sources.length; m++) { 883 StreamSource ss = sources[m]; 884 String baseURI = ss.getSystemId(); 885 if (baseURI == null) { 886 if (m < hints.length) { 887 ss.setSystemId(hints[m]); 888 } else { 889 grumble("No base URI available for imported module", "XQST0059"); 890 } 891 } 892 try { 893 String queryText = QueryReader.readSourceQuery(ss); 894 StaticQueryContext importedModule = StaticQueryContext.makeStaticQueryContext( 895 baseURI, executable, thisModule, queryText, moduleURI); 896 } catch (StaticError err) { 898 if (err.getLocator() == null) { 899 err.setLocator(makeLocator()); 900 } 901 reportError(err); 902 } 903 } 904 } 905 906 911 912 private void parseBaseURIDeclaration() throws StaticError { 913 if (foundBaseURIDeclaration) { 914 grumble("Base URI Declaration may only appear once", "XQST0032"); 915 } 916 foundBaseURIDeclaration = true; 917 nextToken(); 918 expect(Token.STRING_LITERAL); 919 String uri = t.currentTokenValue; 920 ((StaticQueryContext) env).setBaseURI(uri); 921 nextToken(); 922 } 923 924 929 930 private void parseDefaultFunctionNamespace() throws StaticError { 931 if (foundDefaultFunctionNamespace) { 932 grumble("default function namespace appears more than once", "XQST0066"); 933 } 934 foundDefaultFunctionNamespace = true; 935 nextToken(); 936 expect(Token.NAME); 937 if (!"namespace".equals(t.currentTokenValue)) { 938 grumble("After 'declare default function', expected 'namespace'"); 939 } 940 nextToken(); 941 expect(Token.STRING_LITERAL); 942 String uri = t.currentTokenValue; 943 ((StaticQueryContext) env).setDefaultFunctionNamespace(uri); 944 nextToken(); 945 } 946 947 952 953 private void parseDefaultElementNamespace() throws StaticError { 954 if (foundDefaultElementNamespace) { 955 grumble("default element namespace appears more than once", "XQST0066"); 956 } 957 foundDefaultElementNamespace = true; 958 nextToken(); 959 expect(Token.NAME); 960 if (!"namespace".equals(t.currentTokenValue)) { 961 grumble("After 'declare default element', expected 'namespace'"); 962 } 963 nextToken(); 964 expect(Token.STRING_LITERAL); 965 String uri = t.currentTokenValue; 966 ((StaticQueryContext) env).setDefaultElementNamespace(uri); 967 nextToken(); 968 } 969 970 975 976 private void parseNamespaceDeclaration() throws StaticError { 977 nextToken(); 978 expect(Token.NAME); 979 String prefix = t.currentTokenValue; 980 if (!XMLChar.isValidNCName(prefix)) { 981 grumble("Invalid namespace prefix " + Err.wrap(prefix)); 982 } 983 checkProhibitedPrefixes(prefix); 984 nextToken(); 985 expect(Token.EQUALS); 986 nextToken(); 987 expect(Token.STRING_LITERAL); 988 String uri = t.currentTokenValue; 989 if ("".equals(uri)) { 990 grumble("A namespace URI cannot be empty"); 991 } 992 try { 993 ((StaticQueryContext) env).declarePassiveNamespace(prefix, uri, true); 994 } catch (StaticError err) { 995 err.setLocator(makeLocator()); 996 reportError(err); 997 } 998 nextToken(); 999 } 1000 1001 1006 1007 private void checkProhibitedPrefixes(String prefix) throws StaticError { 1008 if ("xml".equals(prefix) || "xmlns".equals(prefix)) { 1009 grumble("The namespace prefix " + Err.wrap(prefix) + " cannot be redeclared", "XQST0070"); 1010 } 1011 } 1012 1013 1020 1021 private void parseVariableDeclaration() throws StaticError { 1022 int offset = t.currentTokenStartOffset; 1023 GlobalVariableDefinition var = new GlobalVariableDefinition(); 1024 var.setLineNumber(t.getLineNumber()); 1025 var.setSystemId(env.getSystemId()); 1026 nextToken(); 1027 expect(Token.DOLLAR); 1028 t.setState(Tokenizer.BARE_NAME_STATE); 1029 nextToken(); 1030 expect(Token.NAME); 1031 String varName = t.currentTokenValue; 1032 var.setVariableName(varName); 1033 int varNameCode = makeNameCode(t.currentTokenValue, false); 1034 int varFingerprint = varNameCode & 0xfffff; 1035 var.setNameCode(varFingerprint); 1036 1037 String uri = env.getNamePool().getURI(varNameCode); 1038 String moduleURI = ((StaticQueryContext)env).getModuleNamespace(); 1039 if (moduleURI != null && !moduleURI.equals(uri)) { 1040 grumble("A variable declared in a library module must be in the module namespace", "XQST0048"); 1041 } 1042 1043 nextToken(); 1044 SequenceType requiredType = SequenceType.ANY_SEQUENCE; 1045 if (isKeyword("as")) { 1046 t.setState(Tokenizer.SEQUENCE_TYPE_STATE); 1047 nextToken(); 1048 requiredType = parseSequenceType(); 1049 } 1050 var.setRequiredType(requiredType); 1051 1052 if (t.currentToken == Token.ASSIGN) { 1053 t.setState(Tokenizer.DEFAULT_STATE); 1054 nextToken(); 1055 Expression exp = parseExpression(); 1056 var.setIsParameter(false); 1057 var.setValueExpression(makeTracer(offset, exp, StandardNames.XSL_VARIABLE, varNameCode)); 1058 } else if (t.currentToken == Token.NAME) { 1059 if ("external".equals(t.currentTokenValue)) { 1060 var.setIsParameter(true); 1061 if (defaultValue != null) { 1062 var.setValueExpression(defaultValue); 1063 } 1064 nextToken(); 1065 } else { 1066 grumble("Variable must either be initialized or be declared as external"); 1067 } 1068 } else { 1069 grumble("Expected ':=' or 'external' in variable declaration"); 1070 } 1071 1072 StaticQueryContext qenv = (StaticQueryContext) env; 1073 if (qenv.getModuleNamespace() != null && 1074 env.getNamePool().getURICode(varFingerprint) != qenv.getModuleNamespaceCode()) { 1075 grumble("Variable " + Err.wrap(varName, Err.VARIABLE) + " is not defined in the module namespace"); 1076 } 1077 try { 1078 qenv.declareVariable(var); 1079 } catch (XPathException e) { 1080 grumble(e.getMessage(), e.getErrorCodeLocalPart()); 1081 } 1082 } 1083 1084 1093 1094 private void parseFunctionDeclaration() throws StaticError { 1095 int offset = t.currentTokenStartOffset; 1097 nextToken(); 1098 expect(Token.FUNCTION); 1099 1100 String uri; 1101 int fnc; 1102 if (t.currentTokenValue.indexOf(':') < 0) { 1103 uri = env.getDefaultFunctionNamespace(); 1104 fnc = env.getNamePool().allocate("", uri, t.currentTokenValue); 1105 } else { 1106 fnc = makeNameCode(t.currentTokenValue, false); 1107 uri = env.getNamePool().getURI(fnc); 1108 } 1109 1110 if (uri.equals("")) { 1111 grumble("The function must be in a namespace", "XQST0060"); 1112 } 1113 1114 String moduleURI = ((StaticQueryContext)env).getModuleNamespace(); 1115 if (moduleURI != null && !moduleURI.equals(uri)) { 1116 grumble("A function in a library module must be in the module namespace", "XQST0048"); 1117 } 1118 1119 if (NamespaceConstant.isReservedInQuery(uri)) { 1120 grumble("The function name " + t.currentTokenValue + " is in a reserved namespace", "XQST0045"); 1121 } 1122 1123 XQueryFunction func = new XQueryFunction(); 1124 func.setNameCode(fnc); 1125 func.arguments = new ArrayList(8); 1126 func.resultType = SequenceType.ANY_SEQUENCE; 1127 func.body = null; 1128 func.lineNumber = t.getLineNumber(offset); 1129 func.columnNumber = t.getColumnNumber(offset); 1130 func.systemId = env.getSystemId(); 1131 func.setExecutable(getExecutable()); 1132 1133 1134 nextToken(); 1135 HashSet paramNames = new HashSet(8); 1136 while (t.currentToken != Token.RPAR) { 1137 expect(Token.DOLLAR); 1140 nextToken(); 1141 expect(Token.NAME); 1142 String argName = t.currentTokenValue; 1143 int nameCode = makeNameCode(argName, false); 1144 int fingerprint = nameCode & 0xfffff; 1145 Integer f = new Integer (fingerprint); 1146 if (paramNames.contains(f)) { 1147 grumble("Duplicate parameter name " + Err.wrap(t.currentTokenValue, Err.VARIABLE), "XQST0039"); 1148 } 1149 paramNames.add(f); 1150 SequenceType paramType = SequenceType.ANY_SEQUENCE; 1151 nextToken(); 1152 if (t.currentToken == Token.NAME && "as".equals(t.currentTokenValue)) { 1153 nextToken(); 1154 paramType = parseSequenceType(); 1155 } 1156 1157 RangeVariableDeclaration arg = new RangeVariableDeclaration(); 1158 arg.setNameCode(nameCode); 1159 arg.setRequiredType(paramType); 1160 arg.setVariableName(argName); 1161 func.arguments.add(arg); 1162 declareRangeVariable(arg); 1163 if (t.currentToken == Token.RPAR) { 1164 break; 1165 } else if (t.currentToken == Token.COMMA) { 1166 nextToken(); 1167 } else { 1168 grumble("Expected ',' or ')' after function argument, found '" + 1169 Token.tokens[t.currentToken] + '\''); 1170 } 1171 } 1172 t.setState(Tokenizer.BARE_NAME_STATE); 1173 nextToken(); 1174 if (isKeyword("as")) { 1175 t.setState(Tokenizer.SEQUENCE_TYPE_STATE); 1176 nextToken(); 1177 func.resultType = parseSequenceType(); 1178 } 1179 if (isKeyword("external")) { 1180 grumble("Saxon does not allow external functions to be declared"); 1181 } else { 1182 expect(Token.LCURLY); 1183 t.setState(Tokenizer.DEFAULT_STATE); 1184 nextToken(); 1185 func.body = parseExpression(); 1186 if (func.body instanceof ComputedExpression) { 1187 ((ComputedExpression)func.body).setParentExpression(func); 1188 } 1189 expect(Token.RCURLY); 1190 lookAhead(); } 1192 UserFunctionParameter[] params = func.getParameterDefinitions(); 1193 for (int i = 0; i < params.length; i++) { 1194 undeclareRangeVariable(); 1195 } 1196 t.setState(Tokenizer.DEFAULT_STATE); 1197 nextToken(); 1198 1199 StaticQueryContext qenv = (StaticQueryContext) env; 1200 1201 try { 1202 qenv.declareFunction(func); 1203 } catch (XPathException e) { 1204 grumble(e.getMessage()); 1205 } 1206 1207 } 1208 1209 1217 1218 private void parseOptionDeclaration() throws StaticError { 1219 nextToken(); 1220 expect(Token.NAME); 1221 int varNameCode = makeNameCode(t.currentTokenValue, false); 1222 String uri = env.getNamePool().getURI(varNameCode); 1223 1224 nextToken(); 1225 expect(Token.STRING_LITERAL); 1226 String value = t.currentTokenValue; 1227 1228 if (uri.equals(NamespaceConstant.SAXON)) { 1229 String localName = env.getNamePool().getLocalName(varNameCode); 1230 if (localName.equals("output")) { 1231 setOutputProperty(value); 1232 } else if (localName.equals("default")) { 1233 defaultValue = setDefaultValue(value); 1234 } else { 1235 warning("Unknown Saxon option declaration: " + env.getNamePool().getDisplayName(varNameCode)); 1236 } 1237 } 1238 1239 nextToken(); 1240 } 1241 1242 1246 1247 private void setOutputProperty(String property) { 1248 int equals = property.indexOf("="); 1249 if (equals < 0) { 1250 badOutputProperty("no equals sign"); 1251 } else if (equals == 0) { 1252 badOutputProperty("starts with '="); 1253 } else if (equals == property.length()-1) { 1254 badOutputProperty("ends with '="); 1255 } 1256 String keyword = property.substring(0, equals).trim(); 1257 String value = property.substring(equals+1).trim(); 1258 Properties props = getExecutable().getDefaultOutputProperties(); 1259 try { 1260 ResultDocument.setSerializationProperty( 1261 props, 1262 makeNameCode(keyword, false) & NamePool.FP_MASK, 1263 value, 1264 env.getNamePool(), 1265 env.getNamespaceResolver() 1266 ); 1267 } catch (XPathException e) { 1268 badOutputProperty(e.getMessage()); 1269 } 1270 } 1271 1272 private void badOutputProperty(String s) { 1273 try { 1274 warning("Invalid serialization property (" + s + ") - ignored"); 1275 } catch (StaticError staticError) { 1276 } 1278 } 1279 1280 1284 1285 public Expression setDefaultValue(String exp) { 1286 try { 1287 IndependentContext ic = new IndependentContext(env.getConfiguration()); 1288 ic.setNamespaceResolver(env.getNamespaceResolver()); 1289 Expression expr = ExpressionTool.make(exp, ic, 0, Token.EOF, 1); 1290 1291 ItemType contextItemType = Type.ITEM_TYPE; 1292 expr = expr.typeCheck(ic, contextItemType); 1293 expr = expr.optimize(env.getConfiguration().getOptimizer(), env, contextItemType); 1294 SlotManager stackFrameMap = ic.getStackFrameMap(); 1295 ExpressionTool.allocateSlots(expr, stackFrameMap.getNumberOfVariables(), stackFrameMap); 1296 return expr; 1297 } catch (XPathException e) { 1298 try { 1299 warning("Invalid expression for default value: " + e.getMessage() + " (ignored)"); 1300 } catch (StaticError staticError) { 1301 } 1303 return null; 1304 } 1305 } 1306 1307 1330 1331 protected Expression parseForExpression() throws StaticError { 1332 int offset = t.currentTokenStartOffset; 1333 Expression whereCondition = null; 1334 int whereOffset = -1; 1335 List clauseList = new ArrayList(4); 1337 while (true) { 1338 if (t.currentToken == Token.FOR) { 1339 parseForClause(clauseList); 1340 } else if (t.currentToken == Token.LET) { 1341 parseLetClause(clauseList); 1342 } else { 1343 break; 1344 } 1345 } 1346 if (t.currentToken == Token.WHERE || isKeyword("where")) { 1347 whereOffset = t.currentTokenStartOffset; 1348 nextToken(); 1349 whereCondition = parseExpression(); 1350 } 1351 int orderByOffset = t.currentTokenStartOffset; 1352 if (isKeyword("stable")) { 1353 nextToken(); 1355 if (!isKeyword("order")) { 1356 grumble("'stable' must be followed by 'order by'"); 1357 } 1358 } 1359 List sortSpecList = null; 1360 if (isKeyword("order")) { 1361 t.setState(Tokenizer.BARE_NAME_STATE); 1362 nextToken(); 1363 if (!isKeyword("by")) { 1364 grumble("'order' must be followed by 'by'"); 1365 } 1366 t.setState(Tokenizer.DEFAULT_STATE); 1367 nextToken(); 1368 sortSpecList = parseSortDefinition(); 1369 } 1370 int returnOffset = t.currentTokenStartOffset; 1371 expect(Token.RETURN); 1372 t.setState(Tokenizer.DEFAULT_STATE); 1373 nextToken(); 1374 Expression action = parseExprSingle(); 1375 action = makeTracer(returnOffset, action, Location.RETURN_EXPRESSION, -1); 1376 1377 1378 1379 1387 if (sortSpecList != null) { 1388 TupleExpression exp = new TupleExpression(1 + sortSpecList.size()); 1389 setLocation(exp); 1390 exp.setExpression(0, action); 1391 for (int i = 0; i < sortSpecList.size(); i++) { 1392 try { 1393 RoleLocator role = new RoleLocator(RoleLocator.ORDER_BY, "FLWR", i, null); 1394 role.setSourceLocator(makeLocator()); 1395 Expression sk = 1396 TypeChecker.staticTypeCheck( 1397 ((SortSpec) sortSpecList.get(i)).sortKey, 1398 SequenceType.OPTIONAL_ATOMIC, 1399 false, 1400 role, env); 1401 exp.setExpression(i + 1, sk); 1402 } catch (XPathException err) { 1403 grumble(err.getMessage()); 1404 } 1405 } 1406 action = exp; 1407 } 1408 1409 1412 if (whereCondition != null) { 1413 action = new IfExpression(whereCondition, action, EmptySequence.getInstance()); 1414 action = makeTracer(whereOffset, action, Location.WHERE_CLAUSE, -1); 1415 setLocation(action); 1416 } 1417 1418 for (int i = clauseList.size() - 1; i >= 0; i--) { 1419 Object clause = clauseList.get(i); 1420 if (clause instanceof ExpressionParser.ForClause) { 1421 ExpressionParser.ForClause fc = (ExpressionParser.ForClause) clause; 1422 ForExpression exp = new ForExpression(); 1423 exp.setVariableDeclaration(fc.rangeVariable); 1424 exp.setPositionVariable(fc.positionVariable); 1425 exp.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), t.getLineNumber(fc.offset))); 1426 exp.setSequence(fc.sequence); 1427 exp.setAction(action); 1428 action = makeTracer(fc.offset, exp, Location.FOR_EXPRESSION, fc.rangeVariable.getNameCode()); 1429 } else { 1430 LetClause lc = (LetClause) clause; 1431 LetExpression exp = makeLetExpression(); 1432 exp.setVariableDeclaration(lc.variable); 1433 exp.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), t.getLineNumber(lc.offset))); 1434 exp.setSequence(lc.value); 1435 exp.setAction(action); 1436 action = makeTracer(lc.offset, exp, Location.LET_EXPRESSION, lc.variable.getNameCode()); 1437 } 1438 } 1439 1440 1442 if (sortSpecList != null) { 1443 FixedSortKeyDefinition[] keys = new FixedSortKeyDefinition[sortSpecList.size()]; 1444 for (int i = 0; i < sortSpecList.size(); i++) { 1445 SortSpec spec = (SortSpec) sortSpecList.get(i); 1446 FixedSortKeyDefinition key = new FixedSortKeyDefinition(); 1447 key.setSortKey(StringValue.EMPTY_STRING); 1449 key.setOrder(new StringValue(spec.ascending ? "ascending" : "descending")); 1450 key.setEmptyFirst(spec.ascending ? spec.emptyLeast : !spec.emptyLeast); 1451 try { 1452 if (spec.collation != null) { 1453 key.setCollation(env.getCollation(spec.collation)); 1454 } 1455 key.bindComparer(env.getConfiguration()); 1456 keys[i] = key; 1457 } catch (XPathException e) { 1458 grumble(e.getMessage()); 1459 } 1460 } 1461 TupleSorter sorter = new TupleSorter(action, keys); 1462 setLocation(sorter); 1463 action = makeTracer(orderByOffset, sorter, Location.ORDER_BY_CLAUSE, -1); 1464 } 1465 1466 1468 for (int i = clauseList.size() - 1; i >= 0; i--) { 1469 Object clause = clauseList.get(i); 1470 if ((clause instanceof ExpressionParser.ForClause) && 1471 ((ExpressionParser.ForClause) clause).positionVariable != null) { 1472 undeclareRangeVariable(); 1474 } 1475 undeclareRangeVariable(); 1477 } 1478 1479 setLocation(action, offset); 1480 return action; 1481 1482 } 1483 1484 1488 1489 private LetExpression makeLetExpression() { 1490 if (env.getConfiguration().getTraceListener() == null) { 1491 return new LetExpression(); 1492 } else { 1493 return new EagerLetExpression(); 1494 } 1495 } 1496 1497 1507 private void parseForClause(List clauseList) throws StaticError { 1508 boolean first = true; 1509 do { 1510 ExpressionParser.ForClause clause = new ExpressionParser.ForClause(); 1511 if (first) { 1512 clause.offset = t.currentTokenStartOffset; 1513 } 1514 clauseList.add(clause); 1515 nextToken(); 1516 if (first) { 1517 first = false; 1518 } else { 1519 clause.offset = t.currentTokenStartOffset; 1520 } 1521 expect(Token.DOLLAR); 1522 nextToken(); 1523 expect(Token.NAME); 1524 String var = t.currentTokenValue; 1525 1526 RangeVariableDeclaration v = new RangeVariableDeclaration(); 1527 v.setNameCode(makeNameCode(var, false)); 1528 v.setRequiredType(SequenceType.SINGLE_ITEM); 1529 v.setVariableName(var); 1530 clause.rangeVariable = v; 1531 nextToken(); 1532 1533 if (isKeyword("as")) { 1534 nextToken(); 1535 SequenceType type = parseSequenceType(); 1536 v.setRequiredType(type); 1537 if (type.getCardinality() != StaticProperty.EXACTLY_ONE) { 1538 grumble("Cardinality of range variable must be exactly one"); 1539 } 1540 } 1541 clause.positionVariable = null; 1542 if (isKeyword("at")) { 1543 nextToken(); 1544 expect(Token.DOLLAR); 1545 nextToken(); 1546 expect(Token.NAME); 1547 RangeVariableDeclaration pos = new RangeVariableDeclaration(); 1548 pos.setNameCode(makeNameCode(t.currentTokenValue, false)); 1549 pos.setRequiredType(SequenceType.SINGLE_INTEGER); 1550 pos.setVariableName(t.currentTokenValue); 1551 clause.positionVariable = pos; 1552 nextToken(); 1554 } 1555 expect(Token.IN); 1556 nextToken(); 1557 clause.sequence = parseExprSingle(); 1558 declareRangeVariable(clause.rangeVariable); 1559 if (clause.positionVariable != null) { 1560 declareRangeVariable(clause.positionVariable); 1561 } 1562 } while (t.currentToken == Token.COMMA); 1563 } 1564 1565 1575 private void parseLetClause(List clauseList) throws StaticError { 1576 boolean first = true; 1577 do { 1578 LetClause clause = new LetClause(); 1579 if (first) { 1580 clause.offset = t.currentTokenStartOffset; 1581 } 1582 clauseList.add(clause); 1583 nextToken(); 1584 if (first) { 1585 first = false; 1586 } else { 1587 clause.offset = t.currentTokenStartOffset; 1588 } 1589 expect(Token.DOLLAR); 1590 nextToken(); 1591 expect(Token.NAME); 1592 String var = t.currentTokenValue; 1593 1594 RangeVariableDeclaration v = new RangeVariableDeclaration(); 1595 v.setNameCode(makeNameCode(var, false)); 1596 v.setRequiredType(SequenceType.ANY_SEQUENCE); 1597 v.setVariableName(var); 1598 clause.variable = v; 1599 nextToken(); 1600 1601 if (isKeyword("as")) { 1602 nextToken(); 1603 v.setRequiredType(parseSequenceType()); 1604 } 1605 1606 expect(Token.ASSIGN); 1607 nextToken(); 1608 clause.value = parseExprSingle(); 1609 declareRangeVariable(v); 1610 } while (t.currentToken == Token.COMMA); 1611 } 1612 1613 1618 1619 public static Expression makeStringJoin(Expression exp, StaticContext env) { 1620 1621 exp = new Atomizer(exp, env.getConfiguration()); 1622 ItemType t = exp.getItemType(); 1623 if (t != Type.STRING_TYPE && t != Type.UNTYPED_ATOMIC_TYPE) { 1624 exp = new AtomicSequenceConverter(exp, Type.STRING_TYPE); 1625 } 1626 1627 StringJoin fn = (StringJoin)SystemFunction.makeSystemFunction("string-join", 2, env.getNamePool()); 1628 Expression[] args = new Expression[2]; 1629 args[0] = exp; 1630 args[1] = StringValue.SINGLE_SPACE; 1631 fn.setArguments(args); 1632 if (exp instanceof ComputedExpression) { 1633 fn.setLocationId(((ComputedExpression)exp).getLocationId()); 1634 } 1635 return fn; 1636 } 1637 1638 private static class LetClause { 1639 public RangeVariableDeclaration variable; 1640 public Expression value; 1641 public int offset; 1642 } 1643 1644 1655 private List parseSortDefinition() throws StaticError { 1656 List sortSpecList = new ArrayList(5); 1657 while (true) { 1658 SortSpec sortSpec = new SortSpec(); 1659 sortSpec.sortKey = parseExprSingle(); 1660 sortSpec.ascending = true; 1661 sortSpec.emptyLeast = defaultEmptyLeast; 1662 sortSpec.collation = env.getDefaultCollationName(); 1663 if (isKeyword("ascending")) { 1665 nextToken(); 1666 } else if (isKeyword("descending")) { 1667 sortSpec.ascending = false; 1668 nextToken(); 1669 } 1670 if (isKeyword("empty")) { 1671 nextToken(); 1672 if (isKeyword("greatest")) { 1673 sortSpec.emptyLeast = false; 1674 nextToken(); 1675 } else if (isKeyword("least")) { 1676 sortSpec.emptyLeast = true; 1677 nextToken(); 1678 } else { 1679 grumble("'empty' must be followed by 'greatest' or 'least'"); 1680 } 1681 } 1682 if (isKeyword("collation")) { 1683 nextToken(); 1684 expect(Token.STRING_LITERAL); 1685 sortSpec.collation = t.currentTokenValue; 1686 nextToken(); 1687 } 1688 sortSpecList.add(sortSpec); 1689 if (t.currentToken == Token.COMMA) { 1690 nextToken(); 1691 } else { 1692 break; 1693 } 1694 } 1695 return sortSpecList; 1696 } 1697 1698 private static class SortSpec { 1699 public Expression sortKey; 1700 public boolean ascending; 1701 public boolean emptyLeast; 1702 public String collation; 1703 } 1704 1705 1715 1716 protected Expression parseTypeswitchExpression() throws StaticError { 1717 1718 int offset = t.currentTokenStartOffset; 1720 nextToken(); 1721 Expression operand = parseExpression(); 1722 List types = new ArrayList(10); 1723 List actions = new ArrayList(10); 1724 expect(Token.RPAR); 1725 nextToken(); 1726 1727 1737 1740 LetExpression outerLet = makeLetExpression(); 1741 1742 RangeVariableDeclaration gen = new RangeVariableDeclaration(); 1743 gen.setNameCode(makeNameCode("zz_typeswitchVar", false)); 1744 gen.setRequiredType(SequenceType.ANY_SEQUENCE); 1745 gen.setVariableName("zz_typeswitchVar"); 1746 1747 outerLet.setVariableDeclaration(gen); 1748 outerLet.setSequence(operand); 1749 1750 while (t.currentToken == Token.CASE) { 1751 int caseOffset = t.currentTokenStartOffset; 1752 SequenceType type; 1753 Expression action; 1754 nextToken(); 1755 if (t.currentToken == Token.DOLLAR) { 1756 nextToken(); 1757 expect(Token.NAME); 1758 final String var = t.currentTokenValue; 1759 final int varCode = makeNameCode(var, false); 1760 nextToken(); 1761 expect(Token.NAME); 1762 if (!"as".equals(t.currentTokenValue)) { 1763 grumble("After 'case $" + var + "', expected 'as'"); 1764 } 1765 nextToken(); 1766 type = parseSequenceType(); 1767 action = makeTracer(caseOffset, 1768 parseTypeswitchReturnClause(var, varCode, gen), 1769 Location.CASE_EXPRESSION, 1770 varCode); 1771 if (action instanceof TraceExpression) { 1772 ((TraceExpression)action).setProperty("type", type.toString()); 1773 } 1774 1775 } else { 1776 type = parseSequenceType(); 1777 t.treatCurrentAsOperator(); 1778 expect(Token.RETURN); 1779 nextToken(); 1780 action = makeTracer(caseOffset, parseExprSingle(), Location.CASE_EXPRESSION, -1); 1781 if (action instanceof TraceExpression) { 1782 ((TraceExpression)action).setProperty("type", type.toString()); 1783 } 1784 } 1785 types.add(type); 1786 actions.add(action); 1787 } 1788 if (types.size() == 0) { 1789 grumble("At least one case clause is required in a typeswitch"); 1790 } 1791 expect(Token.DEFAULT); 1792 final int defaultOffset = t.currentTokenStartOffset; 1793 nextToken(); 1794 Expression defaultAction; 1795 if (t.currentToken == Token.DOLLAR) { 1796 nextToken(); 1797 expect(Token.NAME); 1798 final String var = t.currentTokenValue; 1799 final int varCode = makeNameCode(var, false); 1800 nextToken(); 1801 defaultAction = makeTracer( 1802 defaultOffset, 1803 parseTypeswitchReturnClause(var, varCode, gen), 1804 Location.DEFAULT_EXPRESSION, 1805 varCode); 1806 } else { 1807 t.treatCurrentAsOperator(); 1808 expect(Token.RETURN); 1809 nextToken(); 1810 defaultAction = makeTracer(defaultOffset, parseExprSingle(), Location.DEFAULT_EXPRESSION, -1); 1811 } 1812 1813 Expression lastAction = defaultAction; 1814 for (int i = types.size() - 1; i >= 0; i--) { 1815 final VariableReference var = new VariableReference(gen); 1816 setLocation(var); 1817 final InstanceOfExpression ioe = 1818 new InstanceOfExpression(var, (SequenceType)types.get(i)); 1819 setLocation(ioe); 1820 final IfExpression ife = 1821 new IfExpression(ioe, (Expression) actions.get(i), lastAction); 1822 setLocation(ife); 1823 lastAction = ife; 1824 } 1825 outerLet.setAction(lastAction); 1826 return makeTracer(offset, outerLet, Location.TYPESWITCH_EXPRESSION, -1); 1827 } 1828 1829 private Expression parseTypeswitchReturnClause(String var, int varCode, RangeVariableDeclaration gen) 1830 throws StaticError { 1831 Expression action; 1832 t.treatCurrentAsOperator(); 1833 expect(Token.RETURN); 1834 nextToken(); 1835 1836 RangeVariableDeclaration v = new RangeVariableDeclaration(); 1837 v.setNameCode(varCode); 1838 v.setRequiredType(SequenceType.ANY_SEQUENCE); 1839 v.setVariableName(var); 1840 1841 declareRangeVariable(v); 1842 action = parseExprSingle(); 1843 undeclareRangeVariable(); 1844 1845 LetExpression innerLet = makeLetExpression(); 1846 innerLet.setVariableDeclaration(v); 1847 innerLet.setSequence(new VariableReference(gen)); 1848 innerLet.setAction(action); 1849 action = innerLet; 1850 return action; 1851 } 1852 1853 1859 1860 protected Expression parseValidateExpression() throws StaticError { 1861 if (!env.getConfiguration().isSchemaAware(Configuration.XQUERY)) { 1862 grumble("To use a validate expression, you need the schema-aware processor from http://www.saxonica.com/"); 1863 } 1864 int offset = t.currentTokenStartOffset; 1865 int mode = Validation.STRICT; 1866 boolean foundCurly = false; 1867 switch (t.currentToken) { 1868 case Token.VALIDATE_STRICT: 1869 mode = Validation.STRICT; 1870 nextToken(); 1871 break; 1872 case Token.VALIDATE_LAX: 1873 mode = Validation.LAX; 1874 nextToken(); 1875 break; 1876 case Token.KEYWORD_CURLY: 1877 if (t.currentTokenValue=="validate") { 1878 mode = Validation.STRICT; 1879 } else { 1880 throw new AssertionError ("shouldn't be parsing a validate expression"); 1881 } 1882 foundCurly = true; 1883 } 1884 1885 if (!foundCurly) { 1886 expect(Token.LCURLY); 1887 } 1888 nextToken(); 1889 1890 Expression exp = parseExpression(); 1891 if (exp instanceof ElementCreator) { 1892 ((ElementCreator)exp).setValidationMode(mode); 1893 } else if (exp instanceof DocumentInstr) { 1894 ((DocumentInstr)exp).setValidationAction(mode); 1895 } else { 1896 try { 1901 RoleLocator role = new RoleLocator(RoleLocator.TYPE_OP, "validate", 0, null); 1902 role.setSourceLocator(makeLocator()); 1903 exp = TypeChecker.staticTypeCheck( 1904 exp, 1905 SequenceType.SINGLE_NODE, 1906 false, 1907 role, env); 1908 } catch (XPathException err) { 1909 grumble(err.getMessage()); 1910 } 1911 exp = new CopyOf(exp, true, mode, null, true); 1912 setLocation(exp); 1913 ((CopyOf)exp).setRequireDocumentOrElement(true); 1914 } 1915 1916 expect(Token.RCURLY); 1917 t.lookAhead(); nextToken(); 1919 return makeTracer(offset, exp, Location.VALIDATE_EXPRESSION, -1); 1920 } 1921 1922 1928 1929 protected Expression parseExtensionExpression() throws StaticError { 1930 nextToken(); 1931 if (t.currentToken == Token.PRAGMA) { 1932 return parseExtensionExpression(); 1933 } 1934 expect(Token.LCURLY); 1935 nextToken(); 1936 if (t.currentToken == Token.RCURLY) { 1937 t.lookAhead(); nextToken(); 1939 grumble("Unrecognized pragma, with no fallback expression"); 1940 } 1941 Expression expr = parseExpression(); 1942 expect(Token.RCURLY); 1943 t.lookAhead(); nextToken(); 1945 return expr; 1946 } 1947 1948 1955 1956 protected Expression parseConstructor() throws StaticError { 1957 int offset = t.currentTokenStartOffset; 1958 switch (t.currentToken) { 1959 case Token.TAG: 1960 Expression tag = parsePseudoXML(false); 1961 lookAhead(); 1962 t.setState(Tokenizer.OPERATOR_STATE); 1963 nextToken(); 1964 return tag; 1965 case Token.KEYWORD_CURLY: 1966 String nodeKind = t.currentTokenValue; 1967 if (nodeKind == "validate") { 1968 return parseValidateExpression(); 1969 } else if (nodeKind == "ordered" || nodeKind=="unordered") { 1970 nextToken(); 1972 Expression content = parseExpression(); 1973 expect(Token.RCURLY); 1974 lookAhead(); nextToken(); 1976 return content; 1977 } else if (nodeKind == "document") { 1978 nextToken(); 1979 Expression content = parseExpression(); 1980 expect(Token.RCURLY); 1981 lookAhead(); nextToken(); 1983 DocumentInstr doc = new DocumentInstr(false, null, env.getBaseURI()); 1984 if (!((StaticQueryContext)env).isPreserveNamespaces()) { 1985 content = new CopyOf(content, false, Validation.PRESERVE, null, true); 1986 } 1987 doc.setValidationAction(((StaticQueryContext)env).getConstructionMode()); 1988 doc.setContentExpression(content); 1989 setLocation(doc, offset); 1990 return doc; 1991 1992 } else if ("element".equals(nodeKind)) { 1993 nextToken(); 1994 Expression name = parseExpression(); 1996 expect(Token.RCURLY); 1997 lookAhead(); nextToken(); 1999 expect(Token.LCURLY); 2000 t.setState(Tokenizer.DEFAULT_STATE); 2001 nextToken(); 2002 Expression content = null; 2003 if (t.currentToken != Token.RCURLY) { 2004 content = parseExpression(); 2006 if (content instanceof ElementCreator) { 2009 ((ElementCreator) content).setValidationMode(Validation.PRESERVE); 2010 } 2011 expect(Token.RCURLY); 2012 } 2013 lookAhead(); nextToken(); 2015 2016 Instruction inst; 2017 if (name instanceof Value) { 2018 int nameCode; 2020 if (name instanceof StringValue) { 2021 String lex = ((StringValue) name).getStringValue(); 2022 nameCode = makeNameCode(lex, true); 2023 } else if (name instanceof QNameValue) { 2024 nameCode = env.getNamePool().allocate("", 2025 ((QNameValue) name).getNamespaceURI(), 2026 ((QNameValue) name).getLocalName()); 2027 } else { 2028 grumble("Element name must be either a string or a QName"); 2029 return null; 2030 } 2031 inst = new FixedElement(nameCode, 2032 ((StaticQueryContext) env).getActiveNamespaceCodes(), 2033 ((StaticQueryContext) env).isInheritNamespaces(), 2034 null, 2035 ((StaticQueryContext) env).getConstructionMode()); 2036 if (content == null) { 2037 content = EmptySequence.getInstance(); 2038 } 2039 ((FixedElement)inst).setContentExpression(content); 2040 setLocation(inst, offset); 2041 return makeTracer(offset, inst,Location.LITERAL_RESULT_ELEMENT, nameCode); 2043 } else { 2044 inst = new ComputedElement(name, null, 2046 env.getNamespaceResolver(), 2047 null, 2048 ((StaticQueryContext) env).getConstructionMode(), 2049 ((StaticQueryContext) env).isInheritNamespaces(), 2050 true); 2051 setLocation(inst); 2052 if (content == null) { 2053 content = EmptySequence.getInstance(); 2054 } 2055 ((ComputedElement)inst).setContentExpression(content); 2056 setLocation(inst, offset); 2057 return makeTracer(offset, inst, StandardNames.XSL_ELEMENT, -1); 2059 } 2060 2061 2062 2063 } else if ("attribute".equals(nodeKind)) { 2064 nextToken(); 2065 Expression name = parseExpression(); 2066 expect(Token.RCURLY); 2067 lookAhead(); nextToken(); 2069 expect(Token.LCURLY); 2070 t.setState(Tokenizer.DEFAULT_STATE); 2071 nextToken(); 2072 Expression content = null; 2073 if (t.currentToken != Token.RCURLY) { 2074 content = parseExpression(); 2075 expect(Token.RCURLY); 2076 } 2077 lookAhead(); nextToken(); 2079 if (name instanceof StringValue && content instanceof Value) { 2080 String attName = ((StringValue)name).getStringValue(); 2081 if (attName.equals("xmlns") || attName.startsWith("xmlns:")) { 2082 grumble("Cannot create a namespace using an attribute constructor"); 2083 } 2084 int nameCode = makeNameCode(attName, false); 2085 FixedAttribute fatt = new FixedAttribute(nameCode, 2086 Validation.STRIP, 2087 null, 2088 StandardNames.XDT_UNTYPED_ATOMIC); 2089 fatt.setRejectDuplicates(); 2090 makeSimpleContent(content, fatt, offset); 2091 return makeTracer(offset, fatt, StandardNames.XSL_ATTRIBUTE, -1); 2092 } else { 2093 Attribute att = new Attribute( 2094 name, 2095 null, 2096 env.getNamespaceResolver(), 2097 Validation.STRIP, 2098 null, 2099 -1, 2100 true); 2101 att.setRejectDuplicates(); 2102 makeSimpleContent(content, att, offset); 2103 return makeTracer(offset, att, StandardNames.XSL_ATTRIBUTE, -1); 2104 } 2105 2106 } else if ("text".equals(nodeKind)) { 2107 nextToken(); 2108 if (t.currentToken == Token.RCURLY) { 2109 lookAhead(); nextToken(); 2111 return EmptySequence.getInstance(); 2112 } else { 2113 Expression value = parseExpression(); 2114 expect(Token.RCURLY); 2115 lookAhead(); nextToken(); 2117 Expression select; 2118 try { 2119 select = stringify(value, true); 2120 } catch (XPathException e) { 2121 throw StaticError.makeStaticError(e); 2122 } 2123 ValueOf vof = new ValueOf(select, false, true); 2124 setLocation(vof, offset); 2125 return makeTracer(offset, vof, StandardNames.XSL_TEXT, -1); 2126 } 2127 } else if ("comment".equals(nodeKind)) { 2128 nextToken(); 2129 if (t.currentToken == Token.RCURLY) { 2130 lookAhead(); nextToken(); 2132 return EmptySequence.getInstance(); 2133 } else { 2134 Expression value = parseExpression(); 2135 expect(Token.RCURLY); 2136 lookAhead(); nextToken(); 2138 Comment com = new Comment(); 2139 makeSimpleContent(value, com, offset); 2140 return makeTracer(offset, com, StandardNames.XSL_COMMENT, -1); 2141 } 2142 } else if ("processing-instruction".equals(nodeKind)) { 2143 nextToken(); 2144 Expression name = parseExpression(); 2145 expect(Token.RCURLY); 2146 lookAhead(); nextToken(); 2148 expect(Token.LCURLY); 2149 t.setState(Tokenizer.DEFAULT_STATE); 2150 nextToken(); 2151 Expression content = null; 2152 if (t.currentToken != Token.RCURLY) { 2153 content = parseExpression(); 2154 expect(Token.RCURLY); 2155 } 2156 lookAhead(); nextToken(); 2158 ProcessingInstruction pi = new ProcessingInstruction(name); 2159 makeSimpleContent(content, pi, offset); 2160 return makeTracer(offset, pi, StandardNames.XSL_PROCESSING_INSTRUCTION, -1); 2161 2162 } else { 2163 grumble("Unrecognized node constructor " + t.currentTokenValue + "{}"); 2164 2165 } 2166 case Token.ELEMENT_QNAME: 2167 int nameCode = makeNameCode(t.currentTokenValue, true); 2168 Expression content = null; 2169 nextToken(); 2170 if (t.currentToken != Token.RCURLY) { 2171 content = parseExpression(); 2172 expect(Token.RCURLY); 2173 } 2174 lookAhead(); nextToken(); 2176 FixedElement el2 = new FixedElement(nameCode, 2177 ((StaticQueryContext) env).getActiveNamespaceCodes(), 2178 ((StaticQueryContext) env).isInheritNamespaces(), 2179 null, 2180 ((StaticQueryContext) env).getConstructionMode()); 2181 setLocation(el2, offset); 2182 if (content == null) { 2183 content = EmptySequence.getInstance(); 2184 } 2185 el2.setContentExpression(content); 2186 return makeTracer(offset, el2, Location.LITERAL_RESULT_ELEMENT, nameCode); 2188 case Token.ATTRIBUTE_QNAME: 2189 if (t.currentTokenValue.equals("xmlns") || t.currentTokenValue.startsWith("xmlns:")) { 2190 grumble("Cannot create a namespace using an attribute constructor"); 2191 } 2192 int attNameCode = makeNameCode(t.currentTokenValue, false); 2193 Expression attContent = null; 2194 nextToken(); 2195 if (t.currentToken != Token.RCURLY) { 2196 attContent = parseExpression(); 2197 expect(Token.RCURLY); 2198 } 2199 lookAhead(); nextToken(); 2201 FixedAttribute att2 = new FixedAttribute(attNameCode, 2202 Validation.STRIP, 2203 null, 2204 StandardNames.XDT_UNTYPED_ATOMIC); 2205 att2.setRejectDuplicates(); 2206 makeSimpleContent(attContent, att2, offset); 2207 return makeTracer(offset, att2, Location.LITERAL_RESULT_ATTRIBUTE, attNameCode); 2208 case Token.PI_QNAME: 2209 Expression piName = new StringValue(t.currentTokenValue); 2210 Expression piContent = null; 2211 nextToken(); 2212 if (t.currentToken != Token.RCURLY) { 2213 piContent = parseExpression(); 2214 expect(Token.RCURLY); 2215 } 2216 lookAhead(); nextToken(); 2218 ProcessingInstruction pi2 = new ProcessingInstruction(piName); 2219 makeSimpleContent(piContent, pi2, offset); 2220 return makeTracer(offset, pi2, StandardNames.XSL_PROCESSING_INSTRUCTION, -1); 2221 } 2222 return null; 2223 } 2224 2225 2231 2232 private void makeSimpleContent(Expression content, SimpleNodeConstructor inst, int offset) throws StaticError { 2233 try { 2234 if (content == null) { 2235 inst.setSelect(StringValue.EMPTY_STRING); 2236 } else { 2237 inst.setSelect(stringify(content, false)); 2238 } 2239 setLocation(inst, offset); 2240 } catch (XPathException e) { 2241 grumble(e.getMessage()); 2242 } 2243 } 2244 2245 2254 2268 2279 2280 private Expression parsePseudoXML(boolean allowEndTag) throws StaticError { 2281 Expression exp = null; 2282 int offset = t.inputOffset; 2283 char c = t.nextChar(); 2285 switch (c) { 2286 case '!': 2287 c = t.nextChar(); 2288 if (c == '-') { 2289 exp = parseCommentConstructor(); 2290 } else if (c == '[') { 2291 grumble("A CDATA section is allowed only in element content"); 2292 } else { 2294 grumble("Expected '--' or '[CDATA[' after '<!'"); 2295 } 2296 break; 2297 case '?': 2298 exp = parsePIConstructor(); 2299 break; 2300 case '/': 2301 if (allowEndTag) { 2302 FastStringBuffer sb = new FastStringBuffer(40); 2303 while (true) { 2304 c = t.nextChar(); 2305 if (c == '>') break; 2306 sb.append(c); 2307 } 2308 return new StringValue(sb); 2309 } 2310 grumble("Unmatched XML end tag"); 2311 break; 2312 default: 2313 t.unreadChar(); 2314 exp = parseDirectElementConstructor(); 2315 } 2316 setLocation(exp, offset); 2317 return exp; 2318 } 2319 2320 2325 2326 private Expression parseDirectElementConstructor() throws StaticError { 2327 int offset = t.inputOffset - 1; 2328 char c; 2330 FastStringBuffer buff = new FastStringBuffer(40); 2331 int namespaceCount = 0; 2332 while (true) { 2333 c = t.nextChar(); 2334 if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '/' || c == '>') { 2335 break; 2336 } 2337 buff.append(c); 2338 } 2339 String elname = buff.toString(); 2340 HashMap attributes = new HashMap(10); 2341 while (true) { 2342 c = skipSpaces(c); 2352 if (c == '/' || c == '>') { 2353 break; 2354 } 2355 int attOffset = t.inputOffset - 1; 2356 buff.setLength(0); 2357 while (true) { 2359 buff.append(c); 2360 c = t.nextChar(); 2361 if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '=') { 2362 break; 2363 } 2364 } 2365 String attName = buff.toString(); 2366 if (!Name.isQName(attName)) { 2367 grumble("Invalid attribute name " + Err.wrap(attName, Err.ATTRIBUTE)); 2368 } 2369 c = skipSpaces(c); 2370 expectChar(c, '='); 2371 c = t.nextChar(); 2372 c = skipSpaces(c); 2373 2374 Expression avt; 2375 try { 2376 avt = makeAttributeContent(t.input, t.inputOffset, c, true); 2377 } catch (StaticError err) { 2378 grumble(err.getMessage()); 2379 return null; 2380 } catch (XPathException err) { 2381 throw err.makeStatic(); 2382 } 2383 int end = (int) ((IntegerValue) avt).longValue(); 2385 String val = t.input.substring(t.inputOffset-1, end+1); 2387 String rval = t.input.substring(t.inputOffset, end); 2389 t.inputOffset = end + 1; 2390 c = t.nextChar(); 2392 if (!(c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '/' || c == '>')) { 2393 grumble("There must be whitespace after every attribute except the last"); 2394 } 2395 if ("xmlns".equals(attName) || attName.startsWith("xmlns:")) { 2396 if (rval.indexOf('{') >= 0) { 2397 grumble("Namespace URI must be a constant value", "XQST0022"); 2398 } 2399 String prefix, uri; 2400 if ("xmlns".equals(attName)) { 2401 prefix = ""; 2402 uri = rval; 2403 } else { 2404 prefix = attName.substring(6); 2405 if (prefix.equals("xml")) { 2406 grumble("Cannot redeclare the XML namespace", "XQST0070"); 2407 } else if (prefix.equals("xmlns")) { 2408 grumble("Cannot use xmlns as a namespace prefix", "XQST0070"); 2409 } 2410 uri = rval; 2411 if ("".equals(uri)) { 2412 grumble("Namespace URI must not be empty", "XQST0085"); 2413 } 2414 } 2415 namespaceCount++; 2416 ((StaticQueryContext) env).declareActiveNamespace(prefix, uri); 2417 } 2418 if (attributes.get(attName) != null) { 2419 if ("xmlns".equals(attName) || attName.startsWith("xmlns:")) { 2420 grumble("Duplicate namespace declaration " + attName, "XQST0071"); 2421 } else { 2422 grumble("Duplicate attribute name " + attName, "XQST0040"); 2423 } 2424 } 2425 if (attName.equals("xml:id") && !XMLChar.isValidNCName(val)) { 2426 grumble("Value of xml:id must be a valid NCName", "XQST0082"); 2427 } 2428 AttributeDetails a = new AttributeDetails(); 2429 a.value = val; 2430 a.startOffset = attOffset; 2431 attributes.put(attName, a); 2432 } 2433 String namespace; 2434 int elNameCode = 0; 2435 try { 2436 String [] parts = Name.getQNameParts(elname); 2437 namespace = ((StaticQueryContext) env).checkURIForPrefix(parts[0]); 2438 if (namespace == null) { 2439 grumble("Undeclared prefix in element name " + Err.wrap(elname, Err.ELEMENT)); 2440 } 2441 elNameCode = env.getNamePool().allocate(parts[0], namespace, parts[1]); 2442 } catch (QNameException e) { 2443 grumble("Invalid element name " + Err.wrap(elname, Err.ELEMENT)); 2444 } 2445 int validationMode = ((StaticQueryContext) env).getConstructionMode(); 2446 FixedElement elInst = new FixedElement( 2447 elNameCode, 2448 ((StaticQueryContext) env).getActiveNamespaceCodes(), 2449 ((StaticQueryContext) env).isInheritNamespaces(), 2450 null, 2451 validationMode); 2452 2453 setLocation(elInst, offset); 2454 2455 List contents = new ArrayList(10); 2456 2457 HashSet attFingerprints = new HashSet(attributes.size()); 2458 for (Iterator iter = attributes.keySet().iterator(); iter.hasNext();) { 2460 String attName = (String ) iter.next(); 2461 AttributeDetails a = (AttributeDetails) attributes.get(attName); 2462 String attValue = a.value; 2463 int attOffset = a.startOffset; 2464 2465 if ("xmlns".equals(attName) || attName.startsWith("xmlns:")) { 2466 } else if (scanOnly) { 2468 } else { 2474 int attNameCode = 0; 2475 String attNamespace; 2476 try { 2477 String [] parts = Name.getQNameParts(attName); 2478 if ("".equals(parts[0])) { 2479 attNamespace = ""; 2481 } else { 2482 attNamespace = ((StaticQueryContext) env).checkURIForPrefix(parts[0]); 2483 } 2484 if (attNamespace == null) { 2485 grumble("Undeclared prefix in attribute name " + Err.wrap(attName, Err.ATTRIBUTE)); 2486 } 2487 attNameCode = env.getNamePool().allocate(parts[0], attNamespace, parts[1]); 2488 Integer key = new Integer (attNameCode & NamePool.FP_MASK); 2489 if (attFingerprints.contains(key)) { 2490 grumble("Duplicate expanded attribute name " + attName, "XQST0040"); 2491 } 2492 attFingerprints.add(key); 2493 } catch (QNameException e) { 2494 grumble("Invalid attribute name " + Err.wrap(attName, Err.ATTRIBUTE)); 2495 } 2496 2497 FixedAttribute attInst = 2498 new FixedAttribute(attNameCode, Validation.STRIP, null, StandardNames.XDT_UNTYPED_ATOMIC); 2499 2500 setLocation(attInst); 2501 Expression select; 2502 try { 2503 select = makeAttributeContent(attValue, 1, attValue.charAt(0), false); 2504 } catch (XPathException err) { 2505 throw err.makeStatic(); 2506 } 2507 attInst.setSelect(select); 2508 attInst.setRejectDuplicates(); 2509 setLocation(attInst); 2510 contents.add(makeTracer(attOffset, attInst, Location.LITERAL_RESULT_ATTRIBUTE, attNameCode)); 2511 } 2512 } 2513 if (c == '/') { 2514 expectChar(t.nextChar(), '>'); 2516 } else { 2517 readElementContent(elname, contents); 2518 } 2519 2520 Expression[] elk = new Expression[contents.size()]; 2521 for (int i = 0; i < contents.size(); i++) { 2522 if (validationMode != Validation.STRIP && 2526 contents.get(i) instanceof ElementCreator && 2527 ((ElementCreator) contents.get(i)).getValidationMode() == validationMode) { 2528 ((ElementCreator) contents.get(i)).setValidationMode(Validation.PRESERVE); 2529 } 2530 elk[i] = (Expression) contents.get(i); 2531 } 2532 Block block = new Block(); 2533 block.setChildren(elk); 2534 elInst.setContentExpression(block); 2535 2536 2538 for (int n = 0; n < namespaceCount; n++) { 2539 ((StaticQueryContext) env).undeclareNamespace(); 2540 } 2541 2542 return makeTracer(offset, elInst, Location.LITERAL_RESULT_ELEMENT, elNameCode); 2543 } 2544 2545 2555 2556 private Expression makeAttributeContent(String avt, 2557 int start, 2558 char terminator, 2559 boolean scanOnly) throws XPathException { 2560 2561 int lineNumber = t.getLineNumber(); 2562 List components = new ArrayList(10); 2563 2564 int i0, i1, i2, i8, i9, len, last; 2565 last = start; 2566 len = avt.length(); 2567 while (last < len) { 2568 i2 = avt.indexOf(terminator, last); 2569 if (i2 < 0) { 2570 throw new StaticError("Attribute constructor is not properly terminated"); 2571 } 2572 2573 i0 = avt.indexOf("{", last); 2574 i1 = avt.indexOf("{{", last); 2575 i8 = avt.indexOf("}", last); 2576 i9 = avt.indexOf("}}", last); 2577 2578 if ((i0 < 0 || i2 < i0) && (i8 < 0 || i2 < i8)) { addStringComponent(components, avt, last, i2); 2580 2581 if (i2+1 < avt.length() && avt.charAt(i2+1)==terminator) { 2583 components.add(new StringValue(terminator + "")); 2584 last = i2+2; 2585 continue; 2586 } else { 2587 last = i2; 2588 break; 2589 } 2590 } else if (i8 >= 0 && (i0 < 0 || i8 < i0)) { if (i8 != i9) { throw new StaticError( 2593 "Closing curly brace in attribute value template \"" + avt + "\" must be doubled"); 2594 } 2595 addStringComponent(components, avt, last, i8 + 1); 2596 last = i8 + 2; 2597 } else if (i1 >= 0 && i1 == i0) { addStringComponent(components, avt, last, i1 + 1); 2599 last = i1 + 2; 2600 } else if (i0 >= 0) { if (i0 > last) { 2602 addStringComponent(components, avt, last, i0); 2603 } 2604 Expression exp; 2605 ExpressionParser parser; 2606 parser = new QueryParser(); 2607 parser.setScanOnly(scanOnly); 2608 if (rangeVariables != null) { 2609 parser.setRangeVariableStack(rangeVariables); 2610 } 2611 exp = parser.parse(avt, i0 + 1, Token.RCURLY, lineNumber, env); 2612 if (!scanOnly) { 2613 exp = exp.simplify(env); 2614 } 2615 last = parser.getTokenizer().currentTokenStartOffset + 1; 2616 components.add(makeStringJoin(exp, env)); 2617 2618 } else { 2619 throw new IllegalStateException ("Internal error parsing direct attribute constructor"); 2620 } 2621 } 2622 2623 2626 if (scanOnly) { 2627 return new IntegerValue(last); 2628 } 2629 2630 2632 if (components.size() == 0) { 2633 return StringValue.EMPTY_STRING; 2634 } 2635 2636 2638 if (components.size() == 1) { 2639 return ((Expression) components.get(0)).simplify(env); 2640 } 2641 2642 2644 Concat fn = (Concat) SystemFunction.makeSystemFunction("concat", components.size(), env.getNamePool()); 2645 Expression[] args = new Expression[components.size()]; 2646 components.toArray(args); 2647 fn.setArguments(args); 2648 fn.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), lineNumber)); 2649 return fn.simplify(env); 2650 2651 } 2652 2653 private void addStringComponent(List components, String avt, int start, int end) 2654 throws XPathException { 2655 if (start < end) { 2657 FastStringBuffer sb = new FastStringBuffer(end - start); 2658 for (int i = start; i < end; i++) { 2659 char c = avt.charAt(i); 2660 switch (c) { 2661 case '&': { 2662 int semic = avt.indexOf(';', i); 2663 if (semic < 0) { 2664 grumble("No closing ';' found for entity or character reference"); 2665 } else { 2666 String entity = avt.substring(i + 1, semic); 2667 sb.append(analyzeEntityReference(entity)); 2668 i = semic; 2669 } 2670 break; 2671 } 2672 case '<': 2673 grumble("The < character must not appear in attribute content"); 2674 break; 2675 case '\n': 2676 case '\t': 2677 sb.append(' '); 2678 break; 2679 case '\r': 2680 sb.append(' '); 2681 if (i+1 < end && avt.charAt(i+1) == '\n') { 2682 i++; 2683 } 2684 break; 2685 default: 2686 sb.append(c); 2687 2688 } 2689 } 2690 components.add(StringValue.makeStringValue(sb)); 2691 } 2692 } 2693 2694 2700 private void readElementContent(String startTag, List components) throws StaticError { 2701 try { 2702 boolean afterRightCurly = false; 2703 boolean afterEnclosedExpr = false; 2704 while (true) { 2705 FastStringBuffer text = new FastStringBuffer(256); 2707 char c; 2708 boolean containsEntities = false; 2709 while (true) { 2710 c = t.nextChar(); 2711 if (c == '<') { 2712 if (t.nextChar() == '!') { 2714 if (t.nextChar() == '[') { 2715 readCDATASection(text); 2716 containsEntities = true; 2717 continue; 2718 } else { 2719 t.unreadChar(); 2720 t.unreadChar(); 2721 } 2722 } else { 2723 t.unreadChar(); 2724 } 2725 break; 2726 } else if (c == '&') { 2727 text.append(readEntityReference()); 2728 containsEntities = true; 2729 } else if (c == '}') { 2730 c = t.nextChar(); 2731 if (c != '}') { 2732 grumble("'}' must be written as '}}' within element content"); 2733 } 2734 text.append(c); 2735 } else if (c == '{') { 2736 c = t.nextChar(); 2737 if (c != '{') { 2738 c = '{'; 2739 break; 2740 } 2741 text.append(c); 2742 } else { 2743 text.append(c); 2744 } 2745 afterRightCurly = false; 2746 } 2747 if (text.length() > 0 && 2748 (containsEntities | preserveSpace | !Whitespace.isWhite(text))) { 2749 ValueOf inst = new ValueOf(new StringValue(text.condense()), false, false); 2750 setLocation(inst); 2751 components.add(inst); 2752 afterEnclosedExpr = false; 2753 } 2754 if (c == '<') { 2755 Expression exp = parsePseudoXML(true); 2756 if (exp instanceof StringValue) { 2758 String endTag = ((StringValue) exp).getStringValue().trim(); 2759 if (endTag.equals(startTag)) { 2760 return; 2761 } else { 2762 grumble("end tag </" + endTag + 2763 "> does not match start tag <" + startTag + '>'); 2764 } 2765 } else { 2766 components.add(exp); 2767 } 2768 afterRightCurly = false; 2769 } else { 2770 if (afterEnclosedExpr) { 2772 Expression previousComponent = (Expression)components.get(components.size()-1); 2773 ItemType previousItemType = previousComponent.getItemType(); 2774 if (!(previousItemType instanceof NodeTest)) { 2775 ValueOf inst = new ValueOf(StringValue.EMPTY_STRING, false, false); 2778 setLocation(inst); 2779 components.add(inst); 2780 } 2781 } 2782 t.unreadChar(); 2783 t.setState(Tokenizer.DEFAULT_STATE); 2784 lookAhead(); 2785 nextToken(); 2786 Expression exp = parseExpression(); 2787 if (!((StaticQueryContext)env).isPreserveNamespaces()) { 2788 exp = new CopyOf(exp, false, Validation.PRESERVE, null, true); 2789 } 2790 components.add(exp); 2791 expect(Token.RCURLY); 2792 afterRightCurly = true; 2793 afterEnclosedExpr = true; 2794 } 2795 } 2796 } catch (StringIndexOutOfBoundsException err) { 2797 grumble("No closing end tag found for direct element constructor"); 2798 } 2799 } 2800 2801 private Expression parsePIConstructor() throws StaticError { 2802 try { 2803 FastStringBuffer pi = new FastStringBuffer(120); 2804 int firstSpace = -1; 2805 while (!pi.toString().endsWith("?>")) { 2806 char c = t.nextChar(); 2807 if (firstSpace < 0 && " \t\r\n".indexOf(c) >= 0) { 2808 firstSpace = pi.length(); 2809 } 2810 pi.append(c); 2811 } 2812 pi.setLength(pi.length() - 2); 2813 2814 String target; 2815 String data = ""; 2816 if (firstSpace < 0) { 2817 target = pi.toString(); 2819 } else { 2820 target = pi.toString().substring(0, firstSpace); 2822 firstSpace++; 2823 while (firstSpace < pi.length() && " \t\r\n".indexOf(pi.charAt(firstSpace)) >= 0) { 2824 firstSpace++; 2825 } 2826 data = pi.toString().substring(firstSpace); 2827 } 2828 2829 if (!XMLChar.isValidNCName(target)) { 2830 grumble("Invalid processing instruction name " + Err.wrap(target)); 2831 } 2832 2833 ProcessingInstruction instruction = 2834 new ProcessingInstruction(new StringValue(target)); 2835 instruction.setSelect(StringValue.makeStringValue(data)); 2836 setLocation(instruction); 2837 return instruction; 2838 } catch (StringIndexOutOfBoundsException err) { 2839 grumble("No closing '?>' found for processing instruction"); 2840 return null; 2841 } 2842 } 2843 2844 private void readCDATASection(FastStringBuffer cdata) throws StaticError { 2845 try { 2846 char c; 2847 c = t.nextChar(); 2849 expectChar(c, 'C'); 2850 c = t.nextChar(); 2851 expectChar(c, 'D'); 2852 c = t.nextChar(); 2853 expectChar(c, 'A'); 2854 c = t.nextChar(); 2855 expectChar(c, 'T'); 2856 c = t.nextChar(); 2857 expectChar(c, 'A'); 2858 c = t.nextChar(); 2859 expectChar(c, '['); 2860 while (!cdata.toString().endsWith("]]>")) { 2861 cdata.append(t.nextChar()); 2862 } 2863 cdata.setLength(cdata.length() - 3); 2864 } catch (StringIndexOutOfBoundsException err) { 2865 grumble("No closing ']]>' found for CDATA section"); 2866 } 2867 } 2868 2869 private Expression parseCommentConstructor() throws StaticError { 2870 try { 2871 char c = t.nextChar(); 2872 ; 2873 expectChar(c, '-'); 2875 FastStringBuffer comment = new FastStringBuffer(240); 2876 while (!comment.toString().endsWith("--")) { 2877 comment.append(t.nextChar()); 2878 } 2879 if (t.nextChar() != '>') { 2880 grumble("'--' is not permitted in an XML comment"); 2881 } 2882 CharSequence commentText = comment.subSequence(0, comment.length() - 2); 2883 Comment instruction = new Comment(); 2884 instruction.setSelect(new StringValue(commentText)); 2885 setLocation(instruction); 2886 return instruction; 2887 } catch (StringIndexOutOfBoundsException err) { 2888 grumble("No closing '-->' found for comment constructor"); 2889 return null; 2890 } 2891 } 2892 2893 2894 2902 2903 private Expression stringify(Expression exp, boolean noNodeIfEmpty) throws XPathException { 2904 return new QuerySimpleContentConstructor(exp, StringValue.SINGLE_SPACE, noNodeIfEmpty).simplify(env); 2905 } 2906 2907 2915 2916 protected StringValue makeStringLiteral(String token) throws StaticError { 2917 if (token.indexOf('&') == -1) { 2918 return StringValue.makeStringValue(token); 2919 } else { 2920 FastStringBuffer sb = new FastStringBuffer(80); 2921 for (int i = 0; i < token.length(); i++) { 2922 char c = token.charAt(i); 2923 if (c == '&') { 2924 int semic = token.indexOf(';', i); 2925 if (semic < 0) { 2926 grumble("No closing ';' found for entity or character reference"); 2927 } else { 2928 String entity = token.substring(i + 1, semic); 2929 sb.append(analyzeEntityReference(entity)); 2930 i = semic; 2931 } 2932 } else { 2933 sb.append(c); 2934 } 2935 } 2936 return StringValue.makeStringValue(sb); 2937 } 2938 } 2939 2940 2947 2948 private String readEntityReference() throws StaticError { 2949 try { 2950 FastStringBuffer sb = new FastStringBuffer(40); 2951 while (true) { 2952 char c = t.nextChar(); 2953 if (c == ';') break; 2954 sb.append(c); 2955 } 2956 String entity = sb.toString(); 2957 return analyzeEntityReference(entity); 2958 } catch (StringIndexOutOfBoundsException err) { 2959 grumble("No closing ';' found for entity or character reference"); 2960 } 2961 return null; } 2963 2964 private String analyzeEntityReference(String entity) throws StaticError { 2965 if ("lt".equals(entity)) { 2966 return "<"; 2967 } else if ("gt".equals(entity)) { 2968 return ">"; 2969 } else if ("amp".equals(entity)) { 2970 return "&"; 2971 } else if ("quot".equals(entity)) { 2972 return "\""; 2973 } else if ("apos".equals(entity)) { 2974 return "'"; 2975 } else if (entity.length() < 2 || entity.charAt(0) != '#') { 2976 grumble("invalid entity reference &" + entity + ';'); 2977 return null; 2978 } else { 2979 entity = entity.toLowerCase(); 2980 return parseCharacterReference(entity); 2981 } 2982 } 2983 2984 private String parseCharacterReference(String entity) throws StaticError { 2985 int value = 0; 2986 if (entity.charAt(1) == 'x') { 2987 for (int i = 2; i < entity.length(); i++) { 2988 int digit = "0123456789abcdef".indexOf(entity.charAt(i)); 2989 if (digit < 0) { 2990 grumble("invalid character '" + entity.charAt(i) + "' in hex character reference"); 2991 } 2992 value = (value * 16) + digit; 2993 } 2994 } else { 2995 for (int i = 1; i < entity.length(); i++) { 2996 int digit = "0123456789".indexOf(entity.charAt(i)); 2997 if (digit < 0) { 2998 grumble("invalid character '" + entity.charAt(i) + "' in decimal character reference"); 2999 } 3000 value = (value * 10) + digit; 3001 } 3002 } 3003 if ((value < 0x0020 3006 && !(value == '\n' || value == '\t' || value == '\r')) 3007 || (value >= 0xD800 && value <= 0xDFFF) 3008 || value == 0xFFFE || value == 0xFFFF 3009 || value > 0x0010ffff) 3010 grumble("Invalid XML character reference x" 3011 + Integer.toHexString(value)); 3012 3013 if (value <= 0x0000ffff) { 3016 return "" + (char) value; 3018 } else if (value <= 0x0010ffff) { 3019 value -= 0x10000; 3020 return "" + ((char) (0xd800 | (value >> 10))) 3022 + ((char) (0xdc00 | (value & 0x0003ff))); 3023 } else { 3024 grumble("Character reference x" + Integer.toHexString(value) + " is too large"); 3026 } 3027 return null; 3028 } 3029 3030 3035 3036 private void lookAhead() throws StaticError { 3037 try { 3038 t.lookAhead(); 3039 } catch (XPathException err) { 3040 grumble(err.getMessage()); 3041 } 3042 } 3043 3044 3049 3050 private char skipSpaces(char c) { 3051 while (c == ' ' || c == '\n' || c == '\r' || c == '\t') { 3052 c = t.nextChar(); 3053 } 3054 return c; 3055 } 3056 3057 3063 3064 private void expectChar(char actual, char expected) throws StaticError { 3065 if (actual != expected) { 3066 grumble("Expected '" + expected + "', found '" + actual + '\''); 3067 } 3068 } 3069 3070 3073 3074 protected String getLanguage() { 3075 return "XQuery"; 3076 } 3077 3078 private static class AttributeDetails { 3079 String value; 3080 int startOffset; 3081 } 3082} 3083 3084 | Popular Tags |