📄 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.xml;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import freemarker.log.Logger;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateMethodModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateNodeModel;
import freemarker.template.TemplateScalarModel;
import freemarker.template.TemplateSequenceModel;
import freemarker.template.utility.ClassUtil;
import freemarker.template.utility.Collections12;
/**
* <p>A data model adapter for three widespread XML document object model
* representations: W3C DOM, dom4j, and JDOM. The adapter automatically
* recognizes the used XML object model and provides a unified interface for it
* toward the template. The model provides access to all XML InfoSet features
* of the XML document and includes XPath support if it has access to the XPath-
* evaluator library Jaxen. The model's philosophy (which closely follows that
* of XML InfoSet and XPath) is as follows: it always wraps a list of XML nodes
* (the "nodelist"). The list can be empty, can have a single element, or can
* have multiple elements. Every operation applied to the model is applied to
* all nodes in its nodelist. You usually start with a single- element nodelist,
* usually the root element node or the document node of the XML tree.
* Additionally, the nodes can contain String objects as a result of certain
* evaluations (getting the names of elements, values of attributes, etc.)</p>
* <p><strong>Implementation note:</strong> If you are using W3C DOM documents
* built by the Crimson XML parser (or you are using the built-in JDK 1.4 XML
* parser, which is essentially Crimson), make sure you call
* <tt>setNamespaceAware(true)</tt> on the
* <tt>javax.xml.parsers.DocumentBuilderFactory</tt> instance used for document
* building even when your documents don't use XML namespaces. Failing to do so,
* you will experience incorrect behavior when using the documents wrapped with
* this model.</p>
*
* @deprecated Use {@link freemarker.ext.dom.NodeModel} instead.
* @version $Id: NodeListModel.java,v 1.15 2004/01/06 17:06:43 szegedia Exp $
* @author Attila Szegedi
*/
public class NodeListModel
implements
TemplateHashModel,
TemplateMethodModel,
TemplateScalarModel,
TemplateSequenceModel,
TemplateNodeModel
{
private static final Logger logger = Logger.getLogger("freemarker.xml");
private static final Class DOM_NODE_CLASS = getClass("org.w3c.dom.Node");
private static final Class DOM4J_NODE_CLASS = getClass("org.dom4j.Node");
private static final Navigator DOM_NAVIGATOR = getNavigator("Dom");
private static final Navigator DOM4J_NAVIGATOR = getNavigator("Dom4j");
private static final Navigator JDOM_NAVIGATOR = getNavigator("Jdom");
private static final Namespaces.Factory NS_FACTORY = getNamespacesFactory();
// The navigator object that implements document model-specific behavior.
private final Navigator navigator;
// The contained nodes
private final List nodes;
// The namespaces object (potentially shared by multiple models)
private Namespaces namespaces;
/**
* Creates a new NodeListModel, wrapping the passed nodes.
* @param nodes you can pass it a single XML node from any supported
* document model, or a Java collection containing any number of nodes.
* Passing null is prohibited. To create an empty model, pass it an empty
* collection. If a collection is passed, all passed nodes must belong to
* the same XML object model, i.e. you can't mix JDOM and dom4j in a single
* instance of NodeListModel. The model itself doesn't check for this condition,
* as it can be time consuming, but will throw spurious
* {@link ClassCastException}s when it encounters mixed objects.
* @throws IllegalArgumentException if you pass null
*/
public NodeListModel(Object nodes) {
Object node = nodes;
if(nodes instanceof Collection) {
this.nodes = new ArrayList((Collection)nodes);
node = this.nodes.isEmpty() ? null : this.nodes.get(0);
}
else if(nodes != null) {
this.nodes = Collections12.singletonList(nodes);
}
else {
throw new IllegalArgumentException("nodes == null");
}
if(DOM_NODE_CLASS != null && DOM_NODE_CLASS.isInstance(node)) {
navigator = DOM_NAVIGATOR;
}
else if(DOM4J_NODE_CLASS != null && DOM4J_NODE_CLASS.isInstance(node)) {
navigator = DOM4J_NAVIGATOR;
}
else {
// Assume JDOM
navigator = JDOM_NAVIGATOR;
}
namespaces = NS_FACTORY.create();
}
private NodeListModel(Navigator navigator, List nodes, Namespaces namespaces) {
this.navigator = navigator;
this.nodes = nodes;
this.namespaces = namespaces;
}
private NodeListModel deriveModel(List derivedNodes) {
namespaces.markShared();
return new NodeListModel(navigator, derivedNodes, namespaces);
}
/**
* Returns the number of nodes in this model's nodelist.
* @see freemarker.template.TemplateSequenceModel#size()
*/
public int size() {
return nodes.size();
}
/**
* Evaluates an XPath expression on XML nodes in this model.
* @param arguments the arguments to the method invocation. Expectes exactly
* one argument - the XPath expression.
* @return a new NodeListModel with nodes selected by applying the XPath
* expression to this model's nodelist.
* @see freemarker.template.TemplateMethodModel#exec(List)
*/
public Object exec(List arguments) throws TemplateModelException {
if(arguments.size() != 1) {
throw new TemplateModelException(
"Expecting exactly one argument - an XPath expression");
}
return deriveModel(navigator.applyXPath(nodes, (String)arguments.get(0), namespaces));
}
/**
* Returns the string representation of the wrapped nodes. String objects in
* the nodelist are rendered as-is (with no XML escaping applied). All other
* nodes are rendered in the default XML serialization format ("plain XML").
* This makes the model quite suited for use as an XML-transformation tool.
* @return the string representation of the wrapped nodes. String objects
* in the nodelist are rendered as-is (with no XML escaping applied). All
* other nodes are rendered in the default XML serialization format ("plain
* XML").
* @see freemarker.template.TemplateScalarModel#getAsString()
*/
public String getAsString() throws TemplateModelException {
StringWriter sw = new StringWriter(size() * 128);
for (Iterator iter = nodes.iterator(); iter.hasNext();) {
Object o = iter.next();
if(o instanceof String) {
sw.write((String)o);
}
else {
navigator.getAsString(o, sw);
}
}
return sw.toString();
}
/**
* Selects a single node from this model's nodelist by its list index and
* returns a new NodeListModel containing that single node.
* @param index the ordinal number of the selected node
* @see freemarker.template.TemplateSequenceModel#get(int)
*/
public TemplateModel get(int index) {
return deriveModel(Collections12.singletonList(nodes.get(index)));
}
/**
* Returns a new NodeListModel containing the nodes that result from applying
* an operator to this model's nodes.
* @param key the operator to apply to nodes. Available operators are:
* <table border="1">
* <thead>
* <tr>
* <th align="left">Key name</th>
* <th align="left">Evaluates to</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td><tt>*</tt> or <tt>_children</tt></td>
* <td>all direct element children of current nodes (non-recursive).
* Applicable to element and document nodes.</td>
* </tr>
* <tr>
* <td><tt>@*</tt> or <tt>_attributes</tt></td>
* <td>all attributes of current nodes. Applicable to elements only.
* </td>
* </tr>
* <tr>
* <td><tt>@<i>attributeName</i></tt></td>
* <td>named attributes of current nodes. Applicable to elements,
* doctypes and processing instructions. On doctypes it supports
* attributes <tt>publicId</tt>, <tt>systemId</tt> and
* <tt>elementName</tt>. On processing instructions, it supports
* attributes <tt>target</tt> and <tt>data</tt>, as well as any
* other attribute name specified in data as
* <tt>name="value"</tt> pair on dom4j or JDOM models.
* The attribute nodes for doctype and processing instruction are
* synthetic, and as such have no parent. Note, however that
* <tt>@*</tt> does NOT operate on doctypes or processing
* instructions.</td>
* </tr>
*
* <tr>
* <td><tt>_ancestor</tt></td>
* <td>all ancestors up to root element (recursive) of current nodes.
* Applicable to same node types as <tt>_parent</tt>.</td>
* </tr>
* <tr>
* <td><tt>_ancestorOrSelf</tt></td>
* <td>all ancestors of current nodes plus current nodes. Applicable
* to same node types as <tt>_parent</tt>.</td>
* </tr>
* <tr>
* <td><tt>_cname</tt></td>
* <td>the canonical names of current nodes (namespace URI + local
* name), one string per node (non-recursive). Applicable to
* elements and attributes</td>
* </tr>
* <tr>
* <td><tt>_content</tt></td>
* <td>the complete content of current nodes, including children
* elements, text, entity references, and processing instructions
* (non-recursive). Applicable to elements and documents.</td>
* </tr>
* <tr>
* <td><tt>_descendant</tt></td>
* <td>all recursive descendant element children of current nodes.
* Applicable to document and element nodes.</td>
* </tr>
* <tr>
* <td><tt>_descendantOrSelf</tt></td>
* <td>all recursive descendant element children of current nodes
* plus current nodes. Applicable to document and element nodes.
* </td>
* </tr>
* <tr>
* <td><tt>_document</tt></td>
* <td>all documents the current nodes belong to. Applicable to all
* nodes except text.</td>
* </tr>
* <tr>
* <td><tt>_doctype</tt></td>
* <td>doctypes of the current nodes. Applicable to document nodes
* only.</td>
* </tr>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -