📄 nodelistmodel.java
字号:
* <tr>
* <td><tt>_filterType</tt></td>
* <td>is a filter-by-type template method model. When called, it
* will yield a node list that contains only those current nodes
* whose type matches one of types passed as argument. You can pass
* as many string arguments as you want, each representing one of
* the types to select: "attribute", "cdata",
* "comment", "document",
* "documentType", "element",
* "entity", "entityReference",
* "namespace", "processingInstruction", or
* "text".</td>
* </tr>
* <tr>
* <td><tt>_name</tt></td>
* <td>the names of current nodes, one string per node
* (non-recursive). Applicable to elements and attributes
* (returns their local names), entity references, processing
* instructions (returns its target), doctypes (returns its public
* ID)</td>
* </tr>
* <tr>
* <td><tt>_nsprefix</tt></td>
* <td>the namespace prefixes of current nodes, one string per node
* (non-recursive). Applicable to elements and attributes</td>
* </tr>
* <tr>
* <td><tt>_nsuri</tt></td>
* <td>the namespace URIs of current nodes, one string per node
* (non-recursive). Applicable to elements and attributes</td>
* </tr>
* <tr>
* <td><tt>_parent</tt></td>
* <td>parent elements of current nodes. Applicable to element,
* attribute, comment, entity, processing instruction.</td>
* </tr>
* <tr>
* <td><tt>_qname</tt></td>
* <td>the qualified names of current nodes in
* <tt>[namespacePrefix:]localName</tt> form, one string per node
* (non-recursive). Applicable to elements and attributes</td>
* </tr>
* <tr>
* <td><tt>_registerNamespace(prefix, uri)</tt></td>
* <td>register a XML namespace with the specified prefix and URI for
* the current node list and all node lists that are derived from
* the current node list. After registering, you can use the
* <tt>nodelist["prefix:localname"]</tt> or
* <tt>nodelist["@prefix:localname"]</tt> syntaxes to
* reach elements and attributes whose names are namespace-scoped.
* Note that the namespace prefix need not match the actual prefix
* used by the XML document itself since namespaces are compared
* solely by their URI.</td>
* </tr>
* <tr>
* <td><tt>_text</tt></td>
* <td>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 NOT
* escaped.</td>
* </tr>
* <tr>
* <td><tt>_type</tt></td>
* <td>Returns a string describing the type of nodes, one
* string per node. The returned values are "attribute",
* "cdata", "comment", "document",
* "documentType", "element",
* "entity", "entityReference",
* "namespace", "processingInstruction",
* "text", or "unknown".</td>
* </tr>
* <tr>
* <td><tt>_unique</tt></td>
* <td>a copy of the current nodes that keeps only the first
* occurrence of every node, eliminating duplicates. Duplicates can
* occur in the node list by applying uptree-traversals
* <tt>_parent</tt>, <tt>_ancestor</tt>, <tt>_ancestorOrSelf</tt>,
* and <tt>_document</tt> on a node list with multiple elements.
* I.e. <tt>foo._children._parent</tt> will return a node list that
* has duplicates of nodes in foo - each node will have the number
* of occurrences equal to the number of its children. In these
* cases, use <tt>foo._children._parent._unique</tt> to eliminate
* duplicates. Applicable to all node types.</td>
* </tr>
* <tr>
* <td>any other key</td>
* <td>element children of current nodes with name matching the key.
* This allows for convenience child traversal in
* <tt>book.chapter.title</tt> style syntax. Applicable to document
* and element nodes.</td>
* </tr>
* </tbody>
* </table>
* @return a new NodeListModel containing the nodes that result from applying
* the operator to this model's nodes.
* @see freemarker.template.TemplateHashModel#get(String)
*/
public TemplateModel get(String key) throws TemplateModelException {
// Try a built-in navigator operator
NodeOperator op = navigator.getOperator(key);
String localName = null;
String namespaceUri = "";
// If not a nav op, then check for special keys.
if(op == null && key.length() > 0 && key.charAt(0) == '_') {
if(key.equals("_unique")) {
return deriveModel(removeDuplicates(nodes));
}
else if(key.equals("_filterType") || key.equals("_ftype")) {
return new FilterByType();
}
else if(key.equals("_registerNamespace")) {
if(namespaces.isShared()) {
namespaces = (Namespaces)namespaces.clone();
}
}
}
// Last, do a named child element or attribute lookup
if(op == null) {
int colon = key.indexOf(':');
if(colon == -1) {
// No namespace prefix specified
localName = key;
}
else {
// Namespace prefix specified
localName = key.substring(colon + 1);
String prefix = key.substring(0, colon);
namespaceUri = namespaces.translateNamespacePrefixToUri(prefix);
if(namespaceUri == null) {
throw new TemplateModelException("Namespace prefix " + prefix + " is not registered.");
}
}
if(localName.charAt(0) == '@') {
op = navigator.getAttributeOperator();
localName = localName.substring(1);
}
else {
op = navigator.getChildrenOperator();
}
}
List result = new ArrayList();
for (Iterator iter = nodes.iterator(); iter.hasNext();) {
try {
op.process(iter.next(), localName, namespaceUri, result);
}
catch(RuntimeException e) {
throw new TemplateModelException(e);
}
}
return deriveModel(result);
}
/**
* Returns true if this NodeListModel contains no nodes.
* @see freemarker.template.TemplateHashModel#isEmpty()
*/
public boolean isEmpty() {
return nodes.isEmpty();
}
/**
* Registers a namespace prefix-URI pair for subsequent use in {@link
* #get(String)} as well as for use in XPath expressions.
* @param prefix the namespace prefix to use for the namespace
* @param uri the namespace URI that identifies the namespace.
*/
public void registerNamespace(String prefix, String uri) {
if(namespaces.isShared()) {
namespaces = (Namespaces)namespaces.clone();
}
namespaces.registerNamespace(prefix, uri);
}
private class FilterByType
implements
TemplateMethodModel
{
public Object exec(List arguments)
{
List filteredNodes = new ArrayList();
for (Iterator iter = arguments.iterator(); iter.hasNext();)
{
Object node = iter.next();
if(arguments.contains(navigator.getType(node))) {
filteredNodes.add(node);
}
}
return deriveModel(filteredNodes);
}
}
private static final List removeDuplicates(List list)
{
int s = list.size();
ArrayList ulist = new ArrayList(s);
Set set = new HashSet(s * 4 / 3, .75f);
Iterator it = list.iterator();
while (it.hasNext()) {
Object o = it.next();
if (set.add(o)) {
ulist.add(o);
}
}
return ulist;
}
private static Class getClass(String className) {
try {
return ClassUtil.forName(className);
}
catch(Exception e) {
if(logger.isDebugEnabled()) {
logger.debug("Couldn't load class " + className, e);
}
return null;
}
}
private static Namespaces.Factory getNamespacesFactory() {
Namespaces.Factory factory = getNamespacesFactory("JaxenNamespaces");
if(factory == null) {
factory = getNamespacesFactory("Namespaces");
}
return factory;
}
private static Namespaces.Factory getNamespacesFactory(String clazz) {
try {
return (Namespaces.Factory)
ClassUtil.forName("freemarker.ext.xml." + clazz)
.getDeclaredField("FACTORY").get(null);
}
catch(Throwable t) {
if(logger.isDebugEnabled()) {
logger.debug("Could not load " + clazz, t);
}
return null;
}
}
private static Navigator getNavigator(String navType) {
try {
Navigator nav =
(Navigator) ClassUtil.forName("freemarker.ext.xml." + navType + "Navigator")
.getDeclaredConstructor(new Class[] {}).newInstance(new Object[] {});
return nav;
}
catch(Throwable t) {
if(logger.isDebugEnabled()) {
logger.debug("Could not load navigator for " + navType, t);
}
return null;
}
}
public TemplateSequenceModel getChildNodes() throws TemplateModelException
{
return (TemplateSequenceModel)get("_content");
}
public String getNodeName() throws TemplateModelException
{
return getUniqueText((NodeListModel)get("_name"), "name");
}
public String getNodeNamespace() throws TemplateModelException
{
return getUniqueText((NodeListModel)get("_nsuri"), "namespace");
}
public String getNodeType() throws TemplateModelException
{
return getUniqueText((NodeListModel)get("_type"), "type");
}
public TemplateNodeModel getParentNode() throws TemplateModelException
{
return (TemplateNodeModel)get("_parent");
}
private String getUniqueText(NodeListModel model, String property) throws TemplateModelException {
String s1 = null;
Set s = null;
for(Iterator it = model.nodes.iterator(); it.hasNext();) {
String s2 = (String)it.next();
if(s2 != null) {
// No text yet, make this text the current text
if(s1 == null) {
s1 = s2;
}
// else if there's already a text and they differ, start
// accumulating them for an error message
else if(!s1.equals(s2)) {
if(s == null) {
s = new HashSet();
s.add(s1);
}
s.add(s2);
}
}
}
// If the set for the error messages is empty, return the retval
if(s == null) {
return s1;
}
// Else throw an exception signaling ambiguity
throw new TemplateModelException(
"Value for node " + property + " is ambiguos: " + s);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -