0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: * Free SoftwareFoundation, Inc.
0023: * 59 Temple Place, Suite 330
0024: * Boston, MA 02111-1307 USA
0025: *
0026: * @author Scott Ferguson
0027: */
0028:
0029: package com.caucho.xsl.java;
0030:
0031: import com.caucho.java.JavaWriter;
0032: import com.caucho.log.Log;
0033: import com.caucho.util.CharBuffer;
0034: import com.caucho.util.CompileException;
0035: import com.caucho.util.L10N;
0036: import com.caucho.util.LineCompileException;
0037: import com.caucho.xml.QName;
0038: import com.caucho.xml.XmlChar;
0039: import com.caucho.xpath.Expr;
0040: import com.caucho.xpath.NamespaceContext;
0041: import com.caucho.xpath.XPath;
0042: import com.caucho.xpath.expr.NumericExpr;
0043: import com.caucho.xpath.pattern.*;
0044: import com.caucho.xsl.JavaGenerator;
0045: import com.caucho.xsl.XslParseException;
0046:
0047: import java.io.IOException;
0048: import java.util.ArrayList;
0049: import java.util.logging.Logger;
0050:
0051: /**
0052: * Represents any XSL node from the stylesheet.
0053: */
0054: public abstract class XslNode {
0055: static final L10N L = new L10N(XslNode.class);
0056: static final Logger log = Log.open(XslNode.class);
0057:
0058: protected String _systemId;
0059: protected String _filename;
0060: protected int _startLine;
0061: protected int _endLine;
0062:
0063: protected JavaGenerator _gen;
0064:
0065: protected QName _name;
0066: protected XslNode _parent;
0067:
0068: protected ArrayList<XslNode> _children;
0069: protected NamespaceContext _matchNamespace;
0070: protected NamespaceContext _outputNamespace;
0071:
0072: private int _varCount;
0073:
0074: protected XslNode() {
0075: }
0076:
0077: /**
0078: * Sets the Java generator.
0079: */
0080: public void setGenerator(JavaGenerator gen) {
0081: _gen = gen;
0082: }
0083:
0084: /**
0085: * Returns the qname of the node.
0086: */
0087: public QName getQName() {
0088: return _name;
0089: }
0090:
0091: /**
0092: * Sets the node's qname
0093: */
0094: public void setQName(QName name) {
0095: _name = name;
0096: }
0097:
0098: /**
0099: * Returns the qname of the node.
0100: */
0101: public String getTagName() {
0102: if (_name != null)
0103: return _name.getName();
0104: else
0105: return getClass().getName();
0106: }
0107:
0108: /**
0109: * Returns the parent node.
0110: */
0111: public XslNode getParent() {
0112: return _parent;
0113: }
0114:
0115: /**
0116: * Sets the parent node
0117: */
0118: public void setParent(XslNode parent) {
0119: _parent = parent;
0120:
0121: if (parent != null) {
0122: _matchNamespace = parent.getMatchNamespace();
0123: _outputNamespace = parent.getOutputNamespace();
0124: }
0125: }
0126:
0127: /**
0128: * Add variable.
0129: */
0130: public void addVariableCount() {
0131: if (_parent != null)
0132: _parent._varCount++;
0133: }
0134:
0135: /**
0136: * Sets the start location of the node.
0137: */
0138: public void setStartLocation(String systemId, String filename,
0139: int line) {
0140: _systemId = systemId;
0141: _filename = filename;
0142: _startLine = line;
0143: }
0144:
0145: /**
0146: * Sets the end location of the node.
0147: */
0148: public void setEndLocation(String filename, int line) {
0149: if (_filename != null && _filename.equals(filename))
0150: _endLine = line;
0151: }
0152:
0153: /**
0154: * Gets the system id of the node
0155: */
0156: public String getSystemId() {
0157: return _systemId;
0158: }
0159:
0160: /**
0161: * Gets the filename of the node
0162: */
0163: public String getFilename() {
0164: return _filename;
0165: }
0166:
0167: /**
0168: * Gets the starting line number
0169: */
0170: public int getStartLine() {
0171: return _startLine;
0172: }
0173:
0174: /**
0175: * Gets the ending line number
0176: */
0177: public int getEndLine() {
0178: return _endLine;
0179: }
0180:
0181: /**
0182: * Returns the base URI.
0183: */
0184: public String getBaseURI() {
0185: return _filename;
0186: }
0187:
0188: /**
0189: * Returns the namespaces.
0190: */
0191: public NamespaceContext getMatchNamespace() {
0192: return _matchNamespace;
0193: }
0194:
0195: /**
0196: * Returns the namespaces.
0197: */
0198: public NamespaceContext getOutputNamespace() {
0199: return _outputNamespace;
0200: }
0201:
0202: /**
0203: * Returns the matching node in the namespace.
0204: */
0205: public String getNamespace(String prefix) {
0206: return NamespaceContext.find(getOutputNamespace(), prefix);
0207: }
0208:
0209: /**
0210: * Adds an attribute.
0211: */
0212: public void addAttribute(QName name, String value)
0213: throws XslParseException {
0214: if (name.getName().startsWith("xmlns")) {
0215: addNamespaceAttribute(name, value);
0216: return;
0217: }
0218:
0219: if (name.getName().startsWith("xml"))
0220: return;
0221:
0222: throw error(L.l("attribute `{0}' is not allowed in <{1}>.",
0223: name.getName(), getTagName()));
0224: }
0225:
0226: /**
0227: * Adds an attribute.
0228: */
0229: protected void addNamespaceAttribute(QName name, String url)
0230: throws XslParseException {
0231: // Note: according to the spec, the default namespace is not used
0232:
0233: /*
0234: if (url.equals(JavaGenerator.XSLNS) || url.equals(JavaGenerator.XTPNS))
0235: return;
0236:
0237: if (url.startsWith("quote:"))
0238: url = url.substring(6);
0239: */
0240:
0241: String localName = name.getLocalName();
0242:
0243: _outputNamespace = new NamespaceContext(_outputNamespace,
0244: localName, url);
0245:
0246: if (!localName.equals("xmlns")) {
0247: // xsl/04w3
0248: _matchNamespace = new NamespaceContext(_matchNamespace,
0249: localName, url);
0250: }
0251: }
0252:
0253: /**
0254: * Called after all the attributes from the tag.
0255: */
0256: public void endAttributes() throws XslParseException {
0257: }
0258:
0259: /**
0260: * Adds text.
0261: */
0262: public void addText(String text) throws XslParseException {
0263: for (int i = 0; i < text.length(); i++) {
0264: char ch = text.charAt(i);
0265:
0266: if (!XmlChar.isWhitespace(ch))
0267: throw error(L.l(
0268: "Text is not allowed in <{0}> at `{1}'.", _name
0269: .getName(), text));
0270: }
0271: }
0272:
0273: /**
0274: * Adds a child node.
0275: */
0276: public void addChild(XslNode node) throws XslParseException {
0277: if (node == null)
0278: return;
0279:
0280: if (_children == null)
0281: _children = new ArrayList<XslNode>();
0282:
0283: _children.add(node);
0284: }
0285:
0286: /**
0287: * Called when the tag closes.
0288: */
0289: public void endElement() throws Exception {
0290: }
0291:
0292: /**
0293: * Returns the children.
0294: */
0295: public ArrayList<XslNode> getChildren() {
0296: return _children;
0297: }
0298:
0299: /**
0300: * Returns true if there are any children.
0301: */
0302: public boolean hasChildren() {
0303: return _children != null && _children.size() > 0;
0304: }
0305:
0306: /**
0307: * Generates the code for the tag
0308: *
0309: * @param out the output writer for the generated java.
0310: */
0311: abstract public void generate(JavaWriter out) throws Exception;
0312:
0313: /**
0314: * Generates the code for the children.
0315: *
0316: * @param out the output writer for the generated java.
0317: */
0318: public void generateChildren(JavaWriter out) throws Exception {
0319: if (_children == null)
0320: return;
0321:
0322: for (int i = 0; i < _children.size(); i++) {
0323: XslNode child = _children.get(i);
0324:
0325: out.setLocation(child.getFilename(), child.getStartLine());
0326:
0327: child.generate(out);
0328: }
0329:
0330: popScope(out);
0331: }
0332:
0333: /**
0334: * Generates the prelude code for the tag
0335: *
0336: * @param out the output writer for the generated java.
0337: */
0338: public void generateDeclaration(JavaWriter out) throws Exception {
0339: generateDeclarationChildren(out);
0340: }
0341:
0342: /**
0343: * Generates the declaration code for the children.
0344: *
0345: * @param out the output writer for the generated java.
0346: */
0347: public void generateDeclarationChildren(JavaWriter out)
0348: throws Exception {
0349: if (_children == null)
0350: return;
0351:
0352: for (int i = 0; i < _children.size(); i++) {
0353: XslNode child = _children.get(i);
0354:
0355: child.generateDeclaration(out);
0356: }
0357: }
0358:
0359: /**
0360: * Prints an attribute value.
0361: */
0362: protected void printAttributeValue(JavaWriter out, String name,
0363: String value) throws Exception {
0364: out.print("out.attribute(");
0365: out.print(name == null ? "null" : ("\"" + name + "\""));
0366: out.print(", ");
0367: if (value == null)
0368: out.print("null");
0369: else {
0370: out.print("\"");
0371: out.printJavaString(value);
0372: out.print("\"");
0373: }
0374: out.println(");");
0375: }
0376:
0377: /**
0378: * Prints an attribute value.
0379: */
0380: protected void printAttributeValue(JavaWriter out, String value)
0381: throws Exception {
0382: if (value == null) {
0383: out.print("null");
0384: return;
0385: }
0386:
0387: if (value.indexOf("{") < 0) {
0388: out.print("\"");
0389: out.printJavaString(value);
0390: out.print("\"");
0391: } else {
0392: generateString(out, value);
0393: }
0394: }
0395:
0396: /**
0397: * Produces code to generate an attribute value template. The same
0398: * code is used to produce a string ('a{b}c' -> "a" + b + "c") or a series of
0399: * print statements (',').
0400: *
0401: * @param string the source template
0402: * @param mode separator: either '+' or ','
0403: * @param elt the containing element. Needed for namespaces.
0404: */
0405: void generateString(JavaWriter out, String string) throws Exception {
0406: int i = 0;
0407: boolean first = true;
0408: int length = string.length();
0409: CharBuffer cb = CharBuffer.allocate();
0410:
0411: for (; i < length; i++) {
0412: char ch = string.charAt(i);
0413:
0414: if (ch == '\n') {
0415: cb.append("\\n");
0416: } else if (ch == '"') {
0417: cb.append("\\\"");
0418: } else if (ch == '{' && i + 1 < length) {
0419: // {{ is treated as a single {
0420: if (string.charAt(i + 1) == '{') {
0421: cb.append('{');
0422: i++;
0423: }
0424: // the value is computed from an XPath expr
0425: else {
0426: // print the gathered text if any
0427: if (cb.length() > 0) {
0428: out.print("out.print(\"");
0429: out.printJavaString(cb.toString());
0430: out.println("\");");
0431: }
0432:
0433: // scan the contents of '{' ... '}'
0434: cb.clear();
0435: for (i++; i < length && string.charAt(i) != '}'; i++)
0436: cb.append(string.charAt(i));
0437:
0438: printStringExpr(out, cb.toString());
0439:
0440: cb.clear();
0441: first = false;
0442: }
0443: }
0444: // }} is treated as a single }
0445: else if (ch == '}' && i + 1 < length) {
0446: if (string.charAt(i + 1) == '}') {
0447: cb.append('}');
0448: i++;
0449: } else
0450: cb.append('}');
0451: }
0452: // <#= interpolates
0453: else if (i + 2 < length && ch == '<'
0454: && string.charAt(i + 1) == '#'
0455: && string.charAt(i + 2) == '=') {
0456: // print the gathered text if any
0457: if (cb.length() > 0) {
0458: out.print("out.print(\"");
0459: out.printJavaString(cb.toString());
0460: out.println("\");");
0461: }
0462:
0463: // scan the contents of '{' ... '}'
0464: cb.clear();
0465: for (i += 3; i + 1 < length && string.charAt(i) != '#'
0466: && string.charAt(i + 1) != '>'; i++)
0467: cb.append(string.charAt(i));
0468:
0469: i++;
0470:
0471: // and add the results
0472: out.println("out.print(" + cb + ");");
0473:
0474: cb.clear();
0475: first = false;
0476: } else
0477: cb.append((char) ch);
0478: }
0479:
0480: // add any trailing text
0481: if (cb.length() > 0)
0482: out.println("out.print(\"" + cb + "\");");
0483: }
0484:
0485: /**
0486: * Produces code to generate an attribute value template. The same
0487: * code is used to produce a string ('a{b}c' -> "a" + b + "c") or a series of
0488: * print statements (',').
0489: *
0490: * @param string the source template
0491: * @param mode separator: either '+' or ','
0492: * @param elt the containing element. Needed for namespaces.
0493: */
0494: void generateString(JavaWriter out, String string, int mode)
0495: throws Exception {
0496: CharBuffer cb = new CharBuffer();
0497: int i = 0;
0498: boolean first = true;
0499: int length = string.length();
0500:
0501: for (; i < length; i++) {
0502: char ch = string.charAt(i);
0503:
0504: if (ch == '\n') {
0505: cb.append("\\n");
0506: } else if (ch == '"') {
0507: cb.append("\\\"");
0508: } else if (ch == '{' && i + 1 < length) {
0509: // {{ is treated as a single {
0510: if (string.charAt(i + 1) == '{') {
0511: cb.append('{');
0512: i++;
0513: }
0514: // the value is computed from an XPath expr
0515: else {
0516: // print the gathered text if any
0517: if (mode == ',') {
0518: if (cb.length() > 0)
0519: out.println("out.print(\"" + cb.toString()
0520: + "\");");
0521: } else {
0522: if (!first)
0523: out.print((char) mode);
0524:
0525: if (cb.length() > 0) {
0526: out.print("\"");
0527: out.print(cb.toString());
0528: out.print("\"");
0529: out.print((char) mode);
0530: }
0531: }
0532:
0533: // scan the contents of '{' ... '}'
0534: cb.clear();
0535: for (i++; i < length && string.charAt(i) != '}'; i++)
0536: cb.append(string.charAt(i));
0537:
0538: // and add the results
0539: if (mode == ',')
0540: printStringExpr(out, cb.toString());
0541: else
0542: stringExpr(out, cb.toString());
0543: cb.clear();
0544: first = false;
0545: }
0546: }
0547: // }} is treated as a single }
0548: else if (ch == '}' && i + 1 < length) {
0549: if (string.charAt(i + 1) == '}') {
0550: cb.append('}');
0551: i++;
0552: } else
0553: cb.append('}');
0554: }
0555: // <#= interpolates
0556: else if (i + 2 < length && ch == '<'
0557: && string.charAt(i + 1) == '#'
0558: && string.charAt(i + 2) == '=') {
0559: // print the gathered text if any
0560: if (mode == ',') {
0561: if (cb.length() > 0)
0562: out.println("out.print(\"" + cb.toString()
0563: + "\");");
0564: } else {
0565: if (!first)
0566: out.print((char) mode);
0567:
0568: if (cb.length() > 0) {
0569: out.print("\"");
0570: out.print(cb.toString());
0571: out.print("\"");
0572: out.print((char) mode);
0573: }
0574: }
0575:
0576: // scan the contents of '{' ... '}'
0577: cb.clear();
0578: for (i += 3; i + 1 < length && string.charAt(i) != '#'
0579: && string.charAt(i + 1) != '>'; i++)
0580: cb.append(string.charAt(i));
0581:
0582: i++;
0583:
0584: // and add the results
0585: if (mode == ',')
0586: out.println("out.print(" + cb + ");");
0587: else {
0588: out.print("(" + cb + ")");
0589: }
0590: cb.clear();
0591: first = false;
0592: } else
0593: cb.append((char) ch);
0594: }
0595:
0596: // add any trailing text
0597: if (cb.length() > 0) {
0598: if (mode == ',')
0599: out.println("out.print(\"" + cb + "\");");
0600: else {
0601: if (!first)
0602: out.print((char) mode);
0603:
0604: out.print("\"" + cb + "\"");
0605: }
0606: } else if (first && mode == '+')
0607: out.print("\"\"");
0608: }
0609:
0610: /**
0611: * Prints a value-of expression
0612: */
0613: protected void printStringExpr(JavaWriter out, String exprString)
0614: throws Exception {
0615: if (exprString == null)
0616: return;
0617:
0618: int length = exprString.length();
0619:
0620: if (length == 0)
0621: return;
0622:
0623: AbstractPattern select = null;
0624: try {
0625: select = parseSelect(exprString);
0626: } catch (Exception e) {
0627: // this is expected in case where the expr is not a select expression
0628: }
0629:
0630: if (exprString.equals(".")) {
0631: out.println("out.valueOf(node);");
0632: return;
0633: } else if (exprString.charAt(0) == '@') {
0634: boolean isSimple = true;
0635:
0636: for (int i = 1; i < length; i++) {
0637: char ch = exprString.charAt(i);
0638: if (!XmlChar.isNameChar(ch) || ch == ':')
0639: isSimple = false;
0640: }
0641:
0642: if (isSimple) {
0643: out.println("if (node instanceof Element)");
0644: out
0645: .print(" out.print(((Element) node).getAttribute(\"");
0646: out.print(exprString.substring(1));
0647: out.println("\"));");
0648: return;
0649: }
0650: } else if (allowJavaSelect(select)) {
0651: int oldSelectDepth = _gen.getSelectDepth();
0652:
0653: String loop = "_xsl_loop" + _gen.generateId();
0654: _gen.setSelectLoopDepth(0);
0655:
0656: String ptr = printSelectBegin(out, select, true, loop);
0657:
0658: out.println("out.valueOf(" + ptr + ");");
0659: out.println("break " + loop + ";");
0660:
0661: int selectDepth = _gen.getSelectDepth();
0662: for (; oldSelectDepth < selectDepth; selectDepth--) {
0663: out.popDepth();
0664: out.println("}");
0665: }
0666: _gen.setSelectDepth(oldSelectDepth);
0667:
0668: return;
0669: }
0670:
0671: out.println("out.valueOf(_exprs[" + addExpr(exprString)
0672: + "].evalObject(node, " + _gen.getEnv() + "));");
0673: }
0674:
0675: protected void stringExpr(JavaWriter out, String exprString)
0676: throws Exception, XslParseException {
0677: out.print("_exprs[" + _gen.addExpr(parseExpr(exprString))
0678: + "].evalString(node, " + getEnv() + ")");
0679: }
0680:
0681: protected void pushCall(JavaWriter out) throws IOException {
0682: out.println("{");
0683: out.pushDepth();
0684:
0685: int callDepth = _gen.pushCallDepth();
0686:
0687: out.println("Env _xsl_arg" + callDepth
0688: + " = XPath.createCall(env);");
0689: }
0690:
0691: protected void popCall(JavaWriter out) throws IOException {
0692: int callDepth = _gen.popCallDepth();
0693: out.println("_xsl_arg" + callDepth + ".free();");
0694:
0695: out.popDepth();
0696: out.println("}");
0697: }
0698:
0699: /**
0700: * Prints iterator code to start a select.
0701: */
0702: protected String printSelectBegin(JavaWriter out,
0703: AbstractPattern select, boolean isForEach, String loopVar)
0704: throws IOException, XslParseException {
0705: if (select == null)
0706: throw new NullPointerException();
0707:
0708: if (select instanceof FromContext
0709: && ((FromContext) select).getCount() == 0)
0710: return "node";
0711:
0712: else if (select instanceof FromRoot)
0713: return "ownerDocument(node)";
0714:
0715: boolean useXPath = allowJavaSelect(select);
0716:
0717: String name = "node";
0718:
0719: if (!useXPath) {
0720: // punt and let XPath handle it.
0721: String iterName = "_xsl_iter" + _gen.generateId();
0722:
0723: String ptrName = "_xsl_ptr" + _gen.generateId();
0724:
0725: if (isForEach)
0726: out.println("env.setCurrentNode(node);");
0727:
0728: out.println("Iterator " + iterName + " = _select_patterns["
0729: + _gen.addSelect(select) + "].select(" + name
0730: + ", env);");
0731:
0732: if (loopVar != null && _gen.getSelectLoopDepth() == 0)
0733: out.println(loopVar + ":");
0734:
0735: out.println("while (" + iterName + ".hasNext()) {");
0736: out.pushDepth();
0737: _gen.pushSelectDepth();
0738: _gen.pushSelectLoopDepth();
0739: out.println("Node " + ptrName + " = (Node) " + iterName
0740: + ".next();");
0741:
0742: return ptrName;
0743: }
0744:
0745: if (select instanceof FromChildren) {
0746: name = printSelectBegin(out, select.getParent(), isForEach,
0747: loopVar);
0748:
0749: String ptrName = "_xsl_ptr" + _gen.generateId();
0750:
0751: if (loopVar != null && _gen.getSelectLoopDepth() == 0)
0752: out.println(loopVar + ":");
0753:
0754: out.println("for (Node " + ptrName + " = " + name
0755: + ".getFirstChild();");
0756: out.println(" " + ptrName + " != null;");
0757: out.println(" " + ptrName + " = " + ptrName
0758: + ".getNextSibling()) {");
0759: out.pushDepth();
0760: _gen.pushSelectDepth();
0761: _gen.pushSelectLoopDepth();
0762:
0763: return ptrName;
0764: } else if (select instanceof FromNextSibling) {
0765: name = printSelectBegin(out, select.getParent(), isForEach,
0766: loopVar);
0767:
0768: String ptrName = "_xsl_ptr" + _gen.generateId();
0769:
0770: if (loopVar != null && _gen.getSelectLoopDepth() == 0)
0771: out.println(loopVar + ":");
0772:
0773: out.println("for (Node " + ptrName + " = " + name
0774: + ".getNextSibling();");
0775: out.println(" " + ptrName + " != null;");
0776: out.println(" " + ptrName + " = " + ptrName
0777: + ".getNextSibling()) {");
0778: out.pushDepth();
0779: _gen.pushSelectDepth();
0780: _gen.pushSelectLoopDepth();
0781:
0782: return ptrName;
0783: } else if (select instanceof NodePattern) {
0784: name = printSelectBegin(out, select.getParent(), isForEach,
0785: loopVar);
0786:
0787: NodePattern pat = (NodePattern) select;
0788:
0789: out.println("if (" + name + ".getNodeName().equals(\""
0790: + pat.getNodeName() + "\") &&");
0791: out.println(" " + name + " instanceof Element) {");
0792: out.pushDepth();
0793: _gen.pushSelectDepth();
0794:
0795: return name;
0796: } else if (select instanceof NodeTypePattern) {
0797: name = printSelectBegin(out, select.getParent(), isForEach,
0798: loopVar);
0799:
0800: NodeTypePattern pat = (NodeTypePattern) select;
0801:
0802: if (pat.getNodeType() >= 0) {
0803: out.println("if (" + name + ".getNodeType() == "
0804: + pat.getNodeType() + ") {");
0805: out.pushDepth();
0806: _gen.pushSelectDepth();
0807: }
0808:
0809: return name;
0810: } else if (select instanceof FilterPattern) {
0811: String posId = "_xsl_pos" + _gen.generateId();
0812:
0813: out.println("int " + posId + " = 0;");
0814:
0815: name = printSelectBegin(out, select.getParent(), isForEach,
0816: loopVar);
0817:
0818: out.println(posId + "++;");
0819:
0820: FilterPattern pat = (FilterPattern) select;
0821: Expr expr = pat.getExpr();
0822:
0823: if (expr instanceof NumericExpr) {
0824: NumericExpr num = (NumericExpr) expr;
0825: if (num.isConstant()) {
0826: out.println("if (" + posId + " > "
0827: + (int) num.getValue() + ")");
0828: out.println(" break;");
0829: out.println("else if (" + posId + " == "
0830: + (int) num.getValue() + ") {");
0831: out.pushDepth();
0832: _gen.pushSelectDepth();
0833:
0834: return name;
0835: }
0836: }
0837:
0838: throw new RuntimeException();
0839: }
0840:
0841: throw new RuntimeException(String.valueOf(select));
0842: }
0843:
0844: /**
0845: * Returns true if we can compile in the java select.
0846: */
0847: protected boolean allowJavaSelect(AbstractPattern select) {
0848: if (select == null)
0849: return false;
0850:
0851: else if (!select.isStrictlyAscending())
0852: return false;
0853:
0854: else if (select instanceof FromContext)
0855: return ((FromContext) select).getCount() == 0;
0856:
0857: else if (select instanceof FromRoot)
0858: return true;
0859:
0860: else if (select instanceof NodePattern)
0861: return allowJavaSelect(select.getParent());
0862:
0863: else if (select instanceof NodeTypePattern)
0864: return allowJavaSelect(select.getParent());
0865:
0866: else if (select instanceof FromChildren)
0867: return allowJavaSelect(select.getParent());
0868:
0869: else if (select instanceof FromNextSibling)
0870: return allowJavaSelect(select.getParent());
0871:
0872: else if (select instanceof FilterPattern) {
0873: if (!allowJavaSelect(select.getParent()))
0874: return false;
0875:
0876: Expr expr = ((FilterPattern) select).getExpr();
0877:
0878: return ((expr instanceof NumericExpr) && ((NumericExpr) expr)
0879: .isConstant());
0880: }
0881:
0882: else
0883: return false;
0884: }
0885:
0886: protected void printNamespace(JavaWriter out,
0887: NamespaceContext namespace) throws Exception {
0888: int index = _gen.addNamespace(namespace);
0889:
0890: out.print("_namespaces[" + index + "]");
0891: }
0892:
0893: /**
0894: * Prints the children as a fragment stored in a variable.
0895: */
0896: protected void printFragmentString(JavaWriter out, String id)
0897: throws Exception {
0898: String fragId = "_frag_" + _gen.generateId();
0899:
0900: out.println("XMLWriter " + fragId + " = out.pushFragment();");
0901:
0902: generateChildren(out);
0903:
0904: out
0905: .println(id
0906: + " = com.caucho.xml.XmlUtil.textValue(out.popFragment("
0907: + fragId + "));");
0908: }
0909:
0910: /**
0911: * Prints the children as a fragment stored in a variable.
0912: */
0913: protected void printFragmentValue(JavaWriter out, String id)
0914: throws Exception {
0915: String fragId = "_frag_" + _gen.generateId();
0916:
0917: out.println("XMLWriter " + fragId + " = out.pushFragment();");
0918:
0919: generateChildren(out);
0920:
0921: out.println(id + " = out.popFragment(" + fragId + ");");
0922: }
0923:
0924: protected void popScope(JavaWriter out) throws Exception {
0925: printPopScope(out);
0926: }
0927:
0928: protected void printPopScope(JavaWriter out) throws Exception {
0929: if (_varCount > 0)
0930: out.println("env.popVars(" + _varCount + ");");
0931: }
0932:
0933: /**
0934: * Prints a test expr.
0935: */
0936: protected void printExprTest(JavaWriter out, int id, String node)
0937: throws IOException {
0938: out.print("_exprs[" + id + "].evalBoolean(" + node + ", "
0939: + getEnv() + ")");
0940: }
0941:
0942: public AbstractPattern parseMatch(String pattern)
0943: throws XslParseException, IOException {
0944: try {
0945: return XPath.parseMatch(pattern, getMatchNamespace())
0946: .getPattern();
0947: } catch (Exception e) {
0948: throw error(L.l("{0} in pattern `{1}'", e.toString(),
0949: pattern));
0950: }
0951: }
0952:
0953: protected AbstractPattern parseSelect(String pattern)
0954: throws XslParseException {
0955: try {
0956: return XPath.parseSelect(pattern, getMatchNamespace())
0957: .getPattern();
0958: } catch (Exception e) {
0959: throw error(e);
0960: }
0961: }
0962:
0963: protected int addExpr(String pattern) throws XslParseException {
0964: return _gen.addExpr(parseExpr(pattern));
0965: }
0966:
0967: /**
0968: * Parses an XPath expression in the current context.
0969: */
0970: protected Expr parseExpr(String pattern) throws XslParseException {
0971: try {
0972: return XPath.parseExpr(pattern, getMatchNamespace(), _gen
0973: .getNodeListContext());
0974: } catch (Exception e) {
0975: throw error(e);
0976: }
0977: }
0978:
0979: protected int generateId() {
0980: return _gen.generateId();
0981: }
0982:
0983: protected String getEnv() {
0984: return _gen.getEnv();
0985: }
0986:
0987: public String escapeJavaString(String s) {
0988: if (s == null)
0989: return "";
0990:
0991: CharBuffer cb = CharBuffer.allocate();
0992: for (int i = 0; i < s.length(); i++) {
0993: if (s.charAt(i) == '\\')
0994: cb.append("\\\\");
0995: else if (s.charAt(i) == '"')
0996: cb.append("\\\"");
0997: else if (s.charAt(i) == '\n')
0998: cb.append("\\n");
0999: else if (s.charAt(i) == '\r')
1000: cb.append("\\r");
1001: else
1002: cb.append(s.charAt(i));
1003: }
1004:
1005: return cb.close();
1006: }
1007:
1008: /**
1009: * Creates a parse exception with the proper line information.
1010: */
1011: protected XslParseException error(String msg) {
1012: String filename = _filename;
1013: if (filename == null)
1014: filename = _systemId;
1015:
1016: if (filename != null)
1017: return new XslParseException(filename + ":" + _startLine
1018: + ": " + msg);
1019: else
1020: return new XslParseException(msg);
1021: }
1022:
1023: /**
1024: * Creates a parse exception with the proper line information.
1025: */
1026: protected XslParseException error(Throwable e) {
1027: String filename = _filename;
1028: if (filename == null)
1029: filename = _systemId;
1030:
1031: if (filename == null || e instanceof LineCompileException)
1032: return new XslParseException(e);
1033: else if (e instanceof CompileException)
1034: return new XslParseException(filename + ":" + _startLine
1035: + ": " + e.getMessage(), e);
1036: else
1037: return new XslParseException(_filename + ":" + _startLine
1038: + ": " + String.valueOf(e), e);
1039: }
1040:
1041: /**
1042: * Returns a printable version of the node.
1043: */
1044: public String toString() {
1045: if (_name == null)
1046: return "<" + getClass().getName() + ">";
1047: else
1048: return "<" + _name.getName() + ">";
1049: }
1050: }
|