📄 nodemodel.java
字号:
case Node.PROCESSING_INSTRUCTION_NODE : return "pi";
case Node.TEXT_NODE : return "text";
}
throw new TemplateModelException("Unknown node type: " + nodeType + ". This should be impossible!");
}
public TemplateModel exec(List args) throws TemplateModelException {
if (args.size() != 1) {
throw new TemplateModelException("Expecting exactly one arguments");
}
String query = (String) args.get(0);
// Now, we try to behave as if this is an XPath expression
XPathSupport xps = getXPathSupport();
if (xps == null) {
throw new TemplateModelException("No XPath support available");
}
return xps.executeQuery(node, query);
}
public final int size() {return 1;}
public final TemplateModel get(int i) {
return i==0 ? this : null;
}
public String getNodeNamespace() {
int nodeType = node.getNodeType();
if (nodeType != Node.ATTRIBUTE_NODE && nodeType != Node.ELEMENT_NODE) {
return null;
}
String result = node.getNamespaceURI();
if (result == null && nodeType == Node.ELEMENT_NODE) {
result = "";
} else if ("".equals(result) && nodeType == Node.ATTRIBUTE_NODE) {
result = null;
}
return result;
}
public final int hashCode() {
return node.hashCode();
}
public boolean equals(Object other) {
if (other == null) return false;
return other.getClass() == this.getClass()
&& ((NodeModel) other).node.equals(this.node);
}
static public NodeModel wrap(Node node) {
if (node == null) {
return null;
}
NodeModel result = null;
switch (node.getNodeType()) {
case Node.DOCUMENT_NODE : result = new DocumentModel((Document) node); break;
case Node.ELEMENT_NODE : result = new ElementModel((Element) node); break;
case Node.ATTRIBUTE_NODE : result = new AttributeNodeModel((Attr) node); break;
case Node.CDATA_SECTION_NODE :
case Node.COMMENT_NODE :
case Node.TEXT_NODE : result = new CharacterDataNodeModel((org.w3c.dom.CharacterData) node); break;
case Node.PROCESSING_INSTRUCTION_NODE : result = new PINodeModel((ProcessingInstruction) node); break;
case Node.DOCUMENT_TYPE_NODE : result = new DocumentTypeModel((DocumentType) node); break;
}
return result;
}
/**
* Recursively removes all comment nodes
* from the subtree.
*
* @see #simplify
*/
static public void removeComments(Node node) {
NodeList children = node.getChildNodes();
int i = 0;
int len = children.getLength();
while (i < len) {
Node child = children.item(i);
if (child.hasChildNodes()) {
removeComments(child);
i++;
} else {
if (child.getNodeType() == Node.COMMENT_NODE) {
node.removeChild(child);
len--;
} else {
i++;
}
}
}
}
/**
* Recursively removes all processing instruction nodes
* from the subtree.
*
* @see #simplify
*/
static public void removePIs(Node node) {
NodeList children = node.getChildNodes();
int i = 0;
int len = children.getLength();
while (i < len) {
Node child = children.item(i);
if (child.hasChildNodes()) {
removePIs(child);
i++;
} else {
if (child.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
node.removeChild(child);
len--;
} else {
i++;
}
}
}
}
/**
* Merges adjacent text/cdata nodes, so that there are no
* adjacent text/cdata nodes. Operates recursively
* on the entire subtree. You thus lose information
* about any CDATA sections occurring in the doc.
*
* @see #simplify
*/
static public void mergeAdjacentText(Node node) {
Node child = node.getFirstChild();
while (child != null) {
if (child instanceof Text || child instanceof CDATASection) {
Node next = child.getNextSibling();
if (next instanceof Text || next instanceof CDATASection) {
String fullText = child.getNodeValue() + next.getNodeValue();
((CharacterData) child).setData(fullText);
node.removeChild(next);
}
}
else {
mergeAdjacentText(child);
}
child = child.getNextSibling();
}
}
/**
* Removes comments and processing instruction, and then unites adjacent text nodes.
* Note that CDATA sections count as text nodes.
*/
static public void simplify(Node node) {
NodeList children = node.getChildNodes();
int i = 0;
int len = children.getLength();
Node prevTextChild = null;
while (i < len) {
Node child = children.item(i);
if (child.hasChildNodes()) {
simplify(child);
prevTextChild = null;
i++;
} else {
int type = child.getNodeType();
if (type == Node.PROCESSING_INSTRUCTION_NODE) {
node.removeChild(child);
len--;
} else if (type == Node.COMMENT_NODE) {
node.removeChild(child);
len--;
} else if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE ) {
if (prevTextChild != null) {
CharacterData ptc = (CharacterData) prevTextChild;
ptc.setData(ptc.getNodeValue() + child.getNodeValue());
node.removeChild(child);
len--;
} else {
prevTextChild = child;
i++;
}
} else {
prevTextChild = null;
i++;
}
}
}
}
NodeModel getDocumentNodeModel() {
if (node instanceof Document) {
return this;
}
else {
return wrap(node.getOwnerDocument());
}
}
/**
* Tells the system to use (restore) the default (initial) XPath system used by
* this FreeMarker version on this system.
*/
static public void useDefaultXPathSupport() {
xpathSupportClass = null;
jaxenXPathSupport = null;
try {
useXalanXPathSupport();
} catch (Exception e) {
; // ignore
}
if (xpathSupportClass == null) try {
useJaxenXPathSupport();
} catch (Exception e) {
; // ignore
}
}
/**
* Convenience method. Tells the system to use Jaxen for XPath queries.
* @throws Exception if the Jaxen classes are not present.
*/
static public void useJaxenXPathSupport() throws Exception {
Class.forName("org.jaxen.dom.DOMXPath");
Class c = Class.forName("freemarker.ext.dom.JaxenXPathSupport");
jaxenXPathSupport = (XPathSupport) c.newInstance();
if (logger.isDebugEnabled()) {
logger.debug("Using Jaxen classes for XPath support");
}
xpathSupportClass = c;
}
/**
* Convenience method. Tells the system to use Xalan for XPath queries.
* @throws Exception if the Xalan XPath classes are not present.
*/
static public void useXalanXPathSupport() throws Exception {
Class.forName("org.apache.xpath.XPath");
Class c = Class.forName("freemarker.ext.dom.XalanXPathSupport");
if (logger.isDebugEnabled()) {
logger.debug("Using Xalan classes for XPath support");
}
xpathSupportClass = c;
}
/**
* Set an alternative implementation of freemarker.ext.dom.XPathSupport to use
* as the XPath engine.
* @param cl the class, or <code>null</code> to disable XPath support.
*/
static public void setXPathSupportClass(Class cl) {
if (cl != null && !cl.isAssignableFrom(XPathSupport.class)) {
throw new RuntimeException("Class " + cl.getName()
+ " does not implement freemarker.ext.dom.XPathSupport");
}
xpathSupportClass = cl;
}
/**
* Get the currently used freemarker.ext.dom.XPathSupport used as the XPath engine.
* Returns <code>null</code> if XPath support is disabled.
*/
static public Class getXPathSupportClass() {
return xpathSupportClass;
}
static private String getText(Node node) {
String result = "";
if (node instanceof Text || node instanceof CDATASection) {
result = ((org.w3c.dom.CharacterData) node).getData();
}
else if (node instanceof Element) {
NodeList children = node.getChildNodes();
for (int i= 0; i<children.getLength(); i++) {
result += getText(children.item(i));
}
}
else if (node instanceof Document) {
result = getText(((Document) node).getDocumentElement());
}
return result;
}
XPathSupport getXPathSupport() {
if (jaxenXPathSupport != null) {
return jaxenXPathSupport;
}
XPathSupport xps = null;
Document doc = node.getOwnerDocument();
if (doc == null) {
doc = (Document) node;
}
synchronized (doc) {
WeakReference ref = (WeakReference) xpathSupportMap.get(doc);
if (ref != null) {
xps = (XPathSupport) ref.get();
}
if (xps == null) {
try {
xps = (XPathSupport) xpathSupportClass.newInstance();
xpathSupportMap.put(doc, new WeakReference(xps));
} catch (Exception e) {
logger.error("Error instantiating xpathSupport class");
}
}
}
return xps;
}
String getQualifiedName() throws TemplateModelException {
return getNodeName();
}
public Object getAdaptedObject(Class hint) {
return node;
}
public Object getWrappedObject() {
return node;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -