1 28 29 package com.caucho.xsl.java; 30 31 import com.caucho.java.JavaWriter; 32 import com.caucho.log.Log; 33 import com.caucho.util.CharBuffer; 34 import com.caucho.util.CompileException; 35 import com.caucho.util.L10N; 36 import com.caucho.util.LineCompileException; 37 import com.caucho.xml.QName; 38 import com.caucho.xml.XmlChar; 39 import com.caucho.xpath.Expr; 40 import com.caucho.xpath.NamespaceContext; 41 import com.caucho.xpath.XPath; 42 import com.caucho.xpath.expr.NumericExpr; 43 import com.caucho.xpath.pattern.*; 44 import com.caucho.xsl.JavaGenerator; 45 import com.caucho.xsl.XslParseException; 46 47 import java.io.IOException ; 48 import java.util.ArrayList ; 49 import java.util.logging.Logger ; 50 51 54 public abstract class XslNode { 55 static final L10N L = new L10N(XslNode.class); 56 static final Logger log = Log.open(XslNode.class); 57 58 protected String _systemId; 59 protected String _filename; 60 protected int _startLine; 61 protected int _endLine; 62 63 protected JavaGenerator _gen; 64 65 protected QName _name; 66 protected XslNode _parent; 67 68 protected ArrayList <XslNode> _children; 69 protected NamespaceContext _matchNamespace; 70 protected NamespaceContext _outputNamespace; 71 72 private int _varCount; 73 74 protected XslNode() 75 { 76 } 77 78 81 public void setGenerator(JavaGenerator gen) 82 { 83 _gen = gen; 84 } 85 86 89 public QName getQName() 90 { 91 return _name; 92 } 93 94 97 public void setQName(QName name) 98 { 99 _name = name; 100 } 101 102 105 public String getTagName() 106 { 107 if (_name != null) 108 return _name.getName(); 109 else 110 return getClass().getName(); 111 } 112 113 116 public XslNode getParent() 117 { 118 return _parent; 119 } 120 121 124 public void setParent(XslNode parent) 125 { 126 _parent = parent; 127 128 if (parent != null) { 129 _matchNamespace = parent.getMatchNamespace(); 130 _outputNamespace = parent.getOutputNamespace(); 131 } 132 } 133 134 137 public void addVariableCount() 138 { 139 if (_parent != null) 140 _parent._varCount++; 141 } 142 143 146 public void setStartLocation(String systemId, String filename, int line) 147 { 148 _systemId = systemId; 149 _filename = filename; 150 _startLine = line; 151 } 152 153 156 public void setEndLocation(String filename, int line) 157 { 158 if (_filename != null && _filename.equals(filename)) 159 _endLine = line; 160 } 161 162 165 public String getSystemId() 166 { 167 return _systemId; 168 } 169 170 173 public String getFilename() 174 { 175 return _filename; 176 } 177 178 181 public int getStartLine() 182 { 183 return _startLine; 184 } 185 186 189 public int getEndLine() 190 { 191 return _endLine; 192 } 193 194 197 public String getBaseURI() 198 { 199 return _filename; 200 } 201 202 205 public NamespaceContext getMatchNamespace() 206 { 207 return _matchNamespace; 208 } 209 210 213 public NamespaceContext getOutputNamespace() 214 { 215 return _outputNamespace; 216 } 217 218 221 public String getNamespace(String prefix) 222 { 223 return NamespaceContext.find(getOutputNamespace(), prefix); 224 } 225 226 229 public void addAttribute(QName name, String value) 230 throws XslParseException 231 { 232 if (name.getName().startsWith("xmlns")) { 233 addNamespaceAttribute(name, value); 234 return; 235 } 236 237 if (name.getName().startsWith("xml")) 238 return; 239 240 throw error(L.l("attribute `{0}' is not allowed in <{1}>.", 241 name.getName(), getTagName())); 242 } 243 244 247 protected void addNamespaceAttribute(QName name, String url) 248 throws XslParseException 249 { 250 252 259 260 String localName = name.getLocalName(); 261 262 263 _outputNamespace = new NamespaceContext(_outputNamespace, localName, url); 264 265 if (! localName.equals("xmlns")) { 266 _matchNamespace = new NamespaceContext(_matchNamespace, localName, url); 268 } 269 } 270 271 274 public void endAttributes() 275 throws XslParseException 276 { 277 } 278 279 282 public void addText(String text) 283 throws XslParseException 284 { 285 for (int i = 0; i < text.length(); i++) { 286 char ch = text.charAt(i); 287 288 if (! XmlChar.isWhitespace(ch)) 289 throw error(L.l("Text is not allowed in <{0}> at `{1}'.", 290 _name.getName(), text)); 291 } 292 } 293 294 297 public void addChild(XslNode node) 298 throws XslParseException 299 { 300 if (node == null) 301 return; 302 303 if (_children == null) 304 _children = new ArrayList <XslNode>(); 305 306 _children.add(node); 307 } 308 309 312 public void endElement() 313 throws Exception 314 { 315 } 316 317 320 public ArrayList <XslNode> getChildren() 321 { 322 return _children; 323 } 324 325 328 public boolean hasChildren() 329 { 330 return _children != null && _children.size() > 0; 331 } 332 333 338 abstract public void generate(JavaWriter out) 339 throws Exception ; 340 341 346 public void generateChildren(JavaWriter out) 347 throws Exception 348 { 349 if (_children == null) 350 return; 351 352 for (int i = 0; i < _children.size(); i++) { 353 XslNode child = _children.get(i); 354 355 out.setLocation(child.getFilename(), child.getStartLine()); 356 357 child.generate(out); 358 } 359 360 popScope(out); 361 } 362 363 368 public void generateDeclaration(JavaWriter out) 369 throws Exception 370 { 371 generateDeclarationChildren(out); 372 } 373 374 379 public void generateDeclarationChildren(JavaWriter out) 380 throws Exception 381 { 382 if (_children == null) 383 return; 384 385 for (int i = 0; i < _children.size(); i++) { 386 XslNode child = _children.get(i); 387 388 child.generateDeclaration(out); 389 } 390 } 391 392 395 protected void printAttributeValue(JavaWriter out, String name, String value) 396 throws Exception 397 { 398 out.print("out.attribute("); 399 out.print(name == null ? "null" : ("\"" + name + "\"")); 400 out.print(", "); 401 if (value == null) 402 out.print("null"); 403 else { 404 out.print("\""); 405 out.printJavaString(value); 406 out.print("\""); 407 } 408 out.println(");"); 409 } 410 411 414 protected void printAttributeValue(JavaWriter out, String value) 415 throws Exception 416 { 417 if (value == null) { 418 out.print("null"); 419 return; 420 } 421 422 if (value.indexOf("{") < 0) { 423 out.print("\""); 424 out.printJavaString(value); 425 out.print("\""); 426 } 427 else { 428 generateString(out, value); 429 } 430 } 431 432 441 void generateString(JavaWriter out, String string) 442 throws Exception 443 { 444 int i = 0; 445 boolean first = true; 446 int length = string.length(); 447 CharBuffer cb = CharBuffer.allocate(); 448 449 for (; i < length; i++) { 450 char ch = string.charAt(i); 451 452 if (ch == '\n') { 453 cb.append("\\n"); 454 } 455 else if (ch == '"') { 456 cb.append("\\\""); 457 } 458 else if (ch == '{' && i + 1 < length) { 459 if (string.charAt(i + 1) == '{') { 461 cb.append('{'); 462 i++; 463 } 464 else { 466 if (cb.length() > 0) { 468 out.print("out.print(\""); 469 out.printJavaString(cb.toString()); 470 out.println("\");"); 471 } 472 473 cb.clear(); 475 for (i++; i < length && string.charAt(i) != '}'; i++) 476 cb.append(string.charAt(i)); 477 478 printStringExpr(out, cb.toString()); 479 480 cb.clear(); 481 first = false; 482 } 483 } 484 else if (ch == '}' && i + 1 < length) { 486 if (string.charAt(i + 1) == '}') { 487 cb.append('}'); 488 i++; 489 } 490 else 491 cb.append('}'); 492 } 493 else if (i + 2 < length && ch == '<' && 495 string.charAt(i + 1) == '#' && 496 string.charAt(i + 2) == '=') { 497 if (cb.length() > 0) { 499 out.print("out.print(\""); 500 out.printJavaString(cb.toString()); 501 out.println("\");"); 502 } 503 504 cb.clear(); 506 for (i += 3; 507 i + 1 < length && string.charAt(i) != '#' && 508 string.charAt(i + 1) != '>'; 509 i++) 510 cb.append(string.charAt(i)); 511 512 i++; 513 514 out.println("out.print(" + cb + ");"); 516 517 cb.clear(); 518 first = false; 519 } 520 else 521 cb.append((char) ch); 522 } 523 524 if (cb.length() > 0) 526 out.println("out.print(\"" + cb + "\");"); 527 } 528 529 538 void generateString(JavaWriter out, String string, int mode) 539 throws Exception 540 { 541 CharBuffer cb = new CharBuffer(); 542 int i = 0; 543 boolean first = true; 544 int length = string.length(); 545 546 for (; i < length; i++) { 547 char ch = string.charAt(i); 548 549 if (ch == '\n') { 550 cb.append("\\n"); 551 } 552 else if (ch == '"') { 553 cb.append("\\\""); 554 } 555 else if (ch == '{' && i + 1 < length) { 556 if (string.charAt(i + 1) == '{') { 558 cb.append('{'); 559 i++; 560 } 561 else { 563 if (mode == ',') { 565 if (cb.length() > 0) 566 out.println("out.print(\"" + cb.toString() + "\");"); 567 } 568 else { 569 if (! first) 570 out.print((char) mode); 571 572 if (cb.length() > 0) { 573 out.print("\""); 574 out.print(cb.toString()); 575 out.print("\""); 576 out.print((char) mode); 577 } 578 } 579 580 cb.clear(); 582 for (i++; i < length && string.charAt(i) != '}'; i++) 583 cb.append(string.charAt(i)); 584 585 if (mode == ',') 587 printStringExpr(out, cb.toString()); 588 else 589 stringExpr(out, cb.toString()); 590 cb.clear(); 591 first = false; 592 } 593 } 594 else if (ch == '}' && i + 1 < length) { 596 if (string.charAt(i + 1) == '}') { 597 cb.append('}'); 598 i++; 599 } 600 else 601 cb.append('}'); 602 } 603 else if (i + 2 < length && ch == '<' && 605 string.charAt(i + 1) == '#' && 606 string.charAt(i + 2) == '=') { 607 if (mode == ',') { 609 if (cb.length() > 0) 610 out.println("out.print(\"" + cb.toString() + "\");"); 611 } 612 else { 613 if (! first) 614 out.print((char) mode); 615 616 if (cb.length() > 0) { 617 out.print("\""); 618 out.print(cb.toString()); 619 out.print("\""); 620 out.print((char) mode); 621 } 622 } 623 624 cb.clear(); 626 for (i += 3; 627 i + 1 < length && string.charAt(i) != '#' && 628 string.charAt(i + 1) != '>'; 629 i++) 630 cb.append(string.charAt(i)); 631 632 i++; 633 634 if (mode == ',') 636 out.println("out.print(" + cb + ");"); 637 else { 638 out.print("(" + cb + ")"); 639 } 640 cb.clear(); 641 first = false; 642 } 643 else 644 cb.append((char) ch); 645 } 646 647 if (cb.length() > 0) { 649 if (mode == ',') 650 out.println("out.print(\"" + cb + "\");"); 651 else { 652 if (! first) 653 out.print((char) mode); 654 655 out.print("\"" + cb + "\""); 656 } 657 } else if (first && mode == '+') 658 out.print("\"\""); 659 } 660 661 664 protected void printStringExpr(JavaWriter out, String exprString) 665 throws Exception 666 { 667 if (exprString == null) 668 return; 669 670 int length = exprString.length(); 671 672 if (length == 0) 673 return; 674 675 AbstractPattern select = null; 676 try { 677 select = parseSelect(exprString); 678 } catch (Exception e) { 679 } 681 682 if (exprString.equals(".")) { 683 out.println("out.valueOf(node);"); 684 return; 685 } 686 else if (exprString.charAt(0) == '@') { 687 boolean isSimple = true; 688 689 for (int i = 1; i < length; i++) { 690 char ch = exprString.charAt(i); 691 if (! XmlChar.isNameChar(ch) || ch == ':') 692 isSimple = false; 693 } 694 695 if (isSimple) { 696 out.println("if (node instanceof Element)"); 697 out.print(" out.print(((Element) node).getAttribute(\""); 698 out.print(exprString.substring(1)); 699 out.println("\"));"); 700 return; 701 } 702 } 703 else if (allowJavaSelect(select)) { 704 int oldSelectDepth = _gen.getSelectDepth(); 705 706 String loop = "_xsl_loop" + _gen.generateId(); 707 _gen.setSelectLoopDepth(0); 708 709 String ptr = printSelectBegin(out, select, true, loop); 710 711 out.println("out.valueOf(" + ptr + ");"); 712 out.println("break " + loop + ";"); 713 714 int selectDepth = _gen.getSelectDepth(); 715 for (; oldSelectDepth < selectDepth; selectDepth--) { 716 out.popDepth(); 717 out.println("}"); 718 } 719 _gen.setSelectDepth(oldSelectDepth); 720 721 return; 722 } 723 724 out.println("out.valueOf(_exprs[" + addExpr(exprString) + 725 "].evalObject(node, " + _gen.getEnv() + "));"); 726 } 727 728 protected void stringExpr(JavaWriter out, String exprString) 729 throws Exception , XslParseException 730 { 731 out.print("_exprs[" + _gen.addExpr(parseExpr(exprString)) + 732 "].evalString(node, " + getEnv() + ")"); 733 } 734 735 protected void pushCall(JavaWriter out) 736 throws IOException 737 { 738 out.println("{"); 739 out.pushDepth(); 740 741 int callDepth = _gen.pushCallDepth(); 742 743 out.println("Env _xsl_arg" + callDepth + " = XPath.createCall(env);"); 744 } 745 746 protected void popCall(JavaWriter out) 747 throws IOException 748 { 749 int callDepth = _gen.popCallDepth(); 750 out.println("_xsl_arg" + callDepth + ".free();"); 751 752 out.popDepth(); 753 out.println("}"); 754 } 755 756 759 protected String printSelectBegin(JavaWriter out, 760 AbstractPattern select, 761 boolean isForEach, String loopVar) 762 throws IOException , XslParseException 763 { 764 if (select == null) 765 throw new NullPointerException (); 766 767 if (select instanceof FromContext && 768 ((FromContext) select).getCount() == 0) 769 return "node"; 770 771 else if (select instanceof FromRoot) 772 return "ownerDocument(node)"; 773 774 boolean useXPath = allowJavaSelect(select); 775 776 String name = "node"; 777 778 if (! useXPath) { 779 String iterName = "_xsl_iter" + _gen.generateId(); 781 782 String ptrName = "_xsl_ptr" + _gen.generateId(); 783 784 if (isForEach) 785 out.println("env.setCurrentNode(node);"); 786 787 out.println("Iterator " + iterName + " = _select_patterns[" + 788 _gen.addSelect(select) + "].select(" + name + ", env);"); 789 790 if (loopVar != null && _gen.getSelectLoopDepth() == 0) 791 out.println(loopVar + ":"); 792 793 out.println("while (" + iterName + ".hasNext()) {"); 794 out.pushDepth(); 795 _gen.pushSelectDepth(); 796 _gen.pushSelectLoopDepth(); 797 out.println("Node " + ptrName + " = (Node) " + iterName + ".next();"); 798 799 return ptrName; 800 } 801 802 if (select instanceof FromChildren) { 803 name = printSelectBegin(out, select.getParent(), isForEach, loopVar); 804 805 String ptrName = "_xsl_ptr" + _gen.generateId(); 806 807 if (loopVar != null && _gen.getSelectLoopDepth() == 0) 808 out.println(loopVar + ":"); 809 810 out.println("for (Node " + ptrName + " = " + name + ".getFirstChild();"); 811 out.println(" " + ptrName + " != null;"); 812 out.println(" " + ptrName + " = " + ptrName + ".getNextSibling()) {"); 813 out.pushDepth(); 814 _gen.pushSelectDepth(); 815 _gen.pushSelectLoopDepth(); 816 817 return ptrName; 818 } 819 else if (select instanceof FromNextSibling) { 820 name = printSelectBegin(out, select.getParent(), isForEach, loopVar); 821 822 String ptrName = "_xsl_ptr" + _gen.generateId(); 823 824 if (loopVar != null && _gen.getSelectLoopDepth() == 0) 825 out.println(loopVar + ":"); 826 827 out.println("for (Node " + ptrName + " = " + name + ".getNextSibling();"); 828 out.println(" " + ptrName + " != null;"); 829 out.println(" " + ptrName + " = " + ptrName + ".getNextSibling()) {"); 830 out.pushDepth(); 831 _gen.pushSelectDepth(); 832 _gen.pushSelectLoopDepth(); 833 834 return ptrName; 835 } 836 else if (select instanceof NodePattern) { 837 name = printSelectBegin(out, select.getParent(), isForEach, loopVar); 838 839 NodePattern pat = (NodePattern) select; 840 841 out.println("if (" + name + ".getNodeName() == \"" + pat.getNodeName() + "\" &&"); 842 out.println(" " + name + " instanceof Element) {"); 843 out.pushDepth(); 844 _gen.pushSelectDepth(); 845 846 return name; 847 } 848 else if (select instanceof NodeTypePattern) { 849 name = printSelectBegin(out, select.getParent(), isForEach, loopVar); 850 851 NodeTypePattern pat = (NodeTypePattern) select; 852 853 if (pat.getNodeType() >= 0) { 854 out.println("if (" + name + ".getNodeType() == " + pat.getNodeType() + ") {"); 855 out.pushDepth(); 856 _gen.pushSelectDepth(); 857 } 858 859 return name; 860 } 861 else if (select instanceof FilterPattern) { 862 String posId = "_xsl_pos" + _gen.generateId(); 863 864 out.println("int " + posId + " = 0;"); 865 866 name = printSelectBegin(out, select.getParent(), isForEach, loopVar); 867 868 out.println(posId + "++;"); 869 870 FilterPattern pat = (FilterPattern) select; 871 Expr expr = pat.getExpr(); 872 873 if (expr instanceof NumericExpr) { 874 NumericExpr num = (NumericExpr) expr; 875 if (num.isConstant()) { 876 out.println("if (" + posId + " > " + (int) num.getValue() + ")"); 877 out.println(" break;"); 878 out.println("else if (" + posId + " == " + (int) num.getValue() + ") {"); 879 out.pushDepth(); 880 _gen.pushSelectDepth(); 881 882 return name; 883 } 884 } 885 886 throw new RuntimeException (); 887 } 888 889 throw new RuntimeException (String.valueOf(select)); 890 } 891 892 895 protected boolean allowJavaSelect(AbstractPattern select) 896 { 897 if (select == null) 898 return false; 899 900 else if (! select.isStrictlyAscending()) 901 return false; 902 903 else if (select instanceof FromContext) 904 return ((FromContext) select).getCount() == 0; 905 906 else if (select instanceof FromRoot) 907 return true; 908 909 else if (select instanceof NodePattern) 910 return allowJavaSelect(select.getParent()); 911 912 else if (select instanceof NodeTypePattern) 913 return allowJavaSelect(select.getParent()); 914 915 else if (select instanceof FromChildren) 916 return allowJavaSelect(select.getParent()); 917 918 else if (select instanceof FromNextSibling) 919 return allowJavaSelect(select.getParent()); 920 921 else if (select instanceof FilterPattern) { 922 if (! allowJavaSelect(select.getParent())) 923 return false; 924 925 Expr expr = ((FilterPattern) select).getExpr(); 926 927 return ((expr instanceof NumericExpr) && 928 ((NumericExpr) expr).isConstant()); 929 } 930 931 else 932 return false; 933 } 934 935 protected void printNamespace(JavaWriter out, NamespaceContext namespace) 936 throws Exception 937 { 938 int index = _gen.addNamespace(namespace); 939 940 out.print("_namespaces[" + index + "]"); 941 } 942 943 946 protected void printFragmentString(JavaWriter out, String id) 947 throws Exception 948 { 949 String fragId = "_frag_" + _gen.generateId(); 950 951 out.println("XMLWriter " + fragId + " = out.pushFragment();"); 952 953 generateChildren(out); 954 955 out.println(id + " = com.caucho.xml.XmlUtil.textValue(out.popFragment(" + fragId + "));"); 956 } 957 958 961 protected void printFragmentValue(JavaWriter out, String id) 962 throws Exception 963 { 964 String fragId = "_frag_" + _gen.generateId(); 965 966 out.println("XMLWriter " + fragId + " = out.pushFragment();"); 967 968 generateChildren(out); 969 970 out.println(id + " = out.popFragment(" + fragId + ");"); 971 } 972 973 protected void popScope(JavaWriter out) 974 throws Exception 975 { 976 printPopScope(out); 977 } 978 979 protected void printPopScope(JavaWriter out) 980 throws Exception 981 { 982 if (_varCount > 0) 983 out.println("env.popVars(" + _varCount + ");"); 984 } 985 986 989 protected void printExprTest(JavaWriter out, int id, String node) 990 throws IOException 991 { 992 out.print("_exprs[" + id + "].evalBoolean(" + node + 993 ", " + getEnv() + ")"); 994 } 995 996 public AbstractPattern parseMatch(String pattern) 997 throws XslParseException, IOException 998 { 999 try { 1000 return XPath.parseMatch(pattern, getMatchNamespace()).getPattern(); 1001 } catch (Exception e) { 1002 throw error(L.l("{0} in pattern `{1}'", 1003 e.toString(), pattern)); 1004 } 1005 } 1006 1007 protected AbstractPattern parseSelect(String pattern) 1008 throws XslParseException 1009 { 1010 try { 1011 return XPath.parseSelect(pattern, getMatchNamespace()).getPattern(); 1012 } catch (Exception e) { 1013 throw error(e); 1014 } 1015 } 1016 1017 protected int addExpr(String pattern) 1018 throws XslParseException 1019 { 1020 return _gen.addExpr(parseExpr(pattern)); 1021 } 1022 1023 1026 protected Expr parseExpr(String pattern) 1027 throws XslParseException 1028 { 1029 try { 1030 return XPath.parseExpr(pattern, 1031 getMatchNamespace(), 1032 _gen.getNodeListContext()); 1033 } catch (Exception e) { 1034 throw error(e); 1035 } 1036 } 1037 1038 protected int generateId() 1039 { 1040 return _gen.generateId(); 1041 } 1042 1043 protected String getEnv() 1044 { 1045 return _gen.getEnv(); 1046 } 1047 1048 public String escapeJavaString(String s) 1049 { 1050 if (s == null) 1051 return ""; 1052 1053 CharBuffer cb = CharBuffer.allocate(); 1054 for (int i = 0; i < s.length(); i++) { 1055 if (s.charAt(i) == '\\') 1056 cb.append("\\\\"); 1057 else if (s.charAt(i) == '"') 1058 cb.append("\\\""); 1059 else if (s.charAt(i) == '\n') 1060 cb.append("\\n"); 1061 else if (s.charAt(i) == '\r') 1062 cb.append("\\r"); 1063 else 1064 cb.append(s.charAt(i)); 1065 } 1066 1067 return cb.close(); 1068 } 1069 1070 1073 protected XslParseException error(String msg) 1074 { 1075 String filename = _filename; 1076 if (filename == null) 1077 filename = _systemId; 1078 1079 if (filename != null) 1080 return new XslParseException(filename + ":" + _startLine + ": " + msg); 1081 else 1082 return new XslParseException(msg); 1083 } 1084 1085 1088 protected XslParseException error(Throwable e) 1089 { 1090 String filename = _filename; 1091 if (filename == null) 1092 filename = _systemId; 1093 1094 if (filename == null || e instanceof LineCompileException) 1095 return new XslParseException(e); 1096 else if (e instanceof CompileException) 1097 return new XslParseException(filename + ":" + _startLine + ": " + 1098 e.getMessage(), e); 1099 else 1100 return new XslParseException(_filename + ":" + _startLine + ": " + 1101 String.valueOf(e), e); 1102 } 1103 1104 1107 public String toString() 1108 { 1109 if (_name == null) 1110 return "<" + getClass().getName() + ">"; 1111 else 1112 return "<" + _name.getName() + ">"; 1113 } 1114} 1115 | Popular Tags |