001: /*
002: * Copyright (c) 2003 The Visigoth Software Society. All rights
003: * reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * 2. Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in
014: * the documentation and/or other materials provided with the
015: * distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowledgement:
019: * "This product includes software developed by the
020: * Visigoth Software Society (http://www.visigoths.org/)."
021: * Alternately, this acknowledgement may appear in the software itself,
022: * if and wherever such third-party acknowledgements normally appear.
023: *
024: * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
025: * project contributors may be used to endorse or promote products derived
026: * from this software without prior written permission. For written
027: * permission, please contact visigoths@visigoths.org.
028: *
029: * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
030: * nor may "FreeMarker" or "Visigoth" appear in their names
031: * without prior written permission of the Visigoth Software Society.
032: *
033: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
034: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
035: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036: * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
037: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
038: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
039: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
040: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
042: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
043: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
044: * SUCH DAMAGE.
045: * ====================================================================
046: *
047: * This software consists of voluntary contributions made by many
048: * individuals on behalf of the Visigoth Software Society. For more
049: * information on the Visigoth Software Society, please see
050: * http://www.visigoths.org/
051: */
052:
053: package freemarker.ext.xml;
054:
055: import java.io.StringWriter;
056: import java.util.HashMap;
057: import java.util.List;
058: import java.util.Map;
059: import java.util.WeakHashMap;
060:
061: import org.jaxen.NamespaceContext;
062:
063: import freemarker.template.TemplateModelException;
064:
065: /**
066: * @version $Id: Navigator.java,v 1.4 2003/01/31 11:39:17 szegedia Exp $
067: * @author Attila Szegedi
068: */
069: abstract class Navigator {
070: // Cache of already parsed XPath expressions
071: private final Map xpathCache = new WeakHashMap();
072: // Operators this navigator defines
073: private final Map operators = createOperatorMap();
074: private final NodeOperator attributeOperator = getOperator("_attributes");
075: private final NodeOperator childrenOperator = getOperator("_children");
076:
077: NodeOperator getOperator(String key) {
078: return (NodeOperator) operators.get(key);
079: }
080:
081: NodeOperator getAttributeOperator() {
082: return attributeOperator;
083: }
084:
085: NodeOperator getChildrenOperator() {
086: return childrenOperator;
087: }
088:
089: abstract void getAsString(Object node, StringWriter sw)
090: throws TemplateModelException;
091:
092: List applyXPath(List nodes, String xpathString, Object namespaces)
093: throws TemplateModelException {
094: XPathEx xpath = null;
095: try {
096: synchronized (xpathCache) {
097: xpath = (XPathEx) xpathCache.get(xpathString);
098: if (xpath == null) {
099: xpath = createXPathEx(xpathString);
100: xpathCache.put(xpathString, xpath);
101: }
102: }
103: return xpath.selectNodes(nodes,
104: (NamespaceContext) namespaces);
105: } catch (Exception e) {
106: throw new TemplateModelException(
107: "Could not evaulate XPath expression "
108: + xpathString, e);
109: }
110: }
111:
112: interface XPathEx {
113: List selectNodes(Object nodes, NamespaceContext namespaces)
114: throws TemplateModelException;
115: }
116:
117: abstract XPathEx createXPathEx(String xpathString)
118: throws TemplateModelException;
119:
120: abstract void getChildren(Object node, String localName,
121: String namespaceUri, List result);
122:
123: abstract void getAttributes(Object node, String localName,
124: String namespaceUri, List result);
125:
126: abstract void getDescendants(Object node, List result);
127:
128: abstract Object getParent(Object node);
129:
130: abstract Object getDocument(Object node);
131:
132: abstract Object getDocumentType(Object node);
133:
134: private void getAncestors(Object node, List result) {
135: for (;;) {
136: Object parent = getParent(node);
137: if (parent == null) {
138: break;
139: }
140: result.add(parent);
141: node = parent;
142: }
143: }
144:
145: abstract void getContent(Object node, List result);
146:
147: abstract String getText(Object node);
148:
149: abstract String getLocalName(Object node);
150:
151: abstract String getNamespacePrefix(Object node);
152:
153: String getQualifiedName(Object node) {
154: String lname = getLocalName(node);
155: if (lname == null) {
156: return null;
157: }
158: String nsprefix = getNamespacePrefix(node);
159: if (nsprefix == null || nsprefix.length() == 0) {
160: return lname;
161: } else {
162: return nsprefix + ":" + lname;
163: }
164: }
165:
166: abstract String getType(Object node);
167:
168: abstract String getNamespaceUri(Object node);
169:
170: boolean equal(String s1, String s2) {
171: return s1 == null ? s2 == null : s1.equals(s2);
172: }
173:
174: private Map createOperatorMap() {
175: Map map = new HashMap();
176: map.put("_attributes", new AttributesOp());
177: map.put("@*", map.get("_attributes"));
178: map.put("_children", new ChildrenOp());
179: map.put("*", map.get("_children"));
180: map.put("_descendantOrSelf", new DescendantOrSelfOp());
181: map.put("_descendant", new DescendantOp());
182: map.put("_document", new DocumentOp());
183: map.put("_doctype", new DocumentTypeOp());
184: map.put("_ancestor", new AncestorOp());
185: map.put("_ancestorOrSelf", new AncestorOrSelfOp());
186: map.put("_content", new ContentOp());
187: map.put("_name", new LocalNameOp());
188: map.put("_nsprefix", new NamespacePrefixOp());
189: map.put("_nsuri", new NamespaceUriOp());
190: map.put("_parent", new ParentOp());
191: map.put("_qname", new QualifiedNameOp());
192: map.put("_text", new TextOp());
193: map.put("_type", new TypeOp());
194: return map;
195: }
196:
197: private class ChildrenOp implements NodeOperator {
198: public void process(Object node, String localName,
199: String namespaceUri, List result) {
200: getChildren(node, localName, namespaceUri, result);
201: }
202: }
203:
204: private class AttributesOp implements NodeOperator {
205: public void process(Object node, String localName,
206: String namespaceUri, List result) {
207: getAttributes(node, localName, namespaceUri, result);
208: }
209: }
210:
211: private class DescendantOrSelfOp implements NodeOperator {
212: public void process(Object node, String localName,
213: String namespaceUri, List result) {
214: result.add(node);
215: getDescendants(node, result);
216: }
217: }
218:
219: private class DescendantOp implements NodeOperator {
220: public void process(Object node, String localName,
221: String namespaceUri, List result) {
222: getDescendants(node, result);
223: }
224: }
225:
226: private class AncestorOrSelfOp implements NodeOperator {
227: public void process(Object node, String localName,
228: String namespaceUri, List result) {
229: result.add(node);
230: getAncestors(node, result);
231: }
232: }
233:
234: private class AncestorOp implements NodeOperator {
235: public void process(Object node, String localName,
236: String namespaceUri, List result) {
237: getAncestors(node, result);
238: }
239: }
240:
241: private class ParentOp implements NodeOperator {
242: public void process(Object node, String localName,
243: String namespaceUri, List result) {
244: Object parent = getParent(node);
245: if (parent != null) {
246: result.add(parent);
247: }
248: }
249: }
250:
251: private class DocumentOp implements NodeOperator {
252: public void process(Object node, String localName,
253: String namespaceUri, List result) {
254: Object document = getDocument(node);
255: if (document != null) {
256: result.add(document);
257: }
258: }
259: }
260:
261: private class DocumentTypeOp implements NodeOperator {
262: public void process(Object node, String localName,
263: String namespaceUri, List result) {
264: Object documentType = getDocumentType(node);
265: if (documentType != null) {
266: result.add(documentType);
267: }
268: }
269: }
270:
271: private class ContentOp implements NodeOperator {
272: public void process(Object node, String localName,
273: String namespaceUri, List result) {
274: getContent(node, result);
275: }
276: }
277:
278: private class TextOp implements NodeOperator {
279: public void process(Object node, String localName,
280: String namespaceUri, List result) {
281: String text = getText(node);
282: if (text != null) {
283: result.add(text);
284: }
285: }
286: }
287:
288: private class LocalNameOp implements NodeOperator {
289: public void process(Object node, String localName,
290: String namespaceUri, List result) {
291: String text = getLocalName(node);
292: if (text != null) {
293: result.add(text);
294: }
295: }
296: }
297:
298: private class QualifiedNameOp implements NodeOperator {
299: public void process(Object node, String localName,
300: String namespaceUri, List result) {
301: String qname = getQualifiedName(node);
302: if (qname != null) {
303: result.add(qname);
304: }
305: }
306: }
307:
308: private class NamespacePrefixOp implements NodeOperator {
309: public void process(Object node, String localName,
310: String namespaceUri, List result) {
311: String text = getNamespacePrefix(node);
312: if (text != null) {
313: result.add(text);
314: }
315: }
316: }
317:
318: private class NamespaceUriOp implements NodeOperator {
319: public void process(Object node, String localName,
320: String namespaceUri, List result) {
321: String text = getNamespaceUri(node);
322: if (text != null) {
323: result.add(text);
324: }
325: }
326: }
327:
328: private class TypeOp implements NodeOperator {
329: public void process(Object node, String localName,
330: String namespaceUri, List result) {
331: result.add(getType(node));
332: }
333: }
334: }
|