public TemplateModel get(String key) throws TemplateModelException {
if (isEmpty())
return EMPTY;
if (key == null || key.length() == 0)
throw new TemplateModelException("Invalid key [" + key + "]");
NodeOperator op = null;
NamedNodeOperator nop = null;
String name = null;
switch (key.charAt(0)) {
case '@":
{
if (key.length() != 2 || key.charAt(1) != '*") {
// Generic attribute key
nop = NAMED_ATTRIBUTE_OP;
name = key.substring(1);
} else
// It is @*
op = ALL_ATTRIBUTES_OP;
break;
}
case '*":
{
if (key.length() == 1)
op = ALL_CHILDREN_OP;
else
// Explicitly disallow any other identifier starting with asterisk
throw new TemplateModelException("Invalid key [" + key + "]");
break;
}
case 'x":
case '_":
{
op = (NodeOperator)OPERATIONS.get(key);
if (op == null) {
// Some special operation?
Integer specop = (Integer)SPECIAL_OPERATIONS.get(key);
if (specop != null) {
switch (specop.intValue()) {
case SPECIAL_OPERATION_COPY:
{
synchronized(namespaces)
{
return new NodeListModel(nodes, (Map)((HashMap)namespaces).clone());
}
}
case SPECIAL_OPERATION_UNIQUE:
return new NodeListModel(removeDuplicates(nodes), namespaces);
case SPECIAL_OPERATION_FILTER_NAME:
return new NameFilter();
case SPECIAL_OPERATION_FILTER_TYPE:
return new TypeFilter();
case SPECIAL_OPERATION_QUERY_TYPE:
return getType();
case SPECIAL_OPERATION_REGISTER_NAMESPACE:
return new RegisterNamespace();
case SPECIAL_OPERATION_PLAINTEXT:
return getPlainText();
}
}
}
break;
}
}
if (op == null && nop == null) {
nop = NAMED_CHILDREN_OP;
name = key;
}
List list = null;
if (op != null)
list = evaluateElementOperation(op, nodes);
else {
String localName = name;
Namespace namespace = Namespace.NO_NAMESPACE;
int colon = name.indexOf(':");
if (colon != -1) {
localName = name.substring(colon + 1);
String nsPrefix = name.substring(0, colon);
synchronized(namespaces)
{
namespace = (Namespace)namespaces.get(nsPrefix);
}
if (namespace == null) {
if (nsPrefix.equals("xml"))
namespace = Namespace.XML_NAMESPACE;
else
throw new TemplateModelException("Unregistered namespace prefix '" + nsPrefix + "'");
}
}
list = evaluateNamedElementOperation(nop, localName, namespace, nodes);
}
return createNodeListModel(list, namespaces);
} Deprecated!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
#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 _ftype
key to explicitly filter out undesired node types prior to applying the
restricted-applicability key. Also "current nodes" means nodes contained in this
set.
- * or _children: all direct element children of current nodes (non-recursive). Applicable
to element and document nodes.
- @* or _attributes: all attributes of current nodes. Applicable to elements only.
- _content the complete content of current nodes (non-recursive).
Applicable to elements and documents.
- _text: 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.
- _plaintext: same as _text, but does not escape any characters,
and instead of returning a NodeList returns a SimpleScalar.
- _name: 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)
- _qname: the qualified names of current nodes in [namespacePrefix:]localName
form, one string per node (non-recursive). Applicable to elements and attributes
- _cname: the canonical names of current nodes (namespace URI + local name),
one string per node (non-recursive). Applicable to elements and attributes
- _nsprefix: namespace prefixes of current nodes,
one string per node (non-recursive). Applicable to elements and attributes
- _nsuri: namespace URIs of current nodes,
one string per node (non-recursive). Applicable to elements and attributes
- _parent: parent elements of current nodes. Applicable to element, attribute, comment,
entity, processing instruction.
- _ancestor: all ancestors up to root element (recursive) of current nodes. Applicable
to same node types as _parent.
- _ancestorOrSelf: all ancestors of current nodes plus current nodes. Applicable
to same node types as _parent.
- _descendant: all recursive descendant element children of current nodes. Applicable to
document and element nodes.
- _descendantOrSelf: all recursive descendant element children of current nodes
plus current nodes. Applicable to document and element nodes.
- _document: all documents the current nodes belong to.
Applicable to all nodes except text.
- _doctype: doctypes of the current nodes.
Applicable to document nodes only.
- _fname: 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.
- _ftype: 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 should pass a single string to this method
containing the characters of all types to keep. Valid characters are:
e (Element), a (Attribute), n (Entity), d (Document), t (DocType),
c (Comment), p (ProcessingInstruction), x (text). If the string anywhere contains
the exclamation mark (!), the filter's effect is inverted.
- _type: Returns a one-character String SimpleScalar containing
the typecode of the first node in the node list. Valid characters are:
e (Element), a (Attribute), n (Entity), d (Document), t (DocType),
c (Comment), p (ProcessingInstruction), x (text). If the type of the node
is unknown, returns '?'. If the node list is empty, returns an empty string scalar.
- _unique: 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 _parent,
_ancestor, _ancestorOrSelf, and _document.
I.e. foo._children._parent 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
foo._children._parent._unique to eliminate duplicates. Applicable
to all node types.
- _copy: a copy of the current node list. It is a shallow copy that
shares the underlying node list with this node list, however it has a
separate namespace registry, so it can be used to guarantee that subsequent
changes to the set of registered namespaces does not affect the node lists
that were used to create this node list. Applicable to all node types.
- _registerNamespace(prefix, uri): 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 nodelist["prefix:localname"] or
nodelist["@prefix:localname"] 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. You can also register
namespaces from Java code using the
#registerNamespace(String, String) method.
- @attributeName: named attributes of current nodes. Applicable to
elements, doctypes and processing instructions. On doctypes it supports
attributes publicId, systemId and elementName. On processing
instructions, it supports attributes target and data, as
well as any other attribute name specified in data as name="value" pair.
The attribute nodes for doctype and processing instruction are synthetic, and
as such have no parent. Note, however that @* does NOT operate on
doctypes or processing instructions.
- any other key: element children of current nodes with name matching the key.
This allows for convenience child traversal in book.chapter.title style syntax.
Note that nodeset.childname is technically equivalent to
nodeset._children._fname("childname"), but is both shorter to write
and evaluates faster. Applicable to document and element nodes.
The order of nodes in the resulting set is the order of evaluation of the key
on each node in this set from left to right. Evaluation of the key on a single
node always yields the results in "natural" order (that of the document preorder
traversal), even for uptree traversals. As a consequence, if this node list's nodes
are listed in natural order, applying any of the keys will produce a node list that
is also naturally ordered. As a special case, all node lists that are directly or
indirectly generated from a single Document or Element node through repeated
invocations of this method will be naturally ordered. |
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();
} Deprecated!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. |