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 << ... >> is shorthand for * <xsl:template match='path'> ... </xsl:template> * <p><{...}> is shorthand for * <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. &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 + -
显示快捷键?