001: /******************************************************************************
002: * JBoss, a division of Red Hat *
003: * Copyright 2006, Red Hat Middleware, LLC, and individual *
004: * contributors as indicated by the @authors tag. See the *
005: * copyright.txt in the distribution for a full listing of *
006: * individual contributors. *
007: * *
008: * This is free software; you can redistribute it and/or modify it *
009: * under the terms of the GNU Lesser General Public License as *
010: * published by the Free Software Foundation; either version 2.1 of *
011: * the License, or (at your option) any later version. *
012: * *
013: * This software is distributed in the hope that it will be useful, *
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of *
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
016: * Lesser General Public License for more details. *
017: * *
018: * You should have received a copy of the GNU Lesser General Public *
019: * License along with this software; if not, write to the Free *
020: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
021: * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
022: ******************************************************************************/package org.jboss.portal.format.template;
023:
024: import org.dom4j.Document;
025: import org.dom4j.DocumentFactory;
026: import org.dom4j.Element;
027:
028: import java.io.File;
029: import java.io.FileNotFoundException;
030: import java.io.FileReader;
031: import java.io.IOException;
032: import java.io.Reader;
033: import java.io.StringReader;
034: import java.util.LinkedList;
035:
036: /** @author <a href="mailto:julien@jboss.org">Julien Viet</a> */
037: public final class TemplateParser implements TemplateAnalyzerConstants {
038:
039: private Reader source;
040: private TemplateAnalyzerTokenManager analyzer;
041: private LinkedList stack = new LinkedList();
042: private Document template;
043: private Element current;
044: private StringBuffer text = null;
045:
046: public TemplateParser(File source) throws FileNotFoundException {
047: this (new FileReader(source));
048: }
049:
050: public TemplateParser(String source) {
051: this (new StringReader(source));
052: }
053:
054: public TemplateParser(Reader source) {
055: this .source = source;
056: analyzer = new TemplateAnalyzerTokenManager(
057: new ASCII_CharStream(source, 1, 1));
058: template = DocumentFactory.getInstance().createDocument();
059: current = template.addElement("node");
060: }
061:
062: /** This method should be called only once. If it is called more than once there are no garanty on the result. */
063: public Document parse() throws ParseException {
064: while (true) {
065: // getChild the next token
066: Token t = analyzer.getNextToken();
067:
068: if (t.image.length() == 0) {
069: if (text != null) {
070: current.addText(text.toString());
071: text = null;
072: }
073:
074: // no more token to read
075: if (current != template.getRootElement()) {
076: throw new ParseException(
077: "An opening loop is not closed");
078: }
079: return template;
080: }
081:
082: switch (t.kind) {
083: case BEGIN:
084: if (text != null) {
085: current.addText(text.toString());
086: text = null;
087: }
088: Element loop = current.addElement("loop");
089: loop.addAttribute("name", t.image.substring(
090: "<!-- BEGIN ".length(), t.image.length()
091: - " -->".length()));
092: push(loop.addElement("node"));
093: break;
094:
095: case END:
096: if (text != null) {
097: current.addText(text.toString());
098: text = null;
099: }
100: if (!"node".equals(current.getName())) {
101: throw new ParseException("Unexpected closing loop");
102: }
103: pop();
104: // if (!((Loop)current.getContent().getLast()).validate(t.image))
105: // {
106: // throw new ParseException("Closing loop does not match");
107: // }
108: break;
109:
110: case PROPERTY:
111: case TEXT:
112: if (text == null) {
113: text = new StringBuffer();
114: }
115: text.append(t.image);
116: break;
117: case NEWLINE:
118: if (text == null) {
119: text = new StringBuffer();
120: }
121: text.append("\n");
122: break;
123:
124: case REF:
125: if (text != null) {
126: current.addText(text.toString());
127: text = null;
128: }
129: Element ref = current.addElement("ref");
130: String tmp = t.image.substring(1, t.image.length() - 1);
131: int count = 0;
132: int previous = -1;
133: while (true) {
134: int index = tmp.indexOf('.', previous + 1);
135: if (index == -1) {
136: String name = tmp.substring(previous + 1);
137: ref.addAttribute("name", name);
138: break;
139: }
140: count++;
141: previous = index;
142: }
143: ref.addAttribute("depth", "" + count);
144: break;
145:
146: default:
147: throw new ParseException("Unexpected token");
148: }
149: }
150: }
151:
152: public void close() {
153: try {
154: source.close();
155: } catch (IOException ignore) {
156: //
157: }
158: }
159:
160: private void push(Element node) {
161: stack.addLast(current);
162: current = node;
163: }
164:
165: private void pop() {
166: current = (Element) stack.removeLast();
167: }
168:
169: }
|