xslparser.java

来自「RESIN 3.2 最新源码」· Java 代码 · 共 1,584 行 · 第 1/3 页

JAVA
1,584
字号
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the *   Free SoftwareFoundation, Inc. *   59 Temple Place, Suite 330 *   Boston, MA 02111-1307  USA * * @author Scott Ferguson */package com.caucho.xsl;import com.caucho.log.Log;import com.caucho.util.CharBuffer;import com.caucho.util.CharCursor;import com.caucho.util.CharScanner;import com.caucho.util.L10N;import com.caucho.util.StringCharCursor;import com.caucho.vfs.Encoding;import com.caucho.vfs.Path;import com.caucho.vfs.ReadStream;import com.caucho.xml.*;import org.w3c.dom.DOMException;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.ProcessingInstruction;import org.w3c.dom.Text;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.logging.Logger;/** * Parses a 'StyleScript' file.  StyleScript is compatible with XSLT, adding * some syntactical sugar: * * <p>path &lt;&lt; ... >> is shorthand for * &lt;xsl:template match='path'> ... &lt;/xsl:template> * <p>&lt;{...}> is shorthand for * &lt;xsl:value-of select='...'/> */class XslParser {  static final Logger log = Log.open(XslParser.class);  static final L10N L = new L10N(XslParser.class);  private static final String XSLNS = Generator.XSLNS;  private static final String XTPNS = Generator.XTPNS;  // this is the value Axis wants  static final String XMLNS = "http://www.w3.org/2000/xmlns/";    static HashMap<String,String> _xslCommands;  static HashMap<String,String> _xtpCommands;  public boolean strictXsl;  boolean rawText;  int line;  int textLine;  ReadStream is;  CharBuffer tag = new CharBuffer();  CharBuffer text = new CharBuffer();  QDocument xsl;  private int peek = -1;  private boolean seenCr;  private String defaultMode;  private HashMap<String,String> _namespaces;  private HashMap macros = new HashMap();  private boolean inTemplate;  XslParser()  {  }  /**   * Parse an XSLT-lite document from the input stream, returning a Document.   */  Document parse(ReadStream is)    throws IOException, XslParseException  {    this.is = is;    line = 1;    defaultMode = null;    xsl = (QDocument) Xml.createDocument();    if (is.getPath().getLastModified() > 0) {      ArrayList<Path> depends = new ArrayList<Path>();      depends.add(is.getPath());      xsl.setProperty(xsl.DEPENDS, depends);    }    xsl.setRootFilename(is.getPath().getURL());    _namespaces = new HashMap<String,String>();    QNode top = (QNode) xsl.createDocumentFragment();    top.setLocation(is.getPath().getURL(), is.getUserPath(), line, 0);    rawText = false;    String encoding = null;    int ch = read();    if (ch != 0xef) {    } else if ((ch = read()) != 0xbb) {      peek = 0xbb;      ch = 0xef;    } else if ((ch = read()) != 0xbf) {      throw error(L.l("Expected 0xbf in UTF-8 header"));    } else {      is.setEncoding("UTF-8");      ch = read();    }        if (ch == '<') {      ch = read();      if (ch == '?') {	ProcessingInstruction pi = parsePi();	if (pi.getNodeName().equals("xml")) {	  encoding = XmlUtil.getPIAttribute(pi.getNodeValue(), "encoding");	  if (encoding != null)	    is.setEncoding(encoding);	}	else	  top.appendChild(pi);	ch = read();      } else {	peek = ch;	ch = '<';      }    }	    parseNode(top, "", true, ch);    QElement elt = null;    for (Node node = top.getFirstChild();	 node != null;	 node = node.getNextSibling()) {      if (node.getNodeType() == Node.ELEMENT_NODE &&	  node.getNodeName().equals("xsl:stylesheet")) {	if (elt != null)	  throw error(L.l("xsl:stylesheet must be sole top element"));	elt = (QElement) node;      }    }    if (elt == null) {      elt = (QElement) xsl.createElementNS(XSLNS, "xsl:stylesheet");      elt.setAttribute("version", "1.0");      elt.setLocation(is.getURL(), is.getUserPath(), 1, 0);      elt.setAttribute("resin:stylescript", "true");      Element out = xsl.createElementNS(XSLNS, "xsl:output");      //out.setAttribute("method", "xtp");      //out.setAttribute("disable-output-escaping", "true");      //out.setAttribute("omit-xml-declaration", "true");            elt.appendChild(out);      elt.appendChild(top);    }    // elt.setAttribute("xsl-caucho", "true");    if (encoding != null) {      Element out = xsl.createElementNS(XSLNS, "xsl:output");      out.setAttribute("encoding", encoding);      elt.insertBefore(out, elt.getFirstChild());    }    xsl.appendChild(elt);    /*    if (dbg.canWrite()) {      new XmlPrinter(dbg).printPrettyXml(xsl);    }    */    return xsl;  }  /**   * Parses in the middle of a node   *   * @param parent parsed children are attached to the parent node   */  private void parseNode(Node parent, String tagEnd,			 boolean isSpecial, int ch)    throws IOException, XslParseException  {    boolean hasContent = false;        text.clear();    if (tagEnd == ">>" && (ch == '\n' || ch == '\r'))      ch = read();    while (ch >= 0) {      switch (ch) {      case '\\':        hasContent = true;	ch = read();	if (ch == '<') {	  addText('<');	  ch = read();	}	else	  addText('\\');	break;      case '<':        hasContent = true;	ch = read();	if (ch == '/') {	  ch = readTag(read());	  String tag = this.tag.toString();	  if (tag.equals(tagEnd)) {	    ch = skipWhitespace(ch);	    if (ch != '>')	      throw error(L.l("expected `{0}' at {1}", ">", badChar(ch)));	    addText(parent);            if (tag.equals("xsl:template"))              inTemplate = false;	    return;	  }          else if (rawText) {            addText("</" + tag + ">");            ch = read();            break;          }          else {            throw error(L.l("`</{0}>' has no matching open tag", tag));          }	} else if (ch == '#') {	  addText(parent);	  ch = parseScriptlet(parent);	  break;	} else if (ch == '?') {	  addText(parent);	  ProcessingInstruction pi = parsePi();	  parent.appendChild(pi);	  ch = read();	  break;	} else if (ch == '!') {	  addText(parent);	  ch = parseDecl(parent);	  break;	} else if (ch == '{') {	  addText(parent);	  parseValueOf(parent);	  ch = read();	  break;	}	ch = readTag(ch);	String tag = this.tag.toString();	// treat the tag as XML when it has a known prefix or we aren't	// in rawText mode	if (! rawText && ! tag.equals("") ||	    tag.startsWith("xsl:") ||	    tag.startsWith("jsp:") || tag.startsWith("xtp:") ||	    macros.get(tag) != null) {	  addText(parent);	  parseElement(parent, tag, ch, isSpecial);	  ch = read();	}	// otherwise tread the tag as text	else {	  addText("<");	  addText(tag);	}	break;      case '>':	int ch1 = read();	if (ch1 == '>' && tagEnd == ">>") {	  if (text.length() > 0 && text.charAt(text.length() - 1) == '\n')	    text.setLength(text.length() - 1);	  if (text.length() > 0 && text.charAt(text.length() - 1) == '\r')	    text.setLength(text.length() - 1);          if (! hasContent) {            Element elt = xsl.createElementNS(XSLNS, "xsl:text");            parent.appendChild(elt);            addText(elt);          }          else            addText(parent);	  return;	}	else {          hasContent = true;	  addText('>');	  ch = ch1;	}	break;      case '$':        hasContent = true;	ch = read();        if (ch == '$') {          addText('$');          ch = read();        }        else if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') {          String name = parseName(ch);          addText(parent);          text.clear();          ch = parseExtension(parent, name);        }        else if (ch == '(') {	  addText(parent);          Element elt = xsl.createElementNS(XSLNS, "xsl:value-of");          CharBuffer test = CharBuffer.allocate();          lexToRparen(test);          elt.setAttribute("select", test.close());          parent.appendChild(elt);          ch = read();        }        else {          addText('$');          ch = read();        }        break;      case ' ': case '\t': case '\n': case '\r':	addText((char) ch);	ch = read();	break;      case '&':        ch = parseEntityReference();        break;      default:        hasContent = true;	if (isSpecial) {	  parseSpecial(parent, ch);	  ch = read();	}	else {	  addText((char) ch);	  ch = read();	}	break;      }    }    addText(parent);    if (! tagEnd.equals(""))      throw error(L.l("expected close of `{0}' (open at {1})",                      tagEnd, ((CauchoNode) parent).getLine()));  }  /**   * Parses an element.   *   * @param parent the owning node of the new child   * @param name the name of the element   * @param ch the current character   * @param isSpecial ??   *   * @return the new child element   */  private Element parseElement(Node parent, String name,			       int ch, boolean isSpecial)    throws IOException, XslParseException  {    HashMap<String,String> oldNamespaces = _namespaces;    QElement element = null;        int p = name.indexOf(':');    if (p >= 0) {      String prefix = name.substring(0, p);      String uri = _namespaces.get(prefix);      if (uri != null)        element = (QElement) xsl.createElementNS(uri, name);      else if (prefix.equals("xsl"))        element = (QElement) xsl.createElementNS(XSLNS, name);    }    try {      if (element == null)        element = (QElement) xsl.createElement(name);    } catch (DOMException e) {      throw error(e);    }        element.setLocation(is.getURL(), is.getUserPath(), line, 0);    ch = parseAttributes(null, element, ch, false);    if (name.equals("xsl:stylesheet")) {      if (element.getAttribute("parsed-content").equals("false")) {	rawText = true;        Element child = xsl.createElementNS(XSLNS, "xsl:output");        child.setAttribute("disable-output-escaping", "yes");        element.appendChild(child);      }    }    if (rawText && (name.startsWith("xsl") || name.startsWith("xtp")) &&	element.getAttribute("xml:space").equals(""))      element.setAttribute("xml:space", "default");    if (name.equals("xsl:template")) {      inTemplate = true;      String macroName = element.getAttribute("name");      if (! macroName.equals(""))	macros.put(macroName, macroName);    }    String oldMode = defaultMode;    if (name.equals("xtp:mode")) {      defaultMode = element.getAttribute("mode");    }    else {      parent.appendChild(element);      parent = element;    }    if (ch == '>') {      parseNode(parent, name, isSpecial && name.equals("xsl:stylesheet"),		read());    } else if (ch == '/') {      if ((ch = read()) != '>')	throw error(L.l("expected `{0}' at {1}", ">", badChar(ch)));    } else      throw error(L.l("expected `{0}' at {1}", ">", badChar(ch)));    defaultMode = oldMode;    _namespaces = oldNamespaces;    return element;  }  /**   * Parses an entity reference, e.g. &amp;lt;   */  private int parseEntityReference()    throws IOException, XslParseException  {    int ch = read();    if (ch == '#') {      int code = 0;      ch = read();      if (ch == 'x') {        for (ch = read(); ch > 0 && ch != ';'; ch = read()) {          if (ch >= '0' && ch <= '9')            code = 16 * code + ch - '0';          else if (ch >= 'a' && ch <= 'f')            code = 16 * code + ch - 'a' + 10;          else if (ch >= 'A' && ch <= 'F')            code = 16 * code + ch - 'A' + 10;          else            break;        }        if (ch == ';') {          addText((char) code);          return read();        }        else {          addText("&#x");          addText(String.valueOf(code));          return ch;        }      }      else {        for (; ch >= '0' && ch <= '9'; ch = read()) {          code = 10 * code + ch - '0';        }      }      if (ch == ';') {        addText((char) code);        return read();      }      else {        addText("&#");        addText(String.valueOf(code));        return ch;      }    }    CharBuffer cb = CharBuffer.allocate();    for (; ch >= 'a' && ch <= 'z'; ch = read())      cb.append((char) ch);    if (ch != ';') {      addText('&');      addText(cb.close());    }    else if (cb.matches("lt")) {      addText('<');      return read();    }    else if (cb.matches("gt")) {      addText('>');      return read();

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?