/*
* 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 {
public void
process(
Object node,
String localName,
String namespaceUri,
List result) {
getChildren(
node,
localName,
namespaceUri,
result);
}
}
private class
AttributesOp implements
NodeOperator {
public void
process(
Object node,
String localName,
String namespaceUri,
List result) {
getAttributes(
node,
localName,
namespaceUri,
result);
}
}
private class
DescendantOrSelfOp implements
NodeOperator {
public void
process(
Object node,
String localName,
String namespaceUri,
List result) {
result.
add(
node);
getDescendants(
node,
result);
}
}
private class
DescendantOp implements
NodeOperator {
public void
process(
Object node,
String localName,
String namespaceUri,
List result) {
getDescendants(
node,
result);
}
}
private class
AncestorOrSelfOp implements
NodeOperator {
public void
process(
Object node,
String localName,
String namespaceUri,
List result) {
result.
add(
node);
getAncestors(
node,
result);
}
}
private class
AncestorOp implements
NodeOperator {
public void
process(
Object node,
String localName,
String namespaceUri,
List result) {
getAncestors(
node,
result);
}
}
private class
ParentOp implements
NodeOperator {
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 {
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 {
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 {
public void
process(
Object node,
String localName,
String namespaceUri,
List result) {
getContent(
node,
result);
}
}
private class
TextOp implements
NodeOperator {
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 {
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 {
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 {
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 {
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 {
public void
process(
Object node,
String localName,
String namespaceUri,
List result) {
result.
add(
getType(
node));
}
}
}