1 52 53 package freemarker.template.utility; 54 55 import freemarker.template.*; 56 import org.w3c.dom.*; 57 import java.util.*; 58 59 63 64 public class DOMNodeModel implements TemplateHashModel { 65 66 static private HashMap equivalenceTable = new HashMap(); 67 static { 68 equivalenceTable.put("*", "children"); 69 equivalenceTable.put("@*", "attributes"); 70 } 71 72 private Node node; 73 private HashMap cache = new HashMap(); 74 75 public DOMNodeModel(Node node) { 76 this.node = node; 77 } 78 79 public TemplateModel get(String key) throws TemplateModelException { 80 TemplateModel result = null; 81 if (equivalenceTable.containsKey(key)) { 82 key = (String ) equivalenceTable.get(key); 83 } 84 if (cache.containsKey(key)) { 85 result = (TemplateModel) cache.get(key); 86 } 87 if (result == null) { 88 if ("attributes".equals(key)) { 89 NamedNodeMap attributes = node.getAttributes(); 90 if (attributes != null) { 91 SimpleHash hash = new SimpleHash(); 92 for (int i = 0; i<attributes.getLength(); i++) { 93 Attr att = (Attr) attributes.item(i); 94 hash.put(att.getName(), att.getValue()); 95 } 96 result = hash; 97 } 98 } 99 else if (key.charAt(0) == '@') { 100 if (node instanceof Element) { 101 String attValue = ((Element) node).getAttribute(key.substring(1)); 102 result = new SimpleScalar(attValue); 103 } 104 else { 105 throw new TemplateModelException("Trying to get an attribute value for a non-element node"); 106 } 107 } 108 else if ("is_element".equals(key)) { 109 result = (node instanceof Element) ? 110 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; 111 } 112 else if ("is_text".equals(key)) { 113 result = (node instanceof Text) ? 114 TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; 115 } 116 else if ("name".equals(key)) { 117 result = new SimpleScalar(node.getNodeName()); 118 } 119 else if ("children".equals(key)) { 120 result = new NodeListTM(node.getChildNodes()); 121 } 122 else if ("parent".equals(key)) { 123 Node parent = node.getParentNode(); 124 result = (parent == null) ? null : new DOMNodeModel(parent); 125 } 126 else if ("ancestorByName".equals(key)) { 127 result = new AncestorByName(); 128 } 129 else if ("nextSibling".equals(key)) { 130 Node next = node.getNextSibling(); 131 result = (next == null) ? null : new DOMNodeModel(next); 132 } 133 else if ("previousSibling".equals(key)) { 134 Node previous = node.getPreviousSibling(); 135 result = (previous == null) ? null : new DOMNodeModel(previous); 136 } 137 else if ("nextSiblingElement".equals(key)) { 138 Node next = nextSiblingElement(node); 139 result = (next == null) ? null : new DOMNodeModel(next); 140 } 141 else if ("previousSiblingElement".equals(key)) { 142 Node previous = previousSiblingElement(node); 143 result = (previous == null) ? null : new DOMNodeModel(previous); 144 } 145 else if ("nextElement".equals(key)) { 146 Node next = nextElement(node); 147 result = (next == null) ? null : new DOMNodeModel(next); 148 } 149 else if ("previousElement".equals(key)) { 150 Node previous = previousElement(node); 151 result = (previous == null) ? null : new DOMNodeModel(previous); 152 } 153 else if ("text".equals(key)) { 154 result = new SimpleScalar(getText(node)); 155 } 156 cache.put(key, result); 157 } 158 return result; 159 } 160 161 public boolean isEmpty() { 162 return false; 163 } 164 165 static private String getText(Node node) { 166 String result = ""; 167 if (node instanceof Text) { 168 result = ((Text) node).getData(); 169 } 170 else if (node instanceof Element) { 171 NodeList children = node.getChildNodes(); 172 for (int i= 0; i<children.getLength(); i++) { 173 result += getText(children.item(i)); 174 } 175 } 176 return result; 177 } 178 179 static private Element nextSiblingElement(Node node) { 180 Node next = node; 181 while (next != null) { 182 next = next.getNextSibling(); 183 if (next instanceof Element) { 184 return (Element) next; 185 } 186 } 187 return null; 188 } 189 190 static private Element previousSiblingElement(Node node) { 191 Node previous = node; 192 while (previous != null) { 193 previous = previous.getPreviousSibling(); 194 if (previous instanceof Element) { 195 return (Element) previous; 196 } 197 } 198 return null; 199 } 200 201 static private Element nextElement(Node node) { 202 if (node.hasChildNodes()) { 203 NodeList children = node.getChildNodes(); 204 for (int i=0; i<children.getLength();i++) { 205 Node child = children.item(i); 206 if (child instanceof Element) { 207 return (Element) child; 208 } 209 } 210 } 211 Element nextSiblingElement = nextSiblingElement(node); 212 if (nextSiblingElement != null) { 213 return nextSiblingElement; 214 } 215 Node parent = node.getParentNode(); 216 while (parent instanceof Element) { 217 Element next = nextSiblingElement(parent); 218 if (next != null) { 219 return next; 220 } 221 parent = parent.getParentNode(); 222 } 223 return null; 224 } 225 226 static private Element previousElement(Node node) { 227 Element result = previousSiblingElement(node); 228 if (result != null) { 229 return result; 230 } 231 Node parent = node.getParentNode(); 232 if (parent instanceof Element) { 233 return (Element) parent; 234 } 235 return null; 236 } 237 238 void setParent(DOMNodeModel parent) { 239 if (parent != null) { 240 cache.put("parent", parent); 241 } 242 } 243 244 String getNodeName() { 245 return node.getNodeName(); 246 } 247 248 249 class AncestorByName implements TemplateMethodModel { 250 public Object exec(List arguments) throws TemplateModelException { 251 if (arguments.size() != 1) { 252 throw new TemplateModelException("Expecting exactly one string argument here"); 253 } 254 String nodeName = (String ) arguments.get(0); 255 DOMNodeModel ancestor = (DOMNodeModel) DOMNodeModel.this.get("parent"); 256 while (ancestor != null) { 257 if (nodeName.equals(ancestor.getNodeName())) { 258 return ancestor; 259 } 260 ancestor = (DOMNodeModel) ancestor.get("parent"); 261 } 262 return null; 263 } 264 } 265 266 267 class NodeListTM implements TemplateSequenceModel, TemplateMethodModel { 268 269 private NodeList nodeList; 270 private TemplateModel[] nodes; 271 272 NodeListTM(NodeList nodeList) { 273 this.nodeList = nodeList; 274 nodes = new TemplateModel[nodeList.getLength()]; 275 } 276 277 public TemplateModel get(int index) { 278 DOMNodeModel result = (DOMNodeModel) nodes[index]; 279 if (result == null) { 280 result = new DOMNodeModel(nodeList.item(index)); 281 nodes[index] = result; 282 result.setParent(DOMNodeModel.this); 283 } 284 return result; 285 } 286 287 public int size() { 288 return nodes.length; 289 } 290 291 public Object exec(List arguments) throws TemplateModelException { 292 if (arguments.size() != 1) { 293 throw new TemplateModelException("Expecting exactly one string argument here"); 294 } 295 if (!(node instanceof Element)) { 296 throw new TemplateModelException("Expecting element here."); 297 } 298 Element elem = (Element) node; 299 return new NodeListTM(elem.getElementsByTagName((String ) arguments.get(0))); 300 } 301 } 302 } 303 304 | Popular Tags |