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;
0030:
0031: import com.caucho.java.JavaWriter;
0032: import com.caucho.java.LineMap;
0033: import com.caucho.log.Log;
0034: import com.caucho.util.CharBuffer;
0035: import com.caucho.util.CharScanner;
0036: import com.caucho.util.IntArray;
0037: import com.caucho.util.IntMap;
0038: import com.caucho.util.L10N;
0039: import com.caucho.util.StringCharCursor;
0040: import com.caucho.vfs.Path;
0041: import com.caucho.vfs.ReadStream;
0042: import com.caucho.xml.CauchoDocument;
0043: import com.caucho.xml.QAbstractNode;
0044: import com.caucho.xml.QElement;
0045: import com.caucho.xml.QName;
0046: import com.caucho.xml.Xml;
0047: import com.caucho.xml.XmlChar;
0048: import com.caucho.xpath.Expr;
0049: import com.caucho.xpath.NamespaceContext;
0050: import com.caucho.xpath.XPath;
0051: import com.caucho.xpath.pattern.AbstractPattern;
0052: import com.caucho.xpath.pattern.UnionPattern;
0053: import com.caucho.xsl.fun.FormatNumberFun;
0054: import com.caucho.xsl.fun.KeyFun;
0055: import com.caucho.xsl.java.XslAttributeSet;
0056: import com.caucho.xsl.java.XslNode;
0057: import com.caucho.xsl.java.XslStylesheet;
0058: import com.caucho.xsl.java.XslTemplate;
0059:
0060: import org.w3c.dom.Attr;
0061: import org.w3c.dom.Document;
0062: import org.w3c.dom.DocumentType;
0063: import org.w3c.dom.Element;
0064: import org.w3c.dom.Node;
0065: import org.w3c.dom.Text;
0066:
0067: import java.io.FileNotFoundException;
0068: import java.io.IOException;
0069: import java.text.DecimalFormatSymbols;
0070: import java.util.ArrayList;
0071: import java.util.HashMap;
0072: import java.util.Iterator;
0073: import java.util.logging.Level;
0074: import java.util.logging.Logger;
0075:
0076: /**
0077: * Base class for generating code from an XSL tree. JavaGenerator and
0078: * JavaScriptGenerator extend this class for language-specific code
0079: * generation.
0080: */
0081: abstract class Generator {
0082: private static final Logger log = Log.open(Generator.class);
0083: protected static final L10N L = new L10N(Generator.class);
0084:
0085: public static final String XSLNS = "http://www.w3.org/1999/XSL/Transform";
0086: public static final String XTPNS = "http://www.caucho.com/XTP/1.0";
0087:
0088: private static final int STYLESHEET = 0;
0089: private static final int OUTPUT = STYLESHEET + 1;
0090: private static final int IMPORT = OUTPUT + 1;
0091: private static final int INCLUDE = IMPORT + 1;
0092: private static final int TEMPLATE = INCLUDE + 1;
0093: private static final int STRIP_SPACE = TEMPLATE + 1;
0094: private static final int PRESERVE_SPACE = STRIP_SPACE + 1;
0095: private static final int KEY = PRESERVE_SPACE + 1;
0096: private static final int LOCALE = KEY + 1;
0097: private static final int ATTRIBUTE_SET = LOCALE + 1;
0098: private static final int NAMESPACE_ALIAS = ATTRIBUTE_SET + 1;
0099:
0100: private static final int APPLY_TEMPLATES = NAMESPACE_ALIAS + 1;
0101: private static final int APPLY_IMPORTS = APPLY_TEMPLATES + 1;
0102: private static final int CALL_TEMPLATE = APPLY_IMPORTS + 1;
0103: private static final int PARAM = CALL_TEMPLATE + 1;
0104: private static final int VARIABLE = PARAM + 1;
0105: private static final int VALUE_OF = VARIABLE + 1;
0106: private static final int COPY_OF = VALUE_OF + 1;
0107: private static final int FOR_EACH = COPY_OF + 1;
0108: private static final int IF = FOR_EACH + 1;
0109: private static final int CHOOSE = IF + 1;
0110:
0111: private static final int TEXT = CHOOSE + 1;
0112: private static final int XSL_TEXT = TEXT + 1;
0113: private static final int NUMBER = XSL_TEXT + 1;
0114: private static final int COPY = NUMBER + 1;
0115: private static final int COPY_ELEMENT = COPY + 1;
0116: private static final int ELEMENT = COPY_ELEMENT + 1;
0117: private static final int ATTRIBUTE = ELEMENT + 1;
0118: private static final int PI = ATTRIBUTE + 1;
0119: private static final int COMMENT = PI + 1;
0120:
0121: private static final int MESSAGE = COMMENT + 1;
0122:
0123: private static final int EXPRESSION = MESSAGE + 1;
0124: private static final int SCRIPTLET = EXPRESSION + 1;
0125: private static final int DECLARATION = SCRIPTLET + 1;
0126: private static final int DIRECTIVE_CACHE = DECLARATION + 1;
0127: private static final int DIRECTIVE_PAGE = DIRECTIVE_CACHE + 1;
0128: private static final int WHILE = DIRECTIVE_PAGE + 1;
0129:
0130: private static final int ASSIGN = WHILE + 1;
0131: private static final int IGNORE = ASSIGN + 1;
0132:
0133: // xslt 2.0
0134: private static final int RESULT_DOCUMENT = IGNORE + 1;
0135:
0136: private static IntMap _tags;
0137: private static IntMap _xtpTags;
0138: private String _version = "1.0";
0139:
0140: String _xslName;
0141: // the root context
0142: Path _topContext;
0143: // the pwd for the file
0144: Path _baseURL;
0145: Path _context;
0146: CharBuffer _text;
0147: HashMap<String, String> _names = new HashMap<String, String>();
0148: int _loopDepth;
0149: Path _workPath;
0150: int _uniqueId;
0151:
0152: protected HashMap<String, String> _preserve = new HashMap<String, String>();
0153: protected HashMap<String, String> _strip = new HashMap<String, String>();
0154:
0155: HashMap<String, XslAttributeSet> _attributeSets = new HashMap<String, XslAttributeSet>();
0156:
0157: protected HashMap<String, String[]> _namespaceAliases = new HashMap<String, String[]>();
0158: protected HashMap<String, String> _excludedNamespaces = new HashMap<String, String>();
0159: protected KeyFun _keyFun;
0160: protected FormatNumberFun _formatNumberFun;
0161:
0162: protected NamespaceContext _namespace;
0163: protected ArrayList _globalActions = new ArrayList();
0164: protected ArrayList<String> _globalParameters = new ArrayList<String>();
0165:
0166: protected Document _doc;
0167: protected CauchoDocument _qDoc;
0168:
0169: protected Path _path;
0170:
0171: boolean _lineContent;
0172: int _lineWs;
0173: String _systemId;
0174: String _filename;
0175: int _line;
0176: protected LineMap _lineMap;
0177: private ArrayList _frags;
0178: protected int _destLine = 1;
0179: boolean _defaultCacheable = true;
0180: boolean _isCacheable;
0181: protected String _encoding;
0182:
0183: HashMap<String, ArrayList<Template>> _templates = new HashMap<String, ArrayList<Template>>();
0184: int _minImportance; // for included files, the minimum importance
0185: int _importance;
0186: int _templateCount;
0187: private IntArray _vars = new IntArray();
0188: private ArrayList<XslNode> _inits = new ArrayList<XslNode>();
0189: protected ArrayList<Path> _depends = new ArrayList<Path>();
0190: protected ArrayList<String> _cacheDepends = new ArrayList<String>();
0191:
0192: private boolean _isCauchoXsl;
0193: protected boolean _isRawText;
0194: protected String _errorPage;
0195: boolean _hasSession;
0196: protected AbstractPattern _nodeListContext;
0197: private boolean _isTop;
0198: private ClassLoader _loader;
0199:
0200: protected boolean _isSpecial;
0201: protected boolean _isStyleScript;
0202:
0203: HashMap<String, String> _outputAttributes = new HashMap<String, String>();
0204: HashMap<String, String> _macros;
0205: HashMap<String, Document> _files;
0206:
0207: protected AbstractStylesheetFactory _xslGenerator;
0208:
0209: protected ArrayList<String> _imports = new ArrayList<String>();
0210:
0211: Generator(AbstractStylesheetFactory xslGenerator) {
0212: _xslGenerator = xslGenerator;
0213:
0214: _workPath = xslGenerator.getWorkPath();
0215:
0216: Path path = xslGenerator.getStylePath();
0217:
0218: _context = path;
0219: _topContext = _context;
0220: _loader = xslGenerator.getClassLoader();
0221: if (_loader == null)
0222: _loader = Thread.currentThread().getContextClassLoader();
0223:
0224: _text = new CharBuffer();
0225: _frags = new ArrayList();
0226: _macros = new HashMap<String, String>();
0227:
0228: _keyFun = new KeyFun();
0229: _formatNumberFun = new FormatNumberFun();
0230: }
0231:
0232: void init(String filename) {
0233: _lineMap = new LineMap(filename);
0234: }
0235:
0236: public void setErrorPage(String errorPage) {
0237: _errorPage = errorPage;
0238: }
0239:
0240: public void setStyleScript(boolean stylescript) {
0241: _isStyleScript = stylescript;
0242: }
0243:
0244: /**
0245: * Adds a Java import to the generated stylesheet.
0246: */
0247: public void addImport(String pkg) {
0248: if (!_imports.contains(pkg))
0249: _imports.add(pkg);
0250: }
0251:
0252: public void setContentType(String type) {
0253: // contentType = type;
0254: }
0255:
0256: void setPath(Path path) {
0257: _path = path;
0258: _context = path;
0259: }
0260:
0261: void setWorkPath(Path path) {
0262: _workPath = path;
0263: }
0264:
0265: public int getMinImportance() {
0266: return _minImportance;
0267: }
0268:
0269: public int getMaxImportance() {
0270: return _importance;
0271: }
0272:
0273: public NamespaceContext getNamespace() {
0274: return _namespace;
0275: }
0276:
0277: public AbstractPattern getNodeListContext() {
0278: return _nodeListContext;
0279: }
0280:
0281: public void addLocale(String name, DecimalFormatSymbols format) {
0282: _formatNumberFun.addLocale(name, format);
0283: }
0284:
0285: /**
0286: * Generates a uniqueId
0287: */
0288: public int uniqueId() {
0289: return _uniqueId++;
0290: }
0291:
0292: /**
0293: * Starts the generation from the top of the document.
0294: *
0295: * @param xsl the stylesheet document.
0296: */
0297: public StylesheetImpl generate(Node node) throws Exception {
0298: Document xsl = node.getOwnerDocument();
0299: if (xsl == null)
0300: xsl = (Document) node;
0301:
0302: DocumentType dtd = xsl.getDoctype();
0303:
0304: if (dtd != null && dtd.getSystemId() != null) {
0305: _context = _path.lookup(dtd.getSystemId());
0306: _topContext = _context;
0307: }
0308:
0309: Element top = (Element) xsl.getDocumentElement();
0310:
0311: if (top == null)
0312: throw error(xsl, L.l("xsl:stylesheet must be top element."));
0313:
0314: _doc = xsl;
0315: if (_doc instanceof CauchoDocument)
0316: _qDoc = (CauchoDocument) _doc;
0317:
0318: QElement qTop = null;
0319: if (top instanceof QElement)
0320: qTop = (QElement) top;
0321:
0322: /*
0323: if (qTop != null && qTop.getFilename() != null)
0324: context = topContext.lookup(qTop.getFilename()).getParent();
0325: */
0326:
0327: _isTop = true;
0328: _files = new HashMap<String, Document>();
0329: scanFiles(top);
0330:
0331: if (_qDoc != null) {
0332: ArrayList depends = (ArrayList) _qDoc
0333: .getProperty(CauchoDocument.DEPENDS);
0334: for (int i = 0; depends != null && i < depends.size(); i++) {
0335: Path path = (Path) depends.get(i);
0336: addDepend(path);
0337: }
0338: } else {
0339: addDepend(_path);
0340: }
0341:
0342: if ("stylesheet".equals(getXslLocal(top))
0343: || "transform".equals(getXslLocal(top))) {
0344: generateStylesheet(top, true);
0345: } else {
0346: // literal result element
0347: printHeader();
0348: boolean oldCacheable = _isCacheable;
0349: boolean oldDefaultCacheable = _defaultCacheable;
0350: _isCacheable = true;
0351:
0352: XslNode literal = createChild(top);
0353:
0354: XslTemplate template = new XslTemplate();
0355: template.setGenerator((JavaGenerator) this );
0356: template.addAttribute(new QName("match"), "/");
0357: template.addChild(literal);
0358:
0359: template.generateDeclaration(getOut());
0360:
0361: template.generate(getOut());
0362:
0363: // printTemplate(top, null, "/", null, 0.0/0.0);
0364:
0365: _isCacheable = oldCacheable;
0366: _defaultCacheable = oldDefaultCacheable;
0367: }
0368:
0369: addNamespace(top);
0370: StylesheetImpl stylesheet = completeGenerate(_inits,
0371: _globalActions);
0372:
0373: return stylesheet;
0374: }
0375:
0376: private static CharScanner commaDelimScanner = new CharScanner(
0377: " \t\n\r,");
0378:
0379: /**
0380: * Scan the stylesheet for imported packages and files. The imported
0381: * stylesheets will be read and stored in the 'files' HashMap for when
0382: * they're actually needed.
0383: */
0384: private void scanFiles(Element top) throws XslParseException,
0385: IOException {
0386: _isCauchoXsl = !top.getAttribute("xsl-caucho").equals("");
0387:
0388: Iterator iter;
0389: try {
0390: iter = XPath.select("//xtp:directive.page/@*", top);
0391: } catch (Exception e) {
0392: throw new XslParseException(e);
0393: }
0394: while (iter.hasNext()) {
0395: Attr attr = (Attr) iter.next();
0396: String name = attr.getNodeName();
0397: String value = attr.getNodeValue();
0398:
0399: if (name.equals("import")) {
0400: StringCharCursor cursor = new StringCharCursor(value);
0401: CharBuffer cb = new CharBuffer();
0402: while (cursor.current() != cursor.DONE) {
0403: char ch;
0404: commaDelimScanner.skip(cursor);
0405:
0406: cb.clear();
0407: ch = commaDelimScanner.scan(cursor, cb);
0408:
0409: if (cb.length() != 0) {
0410: addImport(cb.toString());
0411: } else if (ch != cursor.DONE)
0412: throw new IOException(L
0413: .l("illegal `import' directive"));
0414: }
0415: }
0416: }
0417:
0418: try {
0419: iter = XPath.select("//xsl:import|xsl:include", top);
0420: } catch (Exception e) {
0421: throw new XslParseException(e);
0422: }
0423: while (iter.hasNext()) {
0424: Element elt = (Element) iter.next();
0425: String href = elt.getAttribute("href");
0426:
0427: ReadStream rs;
0428:
0429: try {
0430: rs = _xslGenerator.openPath(href, _context.getURL());
0431: } catch (Exception e) {
0432: throw new XslParseException(e);
0433: }
0434:
0435: Path path = rs.getPath();
0436:
0437: Document xsl = readXsl(rs);
0438: Element subtop = xsl.getDocumentElement();
0439:
0440: if (subtop == null)
0441: throw error(elt, L.l("xsl:import file {0} is empty",
0442: path.getFullPath()));
0443:
0444: Path oldContext = _context;
0445:
0446: Path virtualPath = _context.getParent().lookup(href);
0447: _context = virtualPath;
0448:
0449: _files.put(virtualPath.getPath(), xsl);
0450:
0451: scanFiles(subtop);
0452: _context = oldContext;
0453: }
0454: }
0455:
0456: public void addImportList(String value) throws XslParseException {
0457: StringCharCursor cursor = new StringCharCursor(value);
0458: CharBuffer cb = new CharBuffer();
0459: while (cursor.current() != cursor.DONE) {
0460: char ch;
0461: commaDelimScanner.skip(cursor);
0462:
0463: cb.clear();
0464: ch = commaDelimScanner.scan(cursor, cb);
0465:
0466: if (cb.length() != 0) {
0467: addImport(cb.toString());
0468: } else if (ch != cursor.DONE)
0469: throw error(L.l("illegal `import' directive"));
0470: }
0471: }
0472:
0473: /**
0474: * Read in an imported or included XSL file.
0475: *
0476: * @param path Path to the include files.
0477: *
0478: * @return XML tree describing the XSL.
0479: */
0480: Document readXsl(Path path) throws IOException, XslParseException {
0481: return readXsl(path.openRead());
0482: }
0483:
0484: /**
0485: * Read in an imported or included XSL file.
0486: *
0487: * @param path Path to the include files.
0488: *
0489: * @return XML tree describing the XSL.
0490: */
0491: Document readXsl(ReadStream file) throws IOException,
0492: XslParseException {
0493: try {
0494: addDepend(file.getPath());
0495:
0496: if (_isStyleScript) {
0497: XslParser parser = new XslParser();
0498:
0499: return parser.parse(file);
0500: } else
0501: return new Xml().parseDocument(file);
0502: } catch (org.xml.sax.SAXException e) {
0503: throw new XslParseException(e);
0504: } finally {
0505: file.close();
0506: }
0507: }
0508:
0509: /**
0510: * Start the top-level stylesheet generation.
0511: */
0512: private void generateStylesheet(Element elt, boolean isTop)
0513: throws Exception {
0514: QElement element = (QElement) elt;
0515: _isCauchoXsl = !element.getAttribute("xsl-caucho").equals("");
0516:
0517: String systemId = element.getBaseURI();
0518: Path oldContext = _context;
0519:
0520: if (systemId != null)
0521: _context = _context.lookup(systemId);
0522:
0523: XslNode stylesheet = createChild(element);
0524:
0525: addNamespace(element);
0526:
0527: if (isTop)
0528: printHeader();
0529:
0530: stylesheet.generateDeclaration(getOut());
0531:
0532: stylesheet.generate(getOut());
0533:
0534: _context = oldContext;
0535:
0536: /*
0537: _version = element.getAttribute("version");
0538: if (_version.equals(""))
0539: _version = "1.0";
0540:
0541: // generateAttributeSets(element);
0542:
0543: excludeNamespaces(element);
0544:
0545: String xslSpace = element.getAttribute("xsl-space");
0546: ArrayList<XslNode> children = new ArrayList<XslNode>();
0547: for (Node child = element.getFirstChild();
0548: child != null;
0549: child = child.getNextSibling()) {
0550: if (! (child instanceof Element))
0551: continue;
0552:
0553: int code = -1;
0554: String name = getXslLocal(child);
0555: if (name != null)
0556: code = _tags.get(name);
0557: else if ((name = getXtpLocal(child)) != null)
0558: code = _xtpTags.get(name);
0559: else {
0560: String childName = child.getNodeName();
0561:
0562: if (childName.startsWith("jsp:directive.") ||
0563: childName.equals("jsp:declaration") ||
0564: childName.equals("jsp:scriptlet"))
0565: addGlobalAction((Element) child);
0566: continue;
0567: }
0568:
0569: NamespaceContext oldNamespace = addNamespace((Element) child);
0570: // generateTopLevelNode(code, (Element) child);
0571: XslNode node = createChild(child);
0572:
0573: children.add(node);
0574: _namespace = oldNamespace;
0575: }
0576:
0577: for (int i = 0; i < children.size(); i++) {
0578: XslNode node = children.get(i);
0579:
0580: node.generate(getOut());
0581: }
0582: */
0583: }
0584:
0585: abstract protected JavaWriter getOut();
0586:
0587: abstract protected XslNode createChild(Node child) throws Exception;
0588:
0589: abstract protected XslNode createChild(XslNode parent, Node child)
0590: throws Exception;
0591:
0592: private void addGlobalAction(Element elt) {
0593: _globalActions.add(elt);
0594: }
0595:
0596: /**
0597: * Converts the exclude-result-prefixes into the "excludedNamespaces"
0598: * hashMap for later use.
0599: */
0600: private void excludeNamespaces(Element element) throws Exception {
0601: if (!(element instanceof QElement))
0602: return;
0603:
0604: QElement elt = (QElement) element;
0605: String excludeNamespace;
0606: excludeNamespace = element
0607: .getAttribute("exclude-result-prefixes");
0608: if (!excludeNamespace.equals("")) {
0609: for (String prefix : excludeNamespace.split("[,\\s]+")) {
0610:
0611: String ns = elt.getNamespace(prefix);
0612: if (ns == null)
0613: throw error(elt, L.l(
0614: "`{0}' must be a namespace prefix", prefix));
0615: _excludedNamespaces.put(ns, "");
0616: }
0617: }
0618: }
0619:
0620: public void addExcludedNamespace(String ns) {
0621: _excludedNamespaces.put(ns, "");
0622: }
0623:
0624: public void addInit(XslNode node) {
0625: _inits.add(node);
0626: }
0627:
0628: public void addGlobalParameter(String param) {
0629: _globalParameters.add(param);
0630: }
0631:
0632: /**
0633: * Adds a file dependency for cacheable references to the output of
0634: * the stylesheet.
0635: */
0636: private void addCacheDepends(String attr) {
0637: if (attr.equals(""))
0638: return;
0639:
0640: int i = 0;
0641: int ch = 0;
0642: int len = attr.length();
0643: for (; i < len && XmlChar.isWhitespace((ch = attr.charAt(i)))
0644: || ch == ','; i++) {
0645: }
0646: CharBuffer cb = new CharBuffer();
0647: while (i < len) {
0648: cb.clear();
0649: for (; i < len
0650: && !XmlChar.isWhitespace((ch = attr.charAt(i)))
0651: && ch != ','; i++) {
0652: cb.append((char) ch);
0653: }
0654:
0655: _cacheDepends.add(cb.toString());
0656:
0657: for (; i < len
0658: && XmlChar.isWhitespace((ch = attr.charAt(i)))
0659: || ch == ','; i++) {
0660: }
0661: }
0662: }
0663:
0664: private void generateCacheDepends(String attr) throws Exception {
0665: if (attr.equals(""))
0666: return;
0667:
0668: int i = 0;
0669: int ch = 0;
0670: int len = attr.length();
0671: for (; i < len && XmlChar.isWhitespace((ch = attr.charAt(i)))
0672: || ch == ','; i++) {
0673: }
0674: CharBuffer cb = new CharBuffer();
0675: while (i < len) {
0676: cb.clear();
0677: for (; i < len
0678: && !XmlChar.isWhitespace((ch = attr.charAt(i)))
0679: && ch != ','; i++) {
0680: cb.append((char) ch);
0681: }
0682:
0683: printCacheDepends(cb.toString());
0684:
0685: for (; i < len
0686: && XmlChar.isWhitespace((ch = attr.charAt(i)))
0687: || ch == ','; i++) {
0688: }
0689: }
0690: }
0691:
0692: /**
0693: * Generate code for xsl:template
0694: */
0695: void generateTemplate(Element element) throws Exception {
0696: String name = element.getAttribute("name");
0697: String patternString = element.getAttribute("match");
0698: String mode = element.getAttribute("mode");
0699: String priority = element.getAttribute("priority");
0700: double dPriority = 0.0 / 0.0;
0701:
0702: if (!name.equals(""))
0703: _macros.put(name, name);
0704:
0705: if (name.equals("") && patternString.equals(""))
0706: throw error("xsl:template expects a `name' or a `match' attribute.");
0707:
0708: if (!priority.equals("")) {
0709: try {
0710: dPriority = Double.valueOf(priority).doubleValue();
0711: } catch (Exception e) {
0712: throw error("xsl:template expects `priority' must be a double.");
0713: }
0714: }
0715:
0716: boolean oldCacheable = _isCacheable;
0717: boolean oldDefaultCacheable = _defaultCacheable;
0718: AbstractPattern oldNodeListContext = _nodeListContext;
0719: if (!patternString.equals(""))
0720: _nodeListContext = parseMatch(patternString);
0721:
0722: _isCacheable = true;
0723: printTemplate(element, name, patternString, mode, dPriority);
0724: _nodeListContext = oldNodeListContext;
0725: _isCacheable = oldCacheable;
0726: _defaultCacheable = oldDefaultCacheable;
0727: }
0728:
0729: public XslNode generateImport(String href) throws Exception {
0730: Path path = lookupPath(href);
0731:
0732: if (_files.get(path.getPath()) != null)
0733: return null;
0734:
0735: Document xsl = readFile(href, path);
0736:
0737: if (xsl == null)
0738: throw new FileNotFoundException(href);
0739:
0740: QElement top = (QElement) xsl.getDocumentElement();
0741: if (top == null || !"stylesheet".equals(getXslLocal(top))
0742: && !"transform".equals(getXslLocal(top))) {
0743: throw error("imported stylesheet `" + href
0744: + "' missing xsl:stylesheet.");
0745: }
0746:
0747: int oldMinImportance = _minImportance;
0748: Path oldContext = _context;
0749: Path virtualPath = _context.getParent().lookup(href);
0750: _context = virtualPath;
0751: _minImportance = _importance;
0752: boolean oldTop = _isTop;
0753: boolean oldRaw = _isRawText;
0754: _isTop = false;
0755: _isRawText = false;
0756:
0757: String systemId = top.getBaseURI();
0758:
0759: if (systemId != null)
0760: _context = _context.lookup(systemId);
0761:
0762: XslStylesheet stylesheet = (XslStylesheet) createChild(top);
0763:
0764: _isRawText = oldRaw;
0765: _isTop = oldTop;
0766: _minImportance = oldMinImportance;
0767: _context = oldContext;
0768:
0769: incrementImportance();
0770:
0771: return stylesheet;
0772: }
0773:
0774: /**
0775: * Generates code for xsl:include. The included file has the same
0776: * importance as the containing file.
0777: */
0778: void generateInclude(Element element) throws Exception {
0779: String href = element.getAttribute("href");
0780: if (href.equals(""))
0781: throw error("xsl:include expects `href' attribute.");
0782:
0783: if (element.getFirstChild() != null)
0784: throw error("xsl:include must be empty");
0785: }
0786:
0787: public void generateInclude(XslNode parent, String href)
0788: throws Exception {
0789: Path path = lookupPath(href);
0790:
0791: if (_files.get(path.getPath()) != null)
0792: return;
0793:
0794: Document xsl = readFile(href, path);
0795:
0796: Element top = (Element) xsl.getDocumentElement();
0797: if (top == null || !"stylesheet".equals(getXslLocal(top))
0798: && !"transform".equals(getXslLocal(top))) {
0799: throw error("imported stylesheet `" + href
0800: + "' missing xsl:stylesheet.");
0801: }
0802:
0803: Path oldContext = _context;
0804: _context = path;
0805:
0806: for (Node node = top.getFirstChild(); node != null; node = node
0807: .getNextSibling()) {
0808: XslNode child = createChild(parent, node);
0809:
0810: if (child != null)
0811: parent.addChild(child);
0812: }
0813:
0814: // generateStylesheet(top, false);
0815:
0816: _context = oldContext;
0817: }
0818:
0819: /**
0820: * Returns the actual path for the relative href.
0821: */
0822: private Path lookupPath(String href) {
0823: return _context.getParent().lookup(href);
0824: }
0825:
0826: private Document readFile(String href, Path virtualPath)
0827: throws Exception {
0828: Document xsl = (Document) _files.get(virtualPath.getPath());
0829:
0830: if (xsl != null)
0831: throw new IllegalStateException(L
0832: .l("'{0}' is a duplicated path", virtualPath
0833: .getPath()));
0834:
0835: ReadStream rs;
0836:
0837: try {
0838: rs = _xslGenerator.openPath(href, _context.getURL());
0839: } catch (Exception e) {
0840: throw new XslParseException(e);
0841: }
0842:
0843: Path path = rs.getPath();
0844:
0845: xsl = readXsl(rs);
0846: Element subtop = xsl.getDocumentElement();
0847:
0848: if (subtop == null)
0849: throw error(L.l("xsl:import file {0} is empty", path
0850: .getFullPath()));
0851:
0852: Path oldContext = _context;
0853:
0854: _context = virtualPath;
0855:
0856: _files.put(virtualPath.getPath(), xsl);
0857:
0858: _context = oldContext;
0859:
0860: return xsl;
0861: }
0862:
0863: void generateKey(Element element) throws Exception {
0864: String name = element.getAttribute("name");
0865: if (name.equals(""))
0866: throw error("xsl:key expects `name' attribute.");
0867: String match = element.getAttribute("match");
0868: if (match.equals(""))
0869: throw error("xsl:key expects `match' attribute.");
0870: String use = element.getAttribute("use");
0871: if (use.equals(""))
0872: throw error("xsl:key expects `use' attribute.");
0873:
0874: if (element.getFirstChild() != null)
0875: throw error("xsl:key must be empty");
0876:
0877: _keyFun.add(name, parseMatch(match), parseExpr(use));
0878: }
0879:
0880: public void addKey(String name, AbstractPattern match, Expr use) {
0881: _keyFun.add(name, match, use);
0882: }
0883:
0884: void generateLocale(Element element) throws Exception {
0885: String name = element.getAttribute("name");
0886: if (name.equals(""))
0887: name = "*";
0888:
0889: DecimalFormatSymbols format = new DecimalFormatSymbols();
0890:
0891: String value = element.getAttribute("decimal-separator");
0892: if (value.length() > 0)
0893: format.setDecimalSeparator(value.charAt(0));
0894:
0895: value = element.getAttribute("grouping-separator");
0896: if (value.length() > 0)
0897: format.setGroupingSeparator(value.charAt(0));
0898:
0899: value = element.getAttribute("infinity");
0900: if (!value.equals(""))
0901: format.setInfinity(value);
0902:
0903: value = element.getAttribute("minus-sign");
0904: if (value.length() > 0)
0905: format.setMinusSign(value.charAt(0));
0906:
0907: value = element.getAttribute("NaN");
0908: if (!value.equals(""))
0909: format.setNaN(value);
0910:
0911: value = element.getAttribute("percent");
0912: if (value.length() > 0)
0913: format.setPercent(value.charAt(0));
0914:
0915: value = element.getAttribute("per-mille");
0916: if (value.length() > 0)
0917: format.setPerMill(value.charAt(0));
0918:
0919: value = element.getAttribute("zero-digit");
0920: if (value.length() > 0)
0921: format.setZeroDigit(value.charAt(0));
0922:
0923: value = element.getAttribute("digit");
0924: if (value.length() > 0)
0925: format.setDigit(value.charAt(0));
0926:
0927: value = element.getAttribute("pattern-separator");
0928: if (value.length() > 0)
0929: format.setPatternSeparator(value.charAt(0));
0930:
0931: _formatNumberFun.addLocale(name, format);
0932: }
0933:
0934: void generateNamespaceAlias(Element element) throws Exception {
0935: if (!(element instanceof QElement))
0936: return;
0937:
0938: QElement elt = (QElement) element;
0939: String stylesheetPrefix;
0940: String resultPrefix;
0941:
0942: stylesheetPrefix = (String) element
0943: .getAttribute("stylesheet-prefix");
0944: resultPrefix = (String) element.getAttribute("result-prefix");
0945:
0946: if (stylesheetPrefix.equals(""))
0947: throw error(element,
0948: "xsl:namespace-alias needs `stylesheet-prefix'");
0949: if (resultPrefix.equals(""))
0950: throw error(element,
0951: "xsl:namespace-alias needs `result-prefix'");
0952: }
0953:
0954: public void addNamespaceAlias(String stylesheetPrefix,
0955: String resultPrefix) {
0956: /*
0957: String stylesheetNs = getNamespace(stylesheetPrefix);
0958: if (stylesheetPrefix.equals("#default"))
0959: stylesheetNs = "";
0960: else if (stylesheetNs.equals(""))
0961: throw error("`" + stylesheetPrefix + "' is not a valid namespace prefix");
0962: String resultNs = getNamespace(resultPrefix);
0963: if (resultPrefix.equals("#default")) {
0964: resultPrefix = "";
0965: resultNs = "";
0966: }
0967: else if (resultNs.equals(""))
0968: throw error("`" + resultPrefix + "' is not a valid namespace prefix");
0969:
0970: String result[] = new String[] { resultPrefix, resultNs };
0971: _namespaceAliases.put(stylesheetNs, result);
0972: */
0973: }
0974:
0975: public void addNamespaceAlias(String namespace, String[] result) {
0976: _namespaceAliases.put(namespace, result);
0977: }
0978:
0979: public String[] getNamespaceAlias(String namespace) {
0980: return _namespaceAliases.get(namespace);
0981: }
0982:
0983: /**
0984: * Scans through the stylesheet, grabbing the attribute set
0985: * definitions.
0986: *
0987: * @param element the current nost
0988: */
0989: /*
0990: void generateAttributeSets(Element element)
0991: throws Exception
0992: {
0993: Node child = element.getFirstChild();
0994:
0995: for (; child != null; child = child.getNextSibling()) {
0996: if (! "attribute-set".equals(getXslLocal(child)))
0997: continue;
0998:
0999: QElement elt = (QElement) child;
1000: String name = elt.getAttribute("name");
1001: if (name.equals(""))
1002: throw error(L.l("xsl:attribute-set expects `name' attribute."));
1003:
1004: generateAttributeSet(element, name);
1005: }
1006: }
1007: */
1008:
1009: /**
1010: * Scans through the stylesheet, grabbing the attribute set
1011: * definitions.
1012: *
1013: * @param element the current node
1014: */
1015: /*
1016: HashMap<String,String> generateAttributeSet(Element element, String setName)
1017: throws Exception
1018: {
1019: Node child = element.getFirstChild();
1020:
1021: for (; child != null; child = child.getNextSibling()) {
1022: if (! "attribute-set".equals(getXslLocal(child)))
1023: continue;
1024:
1025: QElement elt = (QElement) child;
1026: String name = elt.getAttribute("name");
1027: if (name.equals(""))
1028: throw error(L.l("xsl:attribute-set expects `name' attribute."));
1029:
1030: if (! name.equals(setName))
1031: continue;
1032:
1033: HashMap<String,String> set = _attributeSets.get(name);
1034: if (set != null)
1035: return set;
1036:
1037: set = new HashMap<String,String>();
1038: _attributeSets.put(name, set);
1039:
1040: // add any attributes from use-attribute-sets
1041: for (Node attr = elt.getFirstAttribute();
1042: attr != null;
1043: attr = attr.getNextSibling()) {
1044: if (attr.getNodeName().equals("use-attribute-sets")) {
1045: HashMap<String,String> subset = generateAttributeSet(element, attr.getNodeValue());
1046:
1047: if (subset == null)
1048: throw error(elt, L.l("Unknown attribute-set `{0}'. Each use-attribute-sets needs a matching xsl:attribute-set.", attr.getNodeValue()));
1049: Iterator<String> iter = subset.keySet().iterator();
1050: while (iter.hasNext()) {
1051: String key = iter.next();
1052: set.put(key, subset.get(key));
1053: }
1054: }
1055: }
1056:
1057: for (Node attr = elt.getFirstChild();
1058: attr != null;
1059: attr = attr.getNextSibling()) {
1060: if (! "attribute".equals(getXslLocal(attr)))
1061: continue;
1062: Element attrElt = (Element) attr;
1063: String attrName = attrElt.getAttribute("name");
1064: if (attrName.equals(""))
1065: throw error(L.l("xsl:attribute expects `name' attribute."));
1066:
1067: set.put(attrName, ((QElement) attr).getTextValue());
1068: }
1069:
1070: for (Attr attr = ((QElement) elt).getFirstAttribute();
1071: attr != null;
1072: attr = (Attr) attr.getNextSibling()) {
1073: if (attr.getNodeName().equals("name") ||
1074: attr.getNodeName().equals("use-attribute-sets"))
1075: continue;
1076:
1077: set.put(attr.getNodeName(), attr.getNodeValue());
1078: }
1079:
1080: return set;
1081: }
1082:
1083: return null;
1084: }
1085: */
1086:
1087: public void addAttributeSet(String name,
1088: XslAttributeSet attributeSet) {
1089: _attributeSets.put(name, attributeSet);
1090: }
1091:
1092: /*
1093: public XslAttributeSet getAttributeSet(String name)
1094: {
1095: return _attributeSets.get(name);
1096: }
1097: */
1098:
1099: public void setDisableOutputEscaping(boolean disable) {
1100: _isRawText = disable;
1101: }
1102:
1103: public boolean getDisableOutputEscaping() {
1104: return _isRawText;
1105: }
1106:
1107: private void generateOutput(Element element) throws Exception {
1108: Node attr = ((QElement) element).getFirstAttribute();
1109:
1110: if (element.getFirstChild() != null)
1111: throw error("xsl:output must be empty");
1112:
1113: String disableEscaping;
1114: disableEscaping = element
1115: .getAttribute("resin:disable-output-escaping");
1116: if (disableEscaping.equals(""))
1117: disableEscaping = element
1118: .getAttribute("disable-output-escaping");
1119: if (disableEscaping.equals("no")
1120: || disableEscaping.equals("false"))
1121: _isRawText = false;
1122: else if (!disableEscaping.equals(""))
1123: _isRawText = true;
1124:
1125: // Only top-level xsl:output matters (XXX: spec?)
1126: if (!_isTop)
1127: return;
1128:
1129: if (_outputAttributes == null)
1130: _outputAttributes = new HashMap<String, String>();
1131:
1132: for (; attr != null; attr = attr.getNextSibling()) {
1133: _outputAttributes.put(attr.getNodeName(), attr
1134: .getNodeValue());
1135: }
1136: }
1137:
1138: public void setOutputAttribute(String name, String value) {
1139: _outputAttributes.put(name, value);
1140: }
1141:
1142: private void generatePreserveSpace(Element element)
1143: throws Exception {
1144: String elements = element.getAttribute("elements");
1145: if (elements.equals(""))
1146: throw error("xsl:preserve-space expects `elements' attribute.");
1147:
1148: if (element.getFirstChild() != null)
1149: throw error("xsl:preserve-space must be empty");
1150:
1151: int i = 0;
1152: int len = elements.length();
1153: for (; i < len && XmlChar.isWhitespace(elements.charAt(i)); i++) {
1154: }
1155: CharBuffer cb = new CharBuffer();
1156: while (i < len) {
1157: cb.clear();
1158:
1159: for (; i < len && !XmlChar.isWhitespace(elements.charAt(i)); i++)
1160: cb.append(elements.charAt(i));
1161:
1162: _preserve.put(cb.toString(), "true");
1163:
1164: for (; i < len && XmlChar.isWhitespace(elements.charAt(i)); i++) {
1165: }
1166: }
1167: }
1168:
1169: private void generateStripSpace(Element element) throws Exception {
1170: throw new UnsupportedOperationException();
1171: /*
1172: String elements = element.getAttribute("elements");
1173: if (elements.equals(""))
1174: throw error("xsl:strip-space expects `elements' attribute.");
1175:
1176: if (element.getFirstChild() != null)
1177: throw error("xsl:strip-space must be empty");
1178: */
1179: }
1180:
1181: public void addStripSpace(String elements) {
1182: int i = 0;
1183: int len = elements.length();
1184: for (; i < len && XmlChar.isWhitespace(elements.charAt(i)); i++) {
1185: }
1186: CharBuffer cb = new CharBuffer();
1187: while (i < len) {
1188: cb.clear();
1189:
1190: for (; i < len && !XmlChar.isWhitespace(elements.charAt(i)); i++) {
1191: cb.append(elements.charAt(i));
1192: }
1193:
1194: _strip.put(cb.toString(), "true");
1195:
1196: for (; i < len && XmlChar.isWhitespace(elements.charAt(i)); i++) {
1197: }
1198: }
1199: }
1200:
1201: public void addPreserveSpace(String elements) {
1202: int i = 0;
1203: int len = elements.length();
1204: for (; i < len && XmlChar.isWhitespace(elements.charAt(i)); i++) {
1205: }
1206: CharBuffer cb = new CharBuffer();
1207: while (i < len) {
1208: cb.clear();
1209:
1210: for (; i < len && !XmlChar.isWhitespace(elements.charAt(i)); i++) {
1211: cb.append(elements.charAt(i));
1212: }
1213:
1214: _preserve.put(cb.toString(), "true");
1215:
1216: for (; i < len && XmlChar.isWhitespace(elements.charAt(i)); i++) {
1217: }
1218: }
1219: }
1220:
1221: protected void generateChildren(Node node) throws Exception {
1222: _vars.add(0);
1223: for (Node child = node.getFirstChild(); child != null; child = child
1224: .getNextSibling()) {
1225: generateChild(child);
1226: }
1227: int count = _vars.pop();
1228: if (count > 0 && _vars.size() > 0)
1229: printPopScope(count);
1230: }
1231:
1232: protected void generateChild(Node child) throws Exception {
1233: generateChildImpl(child);
1234: }
1235:
1236: public void generateChildImpl(Node child) throws Exception {
1237: String nodeName = getXslLocal(child);
1238: int code = -1;
1239: if (nodeName != null)
1240: code = _tags.get(nodeName);
1241: else if ((nodeName = getXtpLocal(child)) != null)
1242: code = _xtpTags.get(nodeName);
1243: /* XXX: xsl/04al
1244: else if (macros.get(child.getNodeName()) != null) {
1245: generateMacro((Element) child);
1246: return;
1247: }
1248: */
1249:
1250: if (nodeName == null) {
1251: if (child.getNodeType() == child.TEXT_NODE)
1252: generateText(child);
1253: else if (child.getNodeType() == child.ELEMENT_NODE) {
1254: NamespaceContext oldNamespace = addNamespace((Element) child);
1255: printElement((Element) child);
1256: _namespace = oldNamespace;
1257: }
1258: return;
1259: }
1260:
1261: if (child instanceof QElement) {
1262: NamespaceContext oldNamespace = addNamespace((QElement) child);
1263: generateChild(child, code);
1264: _namespace = oldNamespace;
1265: } else
1266: generateChild(child, code);
1267: }
1268:
1269: public void generateChild(Node child, int code) throws Exception {
1270: if (child instanceof QAbstractNode) {
1271: QAbstractNode qChild = (QAbstractNode) child;
1272: setLocation(qChild.getBaseURI(), qChild.getFilename(),
1273: qChild.getLine());
1274: }
1275:
1276: switch (code) {
1277: case TEXT:
1278: generateText(child);
1279: break;
1280:
1281: case XSL_TEXT:
1282: generateXslText((Element) child);
1283: break;
1284:
1285: case APPLY_TEMPLATES:
1286: generateApplyTemplates((Element) child);
1287: break;
1288:
1289: case APPLY_IMPORTS:
1290: generateApplyImports((Element) child);
1291: break;
1292:
1293: case CALL_TEMPLATE:
1294: generateCallTemplate((Element) child);
1295: break;
1296:
1297: case PARAM:
1298: generateParamVariable((Element) child);
1299: break;
1300:
1301: case VARIABLE:
1302: generateVariable((Element) child);
1303: break;
1304:
1305: case VALUE_OF:
1306: generateValueOf((Element) child);
1307: break;
1308:
1309: case COPY_OF:
1310: generateCopyOf((Element) child);
1311: break;
1312:
1313: case FOR_EACH:
1314: generateForEach((Element) child);
1315: break;
1316:
1317: case IF:
1318: generateIf((Element) child);
1319: break;
1320:
1321: case CHOOSE:
1322: generateChoose((Element) child);
1323: break;
1324:
1325: case NUMBER:
1326: generateNumber((Element) child);
1327: break;
1328:
1329: case COPY:
1330: printCopy((Element) child);
1331: break;
1332:
1333: case COPY_ELEMENT:
1334: printCopyElement((Element) child);
1335: break;
1336:
1337: case ELEMENT:
1338: generateElement((Element) child);
1339: break;
1340:
1341: case ATTRIBUTE:
1342: generateAttribute((Element) child);
1343: break;
1344:
1345: case PI:
1346: printPi((Element) child);
1347: break;
1348:
1349: case COMMENT:
1350: printComment((Element) child);
1351: break;
1352:
1353: case MESSAGE:
1354: printMessage((Element) child);
1355: break;
1356:
1357: case EXPRESSION:
1358: if (!_defaultCacheable)
1359: _isCacheable = false;
1360: printExpression((Element) child);
1361: break;
1362:
1363: case SCRIPTLET:
1364: if (!_defaultCacheable)
1365: _isCacheable = false;
1366: printScriptlet((Element) child);
1367: break;
1368:
1369: case DIRECTIVE_CACHE:
1370: generateCacheDepends(((Element) child).getAttribute("file"));
1371: if (!((Element) child).getAttribute("no-cache").equals("")) {
1372: _isCacheable = false;
1373: _defaultCacheable = false;
1374: } else
1375: _defaultCacheable = true;
1376: break;
1377:
1378: case WHILE:
1379: generateWhile((Element) child);
1380: break;
1381:
1382: case ASSIGN:
1383: generateAssign((Element) child);
1384: break;
1385:
1386: case RESULT_DOCUMENT:
1387: generateResultDocument((Element) child);
1388: break;
1389:
1390: case IGNORE:
1391: break;
1392:
1393: default:
1394: if (child instanceof QElement
1395: && XSLNS.equals(((QElement) child)
1396: .getNamespaceURI()) && _version != null
1397: && _version.equals("1.0"))
1398: throw error(child, "unknown XSL element `"
1399: + child.getNodeName() + "'");
1400: else {
1401: Node subchild = child.getFirstChild();
1402: boolean hasFallback = false;
1403: for (; subchild != null; subchild = subchild
1404: .getNextSibling()) {
1405: String local = getXslLocal(subchild);
1406: if (local != null && local.equals("fallback")) {
1407: hasFallback = true;
1408: generateChildren(subchild);
1409: }
1410: }
1411: if (!hasFallback) // && child.getNamespace().equals(XSLNS))
1412: printError(L.l("expected xsl tag at `{0}'", child
1413: .getNodeName()));
1414: }
1415: break;
1416: }
1417: }
1418:
1419: private void generateText(Node node) throws Exception {
1420: String data = node.getNodeValue();
1421: int length = data.length();
1422:
1423: if (length == 0)
1424: return;
1425:
1426: int i = 0;
1427: for (; i < length && XmlChar.isWhitespace(data.charAt(i)); i++) {
1428: }
1429:
1430: if (i == length && stripNode(node))
1431: return;
1432:
1433: if (data != null && data.length() > 0
1434: && node instanceof QAbstractNode) {
1435: setLocation(node);
1436: writeText(data);
1437: }
1438: }
1439:
1440: private boolean stripNode(Node node) {
1441: for (node = node.getParentNode(); node != null; node = node
1442: .getParentNode()) {
1443: if (node instanceof Element) {
1444: Element elt = (Element) node;
1445: String space = elt.getAttribute("xml:space");
1446: if (!space.equals(""))
1447: return !space.equals("preserve");
1448: }
1449: }
1450:
1451: return true;
1452: }
1453:
1454: void generateXslText(Element element) throws Exception {
1455: _text.clear();
1456: for (Node child = element.getFirstChild(); child != null; child = child
1457: .getNextSibling()) {
1458: if (!(child instanceof Text))
1459: continue;
1460:
1461: String data = child.getNodeValue();
1462: int length = data.length();
1463:
1464: _text.append(data);
1465: }
1466:
1467: String disableEscaping = element
1468: .getAttribute("disable-output-escaping");
1469: if (disableEscaping.equals(""))
1470: disableEscaping = "no";
1471:
1472: if (_text.length() <= 0) {
1473: } else if (!disableEscaping.equals("yes")
1474: && !disableEscaping.equals("true"))
1475: writeText(_text.toString());
1476: else {
1477: startDisableEscaping();
1478: writeText(_text.toString());
1479: endDisableEscaping();
1480: }
1481: }
1482:
1483: private void generateApplyTemplates(Node node) throws Exception {
1484: QElement element = (QElement) node;
1485: String select = element.getAttribute("select");
1486: String mode = element.getAttribute("mode");
1487: AbstractPattern selectPattern = null;
1488: if (!select.equals(""))
1489: selectPattern = parseSelect(select, node);
1490:
1491: Sort[] sort = generateSort(node);
1492:
1493: if (sort != null && selectPattern == null)
1494: selectPattern = parseSelect("*", node);
1495:
1496: pushCall();
1497: generateArgs(element);
1498: printApplyTemplates(selectPattern, mode, sort);
1499: popCall();
1500: }
1501:
1502: private void generateApplyImports(Node node) throws Exception {
1503: QElement element = (QElement) node;
1504: String mode = element.getAttribute("mode");
1505:
1506: if (element.getFirstChild() != null)
1507: throw error(L.l("xsl:apply-imports must be empty"));
1508:
1509: pushCall();
1510: generateArgs(element);
1511: printApplyImports(mode, _minImportance, _importance);
1512: popCall();
1513: }
1514:
1515: private void generateCallTemplate(Element element) throws Exception {
1516: String name = element.getAttribute("name");
1517: String mode = element.getAttribute("mode");
1518:
1519: if (name.equals(""))
1520: throw error(L.l("{0} expects `{1}' attribute",
1521: "xsl:call-template", "name"));
1522:
1523: if (findMacro(name) == null)
1524: throw error(
1525: element,
1526: L
1527: .l(
1528: "`{0}' is an unknown macro for xsl:call-template. All macros must be defined in an <xsl:template name='...'> element.",
1529: name));
1530:
1531: pushCall();
1532: generateArgs(element);
1533: printCallTemplate(name, mode);
1534: popCall();
1535: }
1536:
1537: private Element findMacro(String name) throws Exception {
1538: Element template = findMacroInDocument(_doc, name);
1539: if (template != null)
1540: return template;
1541:
1542: Iterator iter = _files.values().iterator();
1543: while (iter.hasNext()) {
1544: Document doc = (Document) iter.next();
1545:
1546: template = findMacroInDocument(doc, name);
1547:
1548: if (template != null)
1549: return template;
1550: }
1551:
1552: return null;
1553: }
1554:
1555: private Element findMacroInDocument(Document doc, String name) {
1556: Element elt = doc.getDocumentElement();
1557:
1558: for (Node child = elt.getFirstChild(); child != null; child = child
1559: .getNextSibling()) {
1560: if (!child.getNodeName().equals("xsl:template"))
1561: continue;
1562:
1563: Element template = (Element) child;
1564:
1565: if (template.getAttribute("name").equals(name))
1566: return template;
1567: }
1568:
1569: return null;
1570: }
1571:
1572: private void generateMacro(Element element) throws Exception {
1573: QElement elt = (QElement) element;
1574:
1575: String name = element.getNodeName();
1576: String mode = element.getAttribute("mode");
1577:
1578: pushCall();
1579: for (Node node = elt.getFirstAttribute(); node != null; node = node
1580: .getNextSibling()) {
1581: String argName = node.getNodeName();
1582: String argValue = node.getNodeValue();
1583:
1584: printParam(argName, argValue, elt);
1585: }
1586: printParam("contents", elt);
1587: printCallTemplate(name, mode);
1588: popCall();
1589: }
1590:
1591: private void generateArgs(Element element) throws Exception {
1592: for (Node node = element.getFirstChild(); node != null; node = node
1593: .getNextSibling()) {
1594: String localName = getXslLocal(node);
1595:
1596: if ("with-param".equals(localName)) {
1597: String key = ((Element) node).getAttribute("name");
1598: String expr = ((Element) node).getAttribute("select");
1599: if (key.equals(""))
1600: throw error(L.l("{0} requires `{1}' attribute",
1601: "xsl:with-param", "name"));
1602:
1603: if (!expr.equals(""))
1604: printParam(key, parseExpr(expr));
1605: else
1606: printParam(key, node);
1607: }
1608: }
1609: }
1610:
1611: private void generateParamVariable(Element element)
1612: throws Exception {
1613: int i = _vars.size() - 1;
1614: _vars.set(i, _vars.get(i) + 1);
1615:
1616: String name = element.getAttribute("name");
1617: String expr = element.getAttribute("select");
1618: if (name.equals(""))
1619: throw error(L.l("{0} expects `{1}' attribute", "xsl:param",
1620: "name"));
1621:
1622: if (!expr.equals(""))
1623: printParamVariable(name, parseExpr(expr));
1624: else
1625: printParamVariable(name, element);
1626: }
1627:
1628: private void generateVariable(Element element) throws Exception {
1629: int i = _vars.size() - 1;
1630: _vars.set(i, _vars.get(i) + 1);
1631:
1632: String name = element.getAttribute("name");
1633: String expr = element.getAttribute("select");
1634: if (name.equals(""))
1635: throw error(L.l("{0} expects `{1}' attribute.",
1636: "xsl:variable", "name"));
1637:
1638: if (!expr.equals(""))
1639: printVariable(name, parseExpr(expr));
1640: else
1641: printVariable(name, element);
1642: }
1643:
1644: private void generateAssign(Element element) throws Exception {
1645: String name = element.getAttribute("name");
1646: String expr = element.getAttribute("select");
1647: if (name.equals(""))
1648: throw error(L.l("{0} expects `{1}' attribute.",
1649: "xtp:assign", "name"));
1650:
1651: if (!expr.equals(""))
1652: printAssign(name, parseExpr(expr));
1653: else
1654: printAssign(name, element);
1655: }
1656:
1657: private void generateResultDocument(Element element)
1658: throws Exception {
1659: String href = element.getAttribute("href");
1660: String format = element.getAttribute("format");
1661: if (href.equals(""))
1662: throw error(L.l("{0} expects `{1}' attribute.",
1663: "xtp:result-document", "href"));
1664:
1665: printResultDocument(element, href, format);
1666: }
1667:
1668: private void generateValueOf(Element element) throws Exception {
1669: String select = element.getAttribute("select");
1670: if (select.equals(""))
1671: throw error(L.l("{0} expects `{1}' attribute.",
1672: "xsl:value-of", "select"));
1673:
1674: if (element.getFirstChild() != null)
1675: throw error(L.l("{0} must be empty", "xsl:value-of"));
1676:
1677: String disable = element
1678: .getAttribute("disable-output-escaping");
1679: boolean isDisabled = disable.equals("yes");
1680: if (isDisabled)
1681: startDisableEscaping();
1682:
1683: printSelectValue(select, element);
1684:
1685: if (isDisabled)
1686: endDisableEscaping();
1687: }
1688:
1689: private void generateCopyOf(Element element) throws Exception {
1690: String select = element.getAttribute("select");
1691: if (select.equals(""))
1692: throw error(L.l("{0} expects `{1}' attribute",
1693: "xsl:copy-of", "select"));
1694:
1695: if (element.getFirstChild() != null)
1696: throw error(L.l("{0} must be empty", "xsl:copy-of"));
1697:
1698: printCopyOf(select, element);
1699: }
1700:
1701: /**
1702: * Generates code for the xsl:for-each element
1703: */
1704: void generateForEach(Element element) throws Exception {
1705: String select = element.getAttribute("select");
1706: if (select.equals(""))
1707: throw error(L.l("{0} expects `{1}' attribute",
1708: "xsl:for-each", "select"));
1709:
1710: Sort[] sort = generateSort(element);
1711:
1712: if (sort != null)
1713: printForEach(element, select, sort);
1714: else
1715: printForEach(element, select);
1716: }
1717:
1718: private Sort[] generateSort(Node node) throws XslParseException,
1719: IOException {
1720: ArrayList<Sort> sorts = new ArrayList<Sort>();
1721: sort: for (Node child = node.getFirstChild(); child != null; child = child
1722: .getNextSibling()) {
1723: if (child.getNodeType() == child.TEXT_NODE) {
1724: String data = child.getNodeValue();
1725: for (int i = 0; i < data.length(); i++) {
1726: if (!XmlChar.isWhitespace(data.charAt(i)))
1727: break sort;
1728: }
1729: continue;
1730: } else if (child.getNodeType() == child.COMMENT_NODE
1731: || child.getNodeType() == child.PROCESSING_INSTRUCTION_NODE)
1732: continue;
1733:
1734: String name = getXslLocal(child);
1735: if (!"sort".equals(name))
1736: break;
1737:
1738: Element elt = (Element) child;
1739: String select = elt.getAttribute("select");
1740: if (select.equals(""))
1741: throw error(L.l("{0} expects attribute `{1}'",
1742: "xsl:sort", "select"));
1743:
1744: Expr expr = parseExpr(select);
1745: String order = elt.getAttribute("order");
1746: Expr isAscending = null;
1747: if (order.equals("")) {
1748: isAscending = parseExpr("true()");
1749: } else if (order.startsWith("{") && order.endsWith("}")) {
1750: order = order.substring(1, order.length() - 1);
1751:
1752: isAscending = parseExpr(order + " = 'ascending'");
1753: } else if (order.equals("ascending"))
1754: isAscending = parseExpr("true()");
1755: else
1756: isAscending = parseExpr("false()");
1757:
1758: String dataType = elt.getAttribute("data-type");
1759: boolean isText = true;
1760: if (dataType.equals("number"))
1761: isText = false;
1762:
1763: String lang = elt.getAttribute("lang");
1764: if (lang.equals("")) {
1765: sorts.add(Sort.create(expr, isAscending, isText));
1766: } else {
1767: if (lang.startsWith("{") && lang.endsWith("}"))
1768: lang = lang.substring(1, lang.length() - 1);
1769: else
1770: lang = "'" + lang + "'";
1771:
1772: sorts.add(Sort.create(expr, isAscending,
1773: parseExpr(lang)));
1774: /*
1775: int p = lang.indexOf('-');
1776: Locale locale = null;
1777:
1778: if (p < 0) {
1779: locale = new Locale(lang, "");
1780: }
1781: else {
1782: String language = lang.substring(0, p);
1783:
1784: int q = lang.indexOf(p + 1, '-');
1785:
1786: if (q < 0) {
1787: String country = lang.substring(p + 1);
1788:
1789: locale = new Locale(language, country);
1790: }
1791: else {
1792: String country = lang.substring(p + 1, q);
1793: String variant = lang.substring(q);
1794:
1795: locale = new Locale(language, country, variant);
1796: }
1797: }
1798:
1799: sorts.add(Sort.create(expr, isAscending, lang));
1800: */
1801: }
1802: }
1803:
1804: if (sorts.size() > 0)
1805: return (Sort[]) sorts.toArray(new Sort[sorts.size()]);
1806: else
1807: return null;
1808: }
1809:
1810: void generateIf(Element element) throws Exception {
1811: String test = (String) element.getAttribute("test");
1812: if (test.equals(""))
1813: throw error(L.l("{0} expects `{1}' attribute", "xsl:if",
1814: "test"));
1815:
1816: printIf(element, parseExpr(test));
1817: }
1818:
1819: void generateWhile(Element element) throws Exception {
1820: String test = (String) element.getAttribute("test");
1821: if (test.equals(""))
1822: throw error(L.l("{0} expects `{1}' attribute", "xsl:while",
1823: "test"));
1824:
1825: printWhile(element, parseExpr(test));
1826: }
1827:
1828: void generateChoose(Element element) throws Exception {
1829: boolean first = true;
1830: for (Node child = element.getFirstChild(); child != null; child = child
1831: .getNextSibling()) {
1832: if (!(child instanceof Element))
1833: continue;
1834:
1835: String name = getXslLocal(child);
1836:
1837: if ("when".equals(name)) {
1838: Element elt = (Element) child;
1839: String test = elt.getAttribute("test");
1840: if (test.equals(""))
1841: throw error(L.l("{0} expects `{1}' attribute",
1842: "xsl:when", "test"));
1843:
1844: printChoose(elt, parseExpr(test), first);
1845: first = false;
1846: } else if ("otherwise".equals(name)) {
1847: printOtherwise((Element) child, first);
1848: } else
1849: throw error(L
1850: .l(
1851: "xsl:choose expects `xsl:when' or `xsl:otherwise' at `{0}'",
1852: child.getNodeName()));
1853: }
1854: }
1855:
1856: void generateElement(Element element) throws Exception {
1857: String name = (String) element.getAttribute("name");
1858: if (name.equals(""))
1859: throw error(L.l("{0} expects `{1}' attribute.",
1860: "xsl:element", "name"));
1861: Attr nsAttr = element.getAttributeNode("namespace");
1862:
1863: if (nsAttr == null)
1864: printElement(element, name);
1865: else
1866: printElement(element, name, nsAttr.getNodeValue());
1867: }
1868:
1869: void generateAttribute(Element element) throws Exception {
1870: String name = (String) element.getAttribute("name");
1871: if (name.equals(""))
1872: throw error(L.l("{0} expects `{1}' attribute",
1873: "xsl:attribute", "name"));
1874: Attr nsAttr = element.getAttributeNode("namespace");
1875:
1876: boolean oldSpecial = _isSpecial;
1877: _isSpecial = true;
1878:
1879: if (nsAttr == null)
1880: printAttribute(element, name);
1881: else
1882: printAttribute(element, name, nsAttr.getNodeValue());
1883:
1884: _isSpecial = oldSpecial;
1885: }
1886:
1887: void generateNumber(Element element) throws Exception {
1888: String value = element.getAttribute("value");
1889: String count = element.getAttribute("count");
1890: String from = element.getAttribute("from");
1891: String level = element.getAttribute("level");
1892: String format = element.getAttribute("format");
1893: String letter = element.getAttribute("letter-value");
1894: String separator = element.getAttribute("grouping-separator");
1895: String lang = element.getAttribute("lang");
1896: String size_name = element.getAttribute("grouping-size");
1897:
1898: int size = 0;
1899: for (int i = 0; i < size_name.length(); i++) {
1900: char ch = size_name.charAt(i);
1901: if (ch >= '0' && ch <= '9')
1902: size = 10 * size + ch - '0';
1903: }
1904:
1905: boolean isAlphabetic = true;
1906: if (!letter.equals("alphabetic"))
1907: isAlphabetic = false;
1908:
1909: AbstractPattern countPattern = null;
1910: if (!count.equals(""))
1911: countPattern = parseMatch(count);
1912:
1913: AbstractPattern fromPattern = null;
1914: if (!from.equals(""))
1915: fromPattern = parseMatch(from);
1916:
1917: if (level.equals("") || level.equals("single"))
1918: level = "single";
1919: else if (level.equals("multiple")) {
1920: } else if (level.equals("any")) {
1921: } else
1922: throw error(L.l("xsl:number can't understand level=`{0}'",
1923: level));
1924:
1925: XslNumberFormat xslFormat;
1926: xslFormat = new XslNumberFormat(format, lang, isAlphabetic,
1927: separator, size);
1928:
1929: if (!value.equals(""))
1930: printNumber(parseExpr(value), xslFormat);
1931: else
1932: printNumber(level, countPattern, fromPattern, xslFormat);
1933: }
1934:
1935: void printNumber(Expr expr, XslNumberFormat format)
1936: throws Exception {
1937:
1938: }
1939:
1940: void printNumber(String level, AbstractPattern countPattern,
1941: AbstractPattern fromPattern, XslNumberFormat format)
1942: throws Exception {
1943:
1944: }
1945:
1946: /**
1947: * Sets location code for the node.
1948: */
1949: void setLocation(Node node) throws Exception {
1950: if (node instanceof QAbstractNode) {
1951: setLocation(((QAbstractNode) node).getBaseURI(),
1952: ((QAbstractNode) node).getFilename(),
1953: ((QAbstractNode) node).getLine());
1954: }
1955: }
1956:
1957: public void setLocation(String systemId, String filename, int line)
1958: throws XslParseException, IOException {
1959: if (filename != null) {
1960: _systemId = systemId;
1961: _filename = filename;
1962: _line = line;
1963: // _lineMap.add(filename, line, getOut().getDestLine());
1964: }
1965: }
1966:
1967: int getTextLength() {
1968: return _text.length();
1969: }
1970:
1971: protected void printHeader() throws XslParseException, IOException {
1972: }
1973:
1974: abstract protected void startDisableEscaping() throws Exception;
1975:
1976: abstract protected void endDisableEscaping() throws Exception;
1977:
1978: abstract protected void writeText(String text) throws Exception;
1979:
1980: abstract protected void printTemplate(Element node, String name,
1981: String pattern, String mode, double priority)
1982: throws Exception;
1983:
1984: /**
1985: * Prints location code for the node.
1986: */
1987: void printLocation(Node node) throws Exception {
1988: if (node instanceof QAbstractNode) {
1989: printLocation(((QAbstractNode) node).getBaseURI(),
1990: ((QAbstractNode) node).getFilename(),
1991: ((QAbstractNode) node).getLine());
1992: }
1993: }
1994:
1995: abstract protected void printLocation(String systemId,
1996: String filename, int line) throws Exception;
1997:
1998: abstract protected void printElement(Node node) throws Exception;
1999:
2000: abstract protected void printApplyTemplates(AbstractPattern select,
2001: String mode, Sort[] sort) throws Exception;
2002:
2003: abstract protected void printApplyImports(String mode, int min,
2004: int max) throws Exception;
2005:
2006: abstract protected void printCallTemplate(String name, String mode)
2007: throws Exception;
2008:
2009: abstract protected void pushCall() throws Exception;
2010:
2011: abstract protected void popCall() throws Exception;
2012:
2013: abstract protected void printParam(String name, Object value)
2014: throws Exception;
2015:
2016: abstract protected void printParam(String name, String value,
2017: Element elt) throws Exception;
2018:
2019: abstract protected void printParamVariable(String name, Expr expr)
2020: throws Exception;
2021:
2022: abstract protected void printParamVariable(String name, Element elt)
2023: throws Exception;
2024:
2025: abstract protected void printVariable(String name, Object value)
2026: throws Exception;
2027:
2028: protected void printAssign(String name, Object value)
2029: throws Exception {
2030: printVariable(name, value);
2031: }
2032:
2033: abstract protected void printPopScope(int count) throws Exception;
2034:
2035: abstract protected void printCopyOf(String select, Element element)
2036: throws Exception;
2037:
2038: abstract protected void printSelectValue(String select,
2039: Element element) throws Exception;
2040:
2041: abstract protected void printForEach(Element element, String select)
2042: throws Exception;
2043:
2044: abstract protected void printForEach(Element element,
2045: String select, Sort[] sort) throws Exception;
2046:
2047: protected void printIf(Element element, Expr expr) throws Exception {
2048: }
2049:
2050: protected void printChoose(Element element, Expr expr, boolean first)
2051: throws Exception {
2052: }
2053:
2054: protected void printOtherwise(Element element, boolean first)
2055: throws Exception {
2056: }
2057:
2058: protected void printCopy(Element element) throws Exception {
2059: }
2060:
2061: protected void printCopyElement(Element element) throws Exception {
2062: }
2063:
2064: protected void printElement(Element element, String name)
2065: throws Exception {
2066: }
2067:
2068: protected void printElement(Element element, String name,
2069: String namespace) throws Exception {
2070: }
2071:
2072: protected void printAttribute(Element node, String name)
2073: throws Exception {
2074: }
2075:
2076: protected void printAttribute(Element node, String name,
2077: String namespace) throws Exception {
2078: }
2079:
2080: protected void printPi(Element node) throws Exception {
2081: }
2082:
2083: protected void printComment(Element node) throws Exception {
2084: }
2085:
2086: protected void printError(String msg) throws Exception {
2087: }
2088:
2089: protected void printMessage(Element node) throws Exception {
2090: }
2091:
2092: // extension
2093:
2094: protected void printExpression(Element node) throws Exception {
2095: }
2096:
2097: protected void printScriptlet(Element node) throws Exception {
2098: }
2099:
2100: protected void printDeclaration(Element node) throws Exception {
2101: }
2102:
2103: protected void printCacheDepends(String path) throws Exception {
2104: }
2105:
2106: protected void printWhile(Element element, Expr expr)
2107: throws Exception {
2108: }
2109:
2110: protected void printResultDocument(Element element, String href,
2111: String format) throws Exception {
2112: }
2113:
2114: public int getImportance() {
2115: return _importance;
2116: }
2117:
2118: public void setMinImportance(int importance) {
2119: _minImportance = importance;
2120: }
2121:
2122: public void incrementImportance() {
2123: _importance++;
2124: }
2125:
2126: /**
2127: * Adds a new template pattern.
2128: *
2129: * @param pattern the match pattern.
2130: * @param mode the template mode.
2131: * @param priority the template priority.
2132: * @param function the associated function name.
2133: * @param funId the function id.
2134: */
2135: Template addPattern(AbstractPattern pattern, String mode,
2136: double priority, String function, int funId) {
2137: if (pattern instanceof UnionPattern) {
2138: UnionPattern union = (UnionPattern) pattern;
2139: addPattern(union.getLeft(), mode, priority, function, funId);
2140: return addPattern(union.getRight(), mode, priority,
2141: function, funId);
2142: }
2143:
2144: if (Double.isNaN(priority))
2145: priority = pattern.getPriority();
2146:
2147: if (log.isLoggable(Level.FINER))
2148: log.finer("add " + pattern.getNodeName() + " " + pattern
2149: + " fun:" + function + " mode:" + mode
2150: + " priority:" + priority);
2151:
2152: Template template = new Template(pattern, mode, _minImportance,
2153: _importance, priority, _templateCount++, function,
2154: funId);
2155:
2156: addTemplate(pattern.getNodeName(), template);
2157:
2158: return template;
2159: }
2160:
2161: private void addTemplate(String nodeName, Template template) {
2162: ArrayList<Template> templateList = _templates.get(nodeName);
2163:
2164: if (templateList == null) {
2165: templateList = new ArrayList<Template>();
2166: _templates.put(nodeName, templateList);
2167: }
2168:
2169: for (int i = templateList.size() - 1; i >= 0; i--) {
2170: Template item = templateList.get(i);
2171:
2172: if (template.compareTo(item) <= 0) {
2173: templateList.add(i + 1, template);
2174: return;
2175: }
2176: }
2177:
2178: templateList.add(0, template);
2179: }
2180:
2181: public AbstractPattern parseMatch(String pattern)
2182: throws XslParseException, IOException {
2183: if (true)
2184: throw new RuntimeException();
2185: try {
2186: return XPath.parseMatch(pattern, _namespace).getPattern();
2187: } catch (Exception e) {
2188: throw error(L.l("{0} in pattern `{1}'", e.toString(),
2189: pattern));
2190: }
2191: }
2192:
2193: public AbstractPattern parseSelect(String pattern)
2194: throws IOException, XslParseException {
2195: if (true)
2196: throw new RuntimeException();
2197:
2198: try {
2199: return XPath.parseSelect(pattern, _namespace).getPattern();
2200: } catch (Exception e) {
2201: throw error(e);
2202: }
2203: }
2204:
2205: protected AbstractPattern parseSelect(String pattern, Node node)
2206: throws IOException, XslParseException {
2207: if (true)
2208: throw new UnsupportedOperationException();
2209: try {
2210: return XPath.parseSelect(pattern, _namespace).getPattern();
2211: } catch (Exception e) {
2212: throw error(node, e);
2213: }
2214: }
2215:
2216: public Expr parseExpr(String pattern) throws XslParseException {
2217: if (true)
2218: throw new UnsupportedOperationException();
2219: try {
2220: return XPath.parseExpr(pattern, _namespace,
2221: _nodeListContext);
2222: } catch (Exception e) {
2223: throw error(e);
2224: }
2225: }
2226:
2227: XslParseException error(Exception e) {
2228: if (e.getMessage() != null)
2229: return error(e.getMessage());
2230: else {
2231: log.log(Level.WARNING, e.toString(), e);
2232:
2233: return error(e.toString());
2234: }
2235: }
2236:
2237: XslParseException error(Node node, Exception e) {
2238: if (e.getMessage() != null)
2239: return error(node, e.getMessage());
2240: else {
2241: log.log(Level.WARNING, e.toString(), e);
2242:
2243: return error(e.toString());
2244: }
2245: }
2246:
2247: XslParseException error(String message) {
2248: return new XslParseException(_filename + ":" + _line + ": "
2249: + message);
2250: }
2251:
2252: /**
2253: * Creates an error message with filename and line number based on
2254: * the source node.
2255: *
2256: * @param node XML node of the source XSL.
2257: * @param message the error message.
2258: */
2259: XslParseException error(Node node, String message) {
2260: if (!(node instanceof QAbstractNode))
2261: return error(message);
2262:
2263: QAbstractNode qnode = (QAbstractNode) node;
2264:
2265: String filename = qnode.getFilename();
2266: int line = qnode.getLine();
2267:
2268: if (filename != null)
2269: return new XslParseException(filename + ":" + line + ": "
2270: + message);
2271: else
2272: return error(message);
2273: }
2274:
2275: /**
2276: * Returns the local name of an XSL element. Non-XSL elements return
2277: * null. So xsl:copy will return "copy", while "foo:bar" returns null.
2278: *
2279: * @param node the XSL source node
2280: * @return the local part of the XSL name.
2281: */
2282: protected String getXslLocal(Node node) {
2283: if (!(node instanceof Element))
2284: return null;
2285:
2286: QElement elt = (QElement) node;
2287:
2288: String ns = elt.getNamespaceURI();
2289: String prefix = elt.getPrefix();
2290:
2291: if (ns == null || ns.equals("")) {
2292: return (elt.getNodeName().startsWith("xsl:") ? elt
2293: .getNodeName().substring(4) : null);
2294: } else if (ns.startsWith(XSLNS)
2295: && (ns.length() == XSLNS.length() || ns.charAt(XSLNS
2296: .length()) == '/'))
2297: return elt.getLocalName();
2298: else
2299: return null;
2300: }
2301:
2302: protected String getXtpLocal(Node node) {
2303: if (!(node instanceof Element))
2304: return null;
2305:
2306: QElement elt = (QElement) node;
2307:
2308: String ns = elt.getNamespaceURI();
2309: String prefix = elt.getPrefix();
2310:
2311: if (ns == null || ns.equals("")) {
2312: return (elt.getNodeName().startsWith("xtp:") ? elt
2313: .getNodeName().substring(4) : null);
2314: } else if (ns.startsWith(XTPNS))
2315: return elt.getLocalName();
2316: else
2317: return null;
2318: }
2319:
2320: /**
2321: * Parses an expression in a context
2322: */
2323: private Expr parseExpr(Node node, String expr) throws Exception {
2324: try {
2325: return XPath.parseExpr(expr, _namespace, _nodeListContext);
2326: } catch (Exception e) {
2327: throw error(node, e.getMessage());
2328: }
2329: }
2330:
2331: /**
2332: * Adds the namespaces in the element to the current NamespaceContext.
2333: * The XPath pattern parsing uses NamespaceContext to associate the right
2334: * context with element patterns.
2335: *
2336: * @param elt the XSL element being processed.
2337: *
2338: * @return the old namespace context
2339: */
2340: protected NamespaceContext addNamespace(Element elt) {
2341: NamespaceContext oldNamespace = _namespace;
2342:
2343: Node attr = ((QElement) elt).getFirstAttribute();
2344: for (; attr != null; attr = attr.getNextSibling()) {
2345: String name = attr.getNodeName();
2346:
2347: if (name.startsWith("xmlns:"))
2348: name = name.substring(6);
2349: else if (name.equals("xmlns"))
2350: name = "";
2351: else
2352: continue;
2353:
2354: // Note: according to the spec, the default namespace is not used
2355:
2356: String url = attr.getNodeValue();
2357: if (url.equals(XSLNS) || url.equals(XTPNS))
2358: continue;
2359:
2360: if (url.startsWith("quote:"))
2361: url = url.substring(6);
2362:
2363: _namespace = new NamespaceContext(_namespace, name, url);
2364: }
2365:
2366: return oldNamespace;
2367: }
2368:
2369: void addDepend(Path depend) {
2370: if (depend != null)
2371: _depends.add(depend);
2372: }
2373:
2374: abstract protected StylesheetImpl completeGenerate(
2375: ArrayList<XslNode> inits, ArrayList globals)
2376: throws Exception;
2377:
2378: /**
2379: * Close call when an error occurs.
2380: */
2381: public void close() throws IOException, XslParseException {
2382: }
2383:
2384: static {
2385: _tags = new IntMap();
2386: _tags.put("stylesheet", STYLESHEET);
2387: _tags.put("transform", STYLESHEET);
2388: _tags.put("output", OUTPUT);
2389: _tags.put("template", TEMPLATE);
2390: _tags.put("preserve-space", PRESERVE_SPACE);
2391: _tags.put("strip-space", STRIP_SPACE);
2392: _tags.put("import", IMPORT);
2393: _tags.put("include", INCLUDE);
2394: _tags.put("key", KEY);
2395: _tags.put("decimal-format", LOCALE);
2396: _tags.put("attribute-set", ATTRIBUTE_SET);
2397: _tags.put("namespace-alias", NAMESPACE_ALIAS);
2398:
2399: _tags.put("apply-templates", APPLY_TEMPLATES);
2400: _tags.put("apply-imports", APPLY_IMPORTS);
2401: _tags.put("call-template", CALL_TEMPLATE);
2402: _tags.put("param", PARAM);
2403: _tags.put("variable", VARIABLE);
2404: _tags.put("for-each", FOR_EACH);
2405: _tags.put("if", IF);
2406: _tags.put("choose", CHOOSE);
2407:
2408: _tags.put("value-of", VALUE_OF);
2409: _tags.put("copy-of", COPY_OF);
2410: _tags.put("text", XSL_TEXT);
2411: _tags.put("#text", TEXT);
2412: _tags.put("number", NUMBER);
2413: _tags.put("copy", COPY);
2414: _tags.put("element", ELEMENT);
2415: _tags.put("attribute", ATTRIBUTE);
2416: _tags.put("pi", PI);
2417: _tags.put("processing-instruction", PI);
2418: _tags.put("comment", COMMENT);
2419:
2420: _tags.put("message", MESSAGE);
2421:
2422: _tags.put("sort", IGNORE);
2423: _tags.put("fallback", IGNORE);
2424: // xslt 2.0
2425: _tags.put("result-document", RESULT_DOCUMENT);
2426:
2427: _xtpTags = new IntMap();
2428: _xtpTags.put("expression", EXPRESSION);
2429: _xtpTags.put("expr", EXPRESSION);
2430: _xtpTags.put("eval", EXPRESSION);
2431: _xtpTags.put("scriptlet", SCRIPTLET);
2432: _xtpTags.put("script", SCRIPTLET);
2433: _xtpTags.put("decl", DECLARATION);
2434: _xtpTags.put("declaration", DECLARATION);
2435: _xtpTags.put("directive.cache", DIRECTIVE_CACHE);
2436: _xtpTags.put("while", WHILE);
2437: _xtpTags.put("assign", ASSIGN);
2438: }
2439: }
|