001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: XsltExtension.java 3634 2007-01-08 21:42:24Z gbevin $
007: */
008: package com.uwyn.rife.template;
009:
010: import com.uwyn.rife.tools.ExceptionUtils;
011: import java.io.IOException;
012: import java.lang.reflect.Method;
013: import java.util.logging.Logger;
014: import javax.xml.parsers.DocumentBuilder;
015: import javax.xml.parsers.DocumentBuilderFactory;
016: import javax.xml.parsers.FactoryConfigurationError;
017: import javax.xml.parsers.ParserConfigurationException;
018: import javax.xml.transform.ErrorListener;
019: import javax.xml.transform.Result;
020: import javax.xml.transform.TransformerException;
021: import javax.xml.transform.dom.DOMResult;
022: import org.apache.xalan.extensions.XSLProcessorContext;
023: import org.apache.xalan.templates.ElemExtensionCall;
024: import org.apache.xalan.transformer.TransformerImpl;
025: import org.w3c.dom.Document;
026: import org.w3c.dom.DocumentFragment;
027: import org.xml.sax.ContentHandler;
028:
029: public class XsltExtension implements ErrorListener {
030: public void fatalError(TransformerException exception)
031: throws TransformerException {
032: Logger.getLogger("com.uwyn.rife.template").severe(
033: ExceptionUtils.getExceptionStackTrace(exception));
034: }
035:
036: public void error(TransformerException exception)
037: throws TransformerException {
038: Logger.getLogger("com.uwyn.rife.template").severe(
039: ExceptionUtils.getExceptionStackTrace(exception));
040: }
041:
042: public void warning(TransformerException exception)
043: throws TransformerException {
044: Logger.getLogger("com.uwyn.rife.template").warning(
045: ExceptionUtils.getExceptionStackTrace(exception));
046: }
047:
048: public void value(XSLProcessorContext context,
049: ElemExtensionCall element)
050: throws FactoryConfigurationError, IOException,
051: ParserConfigurationException, TransformerException {
052: // ensure that the name of the tag has been provided
053: String name = element.getAttribute("name");
054: if (null == name) {
055: return;
056: }
057:
058: // build a document for constructing the alternate output elements
059: DocumentBuilderFactory factory = null;
060: DocumentBuilder builder = null;
061: Document document = null;
062: factory = DocumentBuilderFactory.newInstance();
063: factory.setValidating(false);
064: factory.setIgnoringComments(false);
065: builder = factory.newDocumentBuilder();
066: document = builder.newDocument();
067:
068: if (element.hasChildNodes()) {
069: // create several document fragments to create the start and end tags
070: DocumentFragment fragment_start = null;
071: DocumentFragment fragment_children = null;
072: DocumentFragment fragment_end = null;
073: fragment_start = document.createDocumentFragment();
074: fragment_children = document.createDocumentFragment();
075: fragment_end = document.createDocumentFragment();
076:
077: fragment_start.appendChild(document.createComment("V '"
078: + name + "'"));
079: fragment_end.appendChild(document.createComment("/V"));
080:
081: // process all child nodes and output the result to the middle
082: // document fragment
083: DOMResult children_result = null;
084: TransformerImpl transformer = null;
085: ContentHandler handler = null;
086: children_result = new DOMResult();
087: children_result.setNode(fragment_children);
088: transformer = context.getTransformer();
089: handler = createContentHandler(transformer, children_result);
090: transformer.setErrorListener(this );
091: transformer.executeChildTemplates(element, context
092: .getContextNode(), context.getMode(), handler);
093:
094: // output the document fragments
095: context.outputToResultTree(context.getStylesheet(),
096: fragment_start);
097: context.outputToResultTree(context.getStylesheet(),
098: fragment_children);
099: context.outputToResultTree(context.getStylesheet(),
100: fragment_end);
101: } else {
102: // obtain a document fragment and add the correct comment to it
103: // so that RIFE's template engine understands it
104: DocumentFragment fragment_short = document
105: .createDocumentFragment();
106: fragment_short.appendChild(document.createComment("V '"
107: + name + "'/"));
108:
109: // output the document fragment
110: context.outputToResultTree(context.getStylesheet(),
111: fragment_short);
112: }
113: }
114:
115: private ContentHandler createContentHandler(
116: TransformerImpl transformer, DOMResult childrenResult)
117: throws TransformerException {
118: ContentHandler handler = null;
119:
120: // support ibm and sun jdk which both contain a different version of
121: // xalan
122: try {
123: Method method = null;
124: try {
125: method = transformer.getClass().getMethod(
126: "createResultContentHandler", Result.class);
127: } catch (NoSuchMethodException e) {
128: try {
129: method = transformer.getClass().getMethod(
130: "createSerializationHandler", Result.class);
131: } catch (NoSuchMethodException e2) {
132: throw new TransformerException(e);
133: }
134: }
135: handler = (ContentHandler) method.invoke(transformer,
136: childrenResult);
137: } catch (Exception e) {
138: throw new TransformerException(e);
139: }
140:
141: return handler;
142: }
143:
144: public void block(XSLProcessorContext context,
145: ElemExtensionCall element)
146: throws FactoryConfigurationError, IOException,
147: ParserConfigurationException, TransformerException {
148: block("B", context, element);
149: }
150:
151: public void blockvalue(XSLProcessorContext context,
152: ElemExtensionCall element)
153: throws FactoryConfigurationError, IOException,
154: ParserConfigurationException, TransformerException {
155: block("BV", context, element);
156: }
157:
158: private void block(String tagName, XSLProcessorContext context,
159: ElemExtensionCall element)
160: throws FactoryConfigurationError, IOException,
161: ParserConfigurationException, TransformerException {
162: // ensure that the name of the tag has been provided
163: String name = element.getAttribute("name");
164: if (null == name) {
165: return;
166: }
167:
168: // build a document for constructing the alternate output elements
169: DocumentBuilderFactory factory = null;
170: DocumentBuilder builder = null;
171: Document document = null;
172: factory = DocumentBuilderFactory.newInstance();
173: factory.setValidating(false);
174: factory.setIgnoringComments(false);
175: builder = factory.newDocumentBuilder();
176: document = builder.newDocument();
177:
178: // create several document fragments to create the start and end tags
179: DocumentFragment fragment_start = null;
180: DocumentFragment fragment_end = null;
181: fragment_start = document.createDocumentFragment();
182: fragment_end = document.createDocumentFragment();
183: fragment_start.appendChild(document.createComment(tagName
184: + " '" + name + "'"));
185: fragment_end.appendChild(document.createComment("/" + tagName));
186:
187: // output the start tag document fragment
188: context.outputToResultTree(context.getStylesheet(),
189: fragment_start);
190: if (element.hasChildNodes()) {
191: // if there are child nodes, create a middle document fragment
192: DOMResult children_result = new DOMResult();
193: DocumentFragment fragment_children = null;
194: fragment_children = document.createDocumentFragment();
195: children_result.setNode(fragment_children);
196:
197: // process all child nodes and output the result to the middle
198: // document fragment
199: TransformerImpl transformer = context.getTransformer();
200: ContentHandler handler = createContentHandler(transformer,
201: children_result);
202: transformer.setErrorListener(this );
203: transformer.executeChildTemplates(element, context
204: .getContextNode(), context.getMode(), handler);
205: // output the middle document fragment
206: context.outputToResultTree(context.getStylesheet(),
207: fragment_children);
208: }
209: // output the end tag document fragment
210: context.outputToResultTree(context.getStylesheet(),
211: fragment_end);
212: }
213:
214: public void include(XSLProcessorContext context,
215: ElemExtensionCall element)
216: throws FactoryConfigurationError, IOException,
217: ParserConfigurationException, TransformerException {
218: // ensure that the name of the tag has been provided
219: String name = element.getAttribute("name");
220: if (null == name) {
221: return;
222: }
223:
224: // build a document for constructing the alternate output elements
225: DocumentBuilderFactory factory = null;
226: DocumentBuilder builder = null;
227: Document document = null;
228: factory = DocumentBuilderFactory.newInstance();
229: factory.setValidating(false);
230: factory.setIgnoringComments(false);
231: builder = factory.newDocumentBuilder();
232: document = builder.newDocument();
233:
234: // obtain a document fragment and add the correct comment to it
235: // so that RIFE's template engine understands it
236: DocumentFragment fragment = document.createDocumentFragment();
237: fragment.appendChild(document
238: .createComment("I '" + name + "'/"));
239:
240: // output the document fragment
241: context.outputToResultTree(context.getStylesheet(), fragment);
242: }
243: }
|