📄 nodelistmodel.java
字号:
/*
* Copyright (c) 2003 The Visigoth Software Society. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowledgement:
* "This product includes software developed by the
* Visigoth Software Society (http://www.visigoths.org/)."
* Alternately, this acknowledgement may appear in the software itself,
* if and wherever such third-party acknowledgements normally appear.
*
* 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
* project contributors may be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact visigoths@visigoths.org.
*
* 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
* nor may "FreeMarker" or "Visigoth" appear in their names
* without prior written permission of the Visigoth Software Society.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Visigoth Software Society. For more
* information on the Visigoth Software Society, please see
* http://www.visigoths.org/
*/
package freemarker.ext.jdom;
import java.io.FileReader;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import org.jaxen.Context;
import org.jaxen.JaxenException;
import org.jaxen.NamespaceContext;
import org.jaxen.jdom.JDOMXPath;
import org.jdom.Attribute;
import org.jdom.CDATA;
import org.jdom.Comment;
import org.jdom.DocType;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.EntityRef;
import org.jdom.Namespace;
import org.jdom.ProcessingInstruction;
import org.jdom.Text;
import org.jdom.output.XMLOutputter;
import freemarker.template.SimpleHash;
import freemarker.template.SimpleScalar;
import freemarker.template.Template;
import freemarker.template.TemplateCollectionModel;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateMethodModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateModelIterator;
import freemarker.template.TemplateScalarModel;
import freemarker.template.TemplateSequenceModel;
import freemarker.template.utility.Collections12;
/**
* Provides a template for wrapping JDOM objects. It is capable of storing not only
* a single JDOM node, but a list of JDOM nodes at once (hence the name).
* Each node is an instance of any of the core JDOM node classes (except namespaces,
* which are not supported at the moment), or String for representing text.
* See individual method documentation for exact details on how the class works. In
* short:
* <ul>
* <li>{@link #getAsString()} will render all contained nodes as XML fragment,</tt>
* <li>{@link #exec(List)} provides full XPath functionality implemented on top of
* the <a href="http://www.jaxen.org">Jaxen</a> library,</li>
* <li>{@link #get(String)} provides node traversal, copying and filtering - somewhat
* less expressive than XPath, however it does not require the external library and
* it evaluates somewhat faster</li>
* <li>being a {@link TemplateCollectionModel} allows to iterate the contained node list, and</li>
* <li>being a {@link TemplateSequenceModel} allows to access the contained nodes by index and query the node count.</li>
* </ul>
*
* <p><b>Note:</b> There is a JDOM independent re-implementation of this class:
* {@link freemarker.ext.xml.NodeListModel freemarker.ext.xml.NodeListModel}
*
* @deprecated Use {@link freemarker.ext.dom.NodeModel} instead.
* @author Attila Szegedi
* @version $Id: NodeListModel.java,v 1.52 2004/01/06 17:06:42 szegedia Exp $
*/
public class NodeListModel
implements
TemplateHashModel,
TemplateMethodModel,
TemplateCollectionModel,
TemplateSequenceModel,
TemplateScalarModel
{
private static final AttributeXMLOutputter OUTPUT = new AttributeXMLOutputter();
// A convenience singleton for representing a node list without nodes.
private static final NodeListModel EMPTY = new NodeListModel(null, false);
// Cache of already parsed XPath expressions
private static final Map XPATH_CACHE = new WeakHashMap();
private static final NamedNodeOperator NAMED_CHILDREN_OP = new NamedChildrenOp();
private static final NamedNodeOperator NAMED_ATTRIBUTE_OP = new NamedAttributeOp();
private static final NodeOperator ALL_ATTRIBUTES_OP = new AllAttributesOp();
private static final NodeOperator ALL_CHILDREN_OP = new AllChildrenOp();
private static final Map OPERATIONS = createOperations();
private static final Map SPECIAL_OPERATIONS = createSpecialOperations();
private static final int SPECIAL_OPERATION_COPY = 0;
private static final int SPECIAL_OPERATION_UNIQUE = 1;
private static final int SPECIAL_OPERATION_FILTER_NAME = 2;
private static final int SPECIAL_OPERATION_FILTER_TYPE = 3;
private static final int SPECIAL_OPERATION_QUERY_TYPE = 4;
private static final int SPECIAL_OPERATION_REGISTER_NAMESPACE = 5;
private static final int SPECIAL_OPERATION_PLAINTEXT = 6;
// The contained nodes
private final List nodes;
private final Map namespaces;
/**
* Creates a node list that holds a single {@link Document} node.
*/
public NodeListModel(Document document)
{
nodes = document == null ? Collections.EMPTY_LIST : Collections12.singletonList(document);
namespaces = new HashMap();
}
/**
* Creates a node list that holds a single {@link Element} node.
*/
public NodeListModel(Element element)
{
nodes = element == null ? Collections.EMPTY_LIST : Collections12.singletonList(element);
namespaces = new HashMap();
}
private NodeListModel(Object object, Map namespaces)
{
nodes = object == null ? Collections.EMPTY_LIST : Collections12.singletonList(object);
this.namespaces = namespaces;
}
/**
* Creates a node list that holds a list of nodes.
* @param nodes the list of nodes this template should hold. The created template
* will copy the passed nodes list, so changes to the passed list will not affect
* the model.
*/
public NodeListModel(List nodes)
{
this(nodes, true);
}
/**
* Creates a node list that holds a list of nodes.
* @param nodes the list of nodes this template should hold.
* @param copy if true, the created template will copy the passed nodes list,
* so changes to the passed list will not affect the model. If false, the model
* will reference the passed list and will sense changes in it, although no
* operations on the list will be synchronized.
*/
public NodeListModel(List nodes, boolean copy)
{
this.nodes = copy && nodes != null ? new ArrayList(nodes) : (nodes == null ? Collections.EMPTY_LIST : nodes);
namespaces = new HashMap();
}
private NodeListModel(List nodes, Map namespaces)
{
this.nodes = nodes == null ? Collections.EMPTY_LIST : nodes;
this.namespaces = namespaces;
}
private static final NodeListModel createNodeListModel(List list, Map namespaces)
{
if (list == null || list.isEmpty()) {
if (namespaces.isEmpty()) {
return EMPTY;
} else {
return new NodeListModel(Collections.EMPTY_LIST, namespaces);
}
}
if (list.size() == 1) return new NodeListModel(list.get(0), namespaces);
return new NodeListModel(list, namespaces);
}
/**
* Returns true if this model contains no nodes.
*/
public boolean isEmpty()
{
return nodes.isEmpty();
}
/**
* This method returns the string resulting from concatenation
* of string representations of its nodes. Each node is rendered using its XML
* serialization format, while text (String) is rendered as itself. This greatly
* simplifies creating XML-transformation templates, as to output a node contained
* in variable x as XML fragment, you simply write ${x} in the template.
*/
public String getAsString()
throws
TemplateModelException
{
if (isEmpty())
return "";
java.io.StringWriter sw = new java.io.StringWriter(nodes.size() * 128);
try {
for (Iterator i = nodes.iterator(); i.hasNext();) {
Object node = i.next();
if (node instanceof Element)
OUTPUT.output((Element)node, sw);
else if (node instanceof Attribute)
OUTPUT.output((Attribute)node, sw);
else if (node instanceof String)
sw.write(OUTPUT.escapeElementEntities(node.toString()));
else if (node instanceof Text)
OUTPUT.output((Text)node, sw);
else if (node instanceof Document)
OUTPUT.output((Document)node, sw);
else if (node instanceof ProcessingInstruction)
OUTPUT.output((ProcessingInstruction)node, sw);
else if (node instanceof Comment)
OUTPUT.output((Comment)node, sw);
else if (node instanceof CDATA)
OUTPUT.output((CDATA)node, sw);
else if (node instanceof DocType)
OUTPUT.output((DocType)node, sw);
else if (node instanceof EntityRef)
OUTPUT.output((EntityRef)node, sw);
else
throw new TemplateModelException(node.getClass().getName() + " is not a core JDOM class");
}
} catch (IOException e) {
throw new TemplateModelException(e.getMessage());
}
return sw.toString();
}
/**
* Provides node list traversal as well as special functions: filtering by name,
* filtering by node type, shallow-copying, and duplicate removal.
* While not as powerful as the full XPath support built into the
* {@link #exec(List)} method, it does not require the external Jaxen
* library to be present at run time. Below are listed the recognized keys.
* In key descriptions, "applicable to this-and-that node type" means that if
* a key is applied to a node list that contains a node of non-applicable type
* a TemplateMethodModel will be thrown. However, you can use <tt>_ftype</tt>
* key to explicitly filter out undesired node types prior to applying the
* restricted-applicability key. Also "current nodes" means nodes contained in this
* set.
* <ul>
* <li><tt>*</tt> or <tt>_children</tt>: all direct element children of current nodes (non-recursive). Applicable
* to element and document nodes.</li>
* <li><tt>@*</tt> or <tt>_attributes</tt>: all attributes of current nodes. Applicable to elements only.</li>
* <li><tt>_content</tt> the complete content of current nodes (non-recursive).
* Applicable to elements and documents.</li>
* <li><tt>_text</tt>: the text of current nodes, one string per node (non-recursive).
* Applicable to elements, attributes, comments, processing instructions (returns its data)
* and CDATA sections. The reserved XML characters ('<' and '&') are escaped.</li>
* <li><tt>_plaintext</tt>: same as <tt>_text</tt>, but does not escape any characters,
* and instead of returning a NodeList returns a SimpleScalar.</li>
* <li><tt>_name</tt>: the names of current nodes, one string per node (non-recursive).
* Applicable to elements and attributes (returns their local name),
* entities, processing instructions (returns its target), doctypes
* (returns its public ID)</li>
* <li><tt>_qname</tt>: the qualified names of current nodes in <tt>[namespacePrefix:]localName</tt>
* form, one string per node (non-recursive). Applicable to elements and attributes</li>
* <li><tt>_cname</tt>: the canonical names of current nodes (namespace URI + local name),
* one string per node (non-recursive). Applicable to elements and attributes</li>
* <li><tt>_nsprefix</tt>: namespace prefixes of current nodes,
* one string per node (non-recursive). Applicable to elements and attributes</li>
* <li><tt>_nsuri</tt>: namespace URIs of current nodes,
* one string per node (non-recursive). Applicable to elements and attributes</li>
* <li><tt>_parent</tt>: parent elements of current nodes. Applicable to element, attribute, comment,
* entity, processing instruction.</li>
* <li><tt>_ancestor</tt>: all ancestors up to root element (recursive) of current nodes. Applicable
* to same node types as <tt>_parent</tt>.</li>
* <li><tt>_ancestorOrSelf</tt>: all ancestors of current nodes plus current nodes. Applicable
* to same node types as <tt>_parent</tt>.</li>
* <li><tt>_descendant</tt>: all recursive descendant element children of current nodes. Applicable to
* document and element nodes.
* <li><tt>_descendantOrSelf</tt>: all recursive descendant element children of current nodes
* plus current nodes. Applicable to document and element nodes.
* <li><tt>_document</tt>: all documents the current nodes belong to.
* Applicable to all nodes except text.
* <li><tt>_doctype</tt>: doctypes of the current nodes.
* Applicable to document nodes only.
* <li><tt>_fname</tt>: is a filter-by-name template method model. When called,
* it will yield a node list that contains only those current nodes whose name
* matches one of names passed as argument. Attribute names should NOT be prefixed with the
* at sign (@). Applicable on all node types, however has no effect on unnamed nodes.</li>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -