001: package org.apache.dvsl;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.util.List;
023: import java.util.Stack;
024: import java.util.Map;
025: import java.util.HashMap;
026:
027: import java.io.Writer;
028: import java.io.StringWriter;
029: import java.io.Reader;
030:
031: import org.apache.velocity.context.Context;
032: import org.apache.velocity.app.VelocityEngine;
033: import org.apache.velocity.VelocityContext;
034:
035: import org.dom4j.Document;
036: import org.dom4j.Element;
037: import org.dom4j.Node;
038: import org.dom4j.DocumentException;
039: import org.dom4j.io.SAXReader;
040:
041: import org.apache.dvsl.dom4j.Dom4jNodeImpl;
042:
043: /**
044: * <p>
045: * Class responsible for actual transformation
046: * of documents.
047: * </p>
048: *
049: * <p>
050: * Note that this class is <em>not</em> threadsafe.
051: * </p>
052: *
053: * @author <a href="mailto:geirm@apache.org>Geir Magnusson Jr.</a>
054: */
055: class Transformer implements TransformTool {
056: /**
057: * Instance of VelocityEngine we are currently using.
058: * This must be reset with a stylesheeet change
059: */
060: private VelocityEngine ve = null;
061:
062: /**
063: * SAXReader that we reuse for every document. Much faster.
064: */
065: private SAXReader saxReader = null;
066:
067: /**
068: * basic context passed to us - can contain tools
069: * and such for use. Is protected from change via
070: * wrapping
071: */
072: private Context baseContext;
073:
074: /**
075: * context used during processing. Wraps the baseContext
076: */
077: private DVSLNodeContext currentContext;
078:
079: private TemplateHandler templateHandler = null;
080:
081: /**
082: * HashMap to hold application values
083: */
084:
085: private Map appValue = new HashMap();
086:
087: /**
088: * Sole public CTOR. We rely on the caller to give us a
089: * VelocityEngine ready with all macros registered.
090: * The context is the callers context with all tools and
091: * style drek.
092: */
093: public Transformer(VelocityEngine ve, TemplateHandler th,
094: Context context, Map applicationValues, boolean validate) {
095: this .ve = ve;
096: this .baseContext = context;
097: this .templateHandler = th;
098:
099: appValue = applicationValues;
100:
101: saxReader = new SAXReader(validate);
102: }
103:
104: /**
105: * "Sealed for your protection."
106: */
107: private Transformer() {
108: }
109:
110: /**
111: * Method that performs the transformation on
112: * a document
113: *
114: * @param reader XML document char stream
115: * @param writer Writer to output transformation to
116: */
117: long transform(Reader reader, Writer writer) throws Exception {
118:
119: /*
120: * parse the document
121: */
122: Document document = saxReader.read(reader);
123:
124: return transform(document, writer);
125: }
126:
127: long transform(Document dom4jdoc, Writer writer) throws Exception {
128: /*
129: * wrap the document. We do this as we let the dom4j package
130: * decide if we have a match against "/", so we need document
131: * to do that
132: */
133:
134: DVSLNode root = new Dom4jNodeImpl(dom4jdoc);
135:
136: return transform(root, writer);
137: }
138:
139: protected long transform(DVSLNode root, Writer writer)
140: throws Exception {
141: /*
142: * wrap in a context to keep subsequent documents from
143: * interacting with each other
144: */
145:
146: currentContext = new DVSLNodeContext(baseContext);
147:
148: long start = System.currentTimeMillis();
149:
150: /*
151: * push 'this' into the context as our TransformTool
152: * and invoke the transformation
153: */
154:
155: currentContext.put("context", this );
156:
157: invoke(root, writer);
158:
159: long end = System.currentTimeMillis();
160:
161: return end - start;
162: }
163:
164: private void invoke(DVSLNode element, Writer writer)
165: throws Exception {
166: String[] arr = {};
167:
168: currentContext.pushNode(element);
169:
170: templateHandler.render(element, currentContext, writer);
171:
172: currentContext.popNode();
173: }
174:
175: public Object get(String key) {
176: return currentContext.get(key);
177: }
178:
179: public String applyTemplates(DVSLNode node, String xpath)
180: throws Exception {
181: /*
182: * get the nodes that was asked for
183: */
184:
185: List nodeset = node.selectNodes(xpath);
186:
187: StringWriter sw = new StringWriter();
188:
189: for (int i = 0; i < nodeset.size(); i++) {
190: DVSLNode n = (DVSLNode) nodeset.get(i);
191:
192: invoke(n, sw);
193: }
194:
195: return sw.toString();
196: }
197:
198: public String applyTemplates(DVSLNode node) throws Exception {
199: StringWriter sw = new StringWriter();
200:
201: invoke(node, sw);
202:
203: return sw.toString();
204: }
205:
206: public String applyTemplates() throws Exception {
207: return applyTemplates(currentContext.peekNode(),
208: "*|@*|text()|comment()|processing-instruction()");
209: }
210:
211: public String applyTemplates(String path) throws Exception {
212: DVSLNode node = currentContext.peekNode();
213:
214: return applyTemplates(node, path);
215: }
216:
217: public String copy() {
218: /*
219: * fakie, for now
220: */
221:
222: DVSLNode node = currentContext.peekNode();
223:
224: return node.copy();
225: }
226:
227: public Object getAppValue(Object key) {
228: return appValue.get(key);
229: }
230:
231: public Object putAppValue(Object key, Object value) {
232: return appValue.put(key, value);
233: }
234:
235: }
|