| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package freemarker.ext.xml; |
| |
| import java.io.StringWriter; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.WeakHashMap; |
| |
| import org.jaxen.NamespaceContext; |
| |
| import freemarker.template.TemplateModelException; |
| |
| /** |
| */ |
| abstract class Navigator { |
| // Cache of already parsed XPath expressions |
| private final Map xpathCache = new WeakHashMap(); |
| // Operators this navigator defines |
| private final Map operators = createOperatorMap(); |
| private final NodeOperator attributeOperator = getOperator("_attributes"); |
| private final NodeOperator childrenOperator = getOperator("_children"); |
| |
| NodeOperator getOperator(String key) { |
| return (NodeOperator) operators.get(key); |
| } |
| |
| NodeOperator getAttributeOperator() { |
| return attributeOperator; |
| } |
| |
| NodeOperator getChildrenOperator() { |
| return childrenOperator; |
| } |
| |
| abstract void getAsString(Object node, StringWriter sw) |
| throws TemplateModelException; |
| |
| List applyXPath(List nodes, String xpathString, Object namespaces) |
| throws TemplateModelException { |
| XPathEx xpath = null; |
| try { |
| synchronized (xpathCache) { |
| xpath = (XPathEx) xpathCache.get(xpathString); |
| if (xpath == null) { |
| xpath = createXPathEx(xpathString); |
| xpathCache.put(xpathString, xpath); |
| } |
| } |
| return xpath.selectNodes(nodes, (NamespaceContext) namespaces); |
| } catch (Exception e) { |
| throw new TemplateModelException("Could not evaulate XPath expression " + xpathString, e); |
| } |
| } |
| |
| interface XPathEx { |
| List selectNodes(Object nodes, NamespaceContext namespaces) throws TemplateModelException; |
| } |
| |
| abstract XPathEx createXPathEx(String xpathString) throws TemplateModelException; |
| |
| abstract void getChildren(Object node, String localName, String namespaceUri, List result); |
| |
| abstract void getAttributes(Object node, String localName, String namespaceUri, List result); |
| |
| abstract void getDescendants(Object node, List result); |
| |
| abstract Object getParent(Object node); |
| |
| abstract Object getDocument(Object node); |
| |
| abstract Object getDocumentType(Object node); |
| |
| private void getAncestors(Object node, List result) { |
| for (; ; ) { |
| Object parent = getParent(node); |
| if (parent == null) { |
| break; |
| } |
| result.add(parent); |
| node = parent; |
| } |
| } |
| |
| abstract void getContent(Object node, List result); |
| |
| abstract String getText(Object node); |
| |
| abstract String getLocalName(Object node); |
| |
| abstract String getNamespacePrefix(Object node); |
| |
| String getQualifiedName(Object node) { |
| String lname = getLocalName(node); |
| if (lname == null) { |
| return null; |
| } |
| String nsprefix = getNamespacePrefix(node); |
| if (nsprefix == null || nsprefix.length() == 0) { |
| return lname; |
| } else { |
| return nsprefix + ":" + lname; |
| } |
| } |
| |
| abstract String getType(Object node); |
| |
| abstract String getNamespaceUri(Object node); |
| |
| boolean equal(String s1, String s2) { |
| return s1 == null ? s2 == null : s1.equals(s2); |
| } |
| |
| private Map createOperatorMap() { |
| Map map = new HashMap(); |
| map.put("_attributes", new AttributesOp()); |
| map.put("@*", map.get("_attributes")); |
| map.put("_children", new ChildrenOp()); |
| map.put("*", map.get("_children")); |
| map.put("_descendantOrSelf", new DescendantOrSelfOp()); |
| map.put("_descendant", new DescendantOp()); |
| map.put("_document", new DocumentOp()); |
| map.put("_doctype", new DocumentTypeOp()); |
| map.put("_ancestor", new AncestorOp()); |
| map.put("_ancestorOrSelf", new AncestorOrSelfOp()); |
| map.put("_content", new ContentOp()); |
| map.put("_name", new LocalNameOp()); |
| map.put("_nsprefix", new NamespacePrefixOp()); |
| map.put("_nsuri", new NamespaceUriOp()); |
| map.put("_parent", new ParentOp()); |
| map.put("_qname", new QualifiedNameOp()); |
| map.put("_text", new TextOp()); |
| map.put("_type", new TypeOp()); |
| return map; |
| } |
| |
| private class ChildrenOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| getChildren(node, localName, namespaceUri, result); |
| } |
| } |
| |
| private class AttributesOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| getAttributes(node, localName, namespaceUri, result); |
| } |
| } |
| |
| private class DescendantOrSelfOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| result.add(node); |
| getDescendants(node, result); |
| } |
| } |
| |
| private class DescendantOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| getDescendants(node, result); |
| } |
| } |
| |
| private class AncestorOrSelfOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| result.add(node); |
| getAncestors(node, result); |
| } |
| } |
| |
| private class AncestorOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| getAncestors(node, result); |
| } |
| } |
| |
| private class ParentOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| Object parent = getParent(node); |
| if (parent != null) { |
| result.add(parent); |
| } |
| } |
| } |
| |
| private class DocumentOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| Object document = getDocument(node); |
| if (document != null) { |
| result.add(document); |
| } |
| } |
| } |
| |
| private class DocumentTypeOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| Object documentType = getDocumentType(node); |
| if (documentType != null) { |
| result.add(documentType); |
| } |
| } |
| } |
| |
| private class ContentOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| getContent(node, result); |
| } |
| } |
| |
| private class TextOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| String text = getText(node); |
| if (text != null) { |
| result.add(text); |
| } |
| } |
| } |
| |
| private class LocalNameOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| String text = getLocalName(node); |
| if (text != null) { |
| result.add(text); |
| } |
| } |
| } |
| |
| private class QualifiedNameOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| String qname = getQualifiedName(node); |
| if (qname != null) { |
| result.add(qname); |
| } |
| } |
| } |
| |
| private class NamespacePrefixOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| String text = getNamespacePrefix(node); |
| if (text != null) { |
| result.add(text); |
| } |
| } |
| } |
| |
| private class NamespaceUriOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| String text = getNamespaceUri(node); |
| if (text != null) { |
| result.add(text); |
| } |
| } |
| } |
| |
| private class TypeOp implements NodeOperator { |
| @Override |
| public void process(Object node, String localName, String namespaceUri, List result) { |
| result.add(getType(node)); |
| } |
| } |
| } |