1 52 53 package freemarker.ext.dom; 54 55 import freemarker.template.utility.StringUtil; 56 import freemarker.template.Template; 57 import freemarker.core.Environment; 58 import java.util.*; 59 import org.w3c.dom.*; 60 61 class NodeOutputter { 62 63 private Element contextNode; 64 private Environment env; 65 private String defaultNS; 66 private boolean hasDefaultNS; 67 private boolean explicitDefaultNSPrefix; 68 private HashMap namespacesToPrefixLookup = new HashMap(); 69 private String namespaceDecl; 70 71 NodeOutputter(Node node) { 72 if (node instanceof Element) { 73 setContext((Element) node); 74 } 75 else if (node instanceof Attr) { 76 setContext(((Attr) node).getOwnerElement()); 77 } 78 else if (node instanceof Document) { 79 setContext(((Document) node).getDocumentElement()); 80 } 81 } 82 83 private void setContext(Element contextNode) { 84 this.contextNode = contextNode; 85 this.env = Environment.getCurrentEnvironment(); 86 this.defaultNS = env.getDefaultNS(); 87 this.hasDefaultNS = defaultNS != null && defaultNS.length() >0; 88 namespacesToPrefixLookup.put(null, ""); 89 namespacesToPrefixLookup.put("", ""); 90 buildPrefixLookup(contextNode); 91 if (!explicitDefaultNSPrefix && hasDefaultNS) { 92 namespacesToPrefixLookup.put(defaultNS, ""); 93 } 94 constructNamespaceDecl(); 95 } 96 97 private void buildPrefixLookup(Node n) { 98 String nsURI = n.getNamespaceURI(); 99 if (nsURI != null && nsURI.length() >0) { 100 String prefix = env.getPrefixForNamespace(nsURI); 101 namespacesToPrefixLookup.put(nsURI, prefix); 102 } else if (hasDefaultNS && n.getNodeType() == Node.ELEMENT_NODE) { 103 namespacesToPrefixLookup.put(defaultNS, Template.DEFAULT_NAMESPACE_PREFIX); 104 explicitDefaultNSPrefix = true; 105 } else if (n.getNodeType() == Node.ATTRIBUTE_NODE && hasDefaultNS && defaultNS.equals(nsURI)) { 106 namespacesToPrefixLookup.put(defaultNS, Template.DEFAULT_NAMESPACE_PREFIX); 107 explicitDefaultNSPrefix = true; 108 } 109 NodeList childNodes = n.getChildNodes(); 110 for (int i = 0; i<childNodes.getLength(); i++) { 111 buildPrefixLookup(childNodes.item(i)); 112 } 113 } 114 115 private void constructNamespaceDecl() { 116 StringBuffer buf = new StringBuffer (); 117 if (explicitDefaultNSPrefix) { 118 buf.append(" xmlns=\""); 119 buf.append(defaultNS); 120 buf.append("\""); 121 } 122 for (Iterator it = namespacesToPrefixLookup.keySet().iterator(); it.hasNext();) { 123 String nsURI = (String ) it.next(); 124 if (nsURI == null || nsURI.length() == 0) { 125 continue; 126 } 127 String prefix = (String ) namespacesToPrefixLookup.get(nsURI); 128 if (prefix == null) { 129 for (int i=0;i<26;i++) { 132 char[] cc = new char[1]; 133 cc[0] = (char) ('a' + i); 134 prefix = new String (cc); 135 if (env.getNamespaceForPrefix(prefix) == null) { 136 break; 137 } 138 prefix = null; 139 } 140 if (prefix == null) { 141 throw new RuntimeException ("This will almost never happen!"); 142 } 143 namespacesToPrefixLookup.put(nsURI, prefix); 144 } 145 buf.append(" xmlns"); 146 if (prefix.length() >0) { 147 buf.append(":"); 148 buf.append(prefix); 149 } 150 buf.append("=\""); 151 buf.append(nsURI); 152 buf.append("\""); 153 } 154 this.namespaceDecl = buf.toString(); 155 } 156 157 private void outputQualifiedName(Node n, StringBuffer buf) { 158 String nsURI = n.getNamespaceURI(); 159 if (nsURI == null || nsURI.length() == 0) { 160 buf.append(n.getNodeName()); 161 } else { 162 String prefix = (String ) namespacesToPrefixLookup.get(nsURI); 163 if (prefix == null) { 164 buf.append(n.getNodeName()); 166 } else { 167 if (prefix.length() > 0) { 168 buf.append(prefix); 169 buf.append(':'); 170 } 171 buf.append(n.getLocalName()); 172 } 173 } 174 } 175 176 void outputContent(Node n, StringBuffer buf) { 177 switch(n.getNodeType()) { 178 case Node.ATTRIBUTE_NODE: { 179 if (((Attr) n).getSpecified()) { 180 buf.append(' '); 181 outputQualifiedName(n, buf); 182 buf.append("=\"") 183 .append(StringUtil.XMLEncQAttr(n.getNodeValue())) 184 .append('"'); 185 } 186 break; 187 } 188 case Node.COMMENT_NODE: { 189 buf.append("<!--").append(n.getNodeValue()).append("-->"); 190 break; 191 } 192 case Node.DOCUMENT_NODE: { 193 outputContent(n.getChildNodes(), buf); 194 break; 195 } 196 case Node.DOCUMENT_TYPE_NODE: { 197 buf.append("<!DOCTYPE ").append(n.getNodeName()); 198 DocumentType dt = (DocumentType)n; 199 if(dt.getPublicId() != null) { 200 buf.append(" PUBLIC \"").append(dt.getPublicId()).append('"'); 201 } 202 if(dt.getSystemId() != null) { 203 buf.append(" \"").append(dt.getSystemId()).append('"'); 204 } 205 if(dt.getInternalSubset() != null) { 206 buf.append(" [").append(dt.getInternalSubset()).append(']'); 207 } 208 buf.append('>'); 209 break; 210 } 211 case Node.ELEMENT_NODE: { 212 buf.append('<'); 213 outputQualifiedName(n, buf); 214 if (n == contextNode) { 215 buf.append(namespaceDecl); 216 } 217 outputContent(n.getAttributes(), buf); 218 NodeList children = n.getChildNodes(); 219 if (children.getLength() == 0) { 220 buf.append(" />"); 221 } else { 222 buf.append('>'); 223 outputContent(n.getChildNodes(), buf); 224 buf.append("</"); 225 outputQualifiedName(n, buf); 226 buf.append('>'); 227 } 228 break; 229 } 230 case Node.ENTITY_NODE: { 231 outputContent(n.getChildNodes(), buf); 232 break; 233 } 234 case Node.ENTITY_REFERENCE_NODE: { 235 buf.append('&').append(n.getNodeName()).append(';'); 236 break; 237 } 238 case Node.PROCESSING_INSTRUCTION_NODE: { 239 buf.append("<?").append(n.getNodeName()).append(' ').append(n.getNodeValue()).append("?>"); 240 break; 241 } 242 247 case Node.CDATA_SECTION_NODE: 248 case Node.TEXT_NODE: { 249 buf.append(StringUtil.XMLEncNQG(n.getNodeValue())); 250 break; 251 } 252 } 253 } 254 255 void outputContent(NodeList nodes, StringBuffer buf) { 256 for(int i = 0; i < nodes.getLength(); ++i) { 257 outputContent(nodes.item(i), buf); 258 } 259 } 260 261 void outputContent(NamedNodeMap nodes, StringBuffer buf) { 262 for(int i = 0; i < nodes.getLength(); ++i) { 263 Node n = nodes.item(i); 264 if (n.getNodeType() != Node.ATTRIBUTE_NODE 265 || (!n.getNodeName().startsWith("xmlns:") && !n.getNodeName().equals("xmlns"))) 266 { 267 outputContent(n, buf); 268 } 269 } 270 } 271 272 String getOpeningTag(Element element) { 273 StringBuffer buf = new StringBuffer (); 274 buf.append('<'); 275 outputQualifiedName(element, buf); 276 buf.append(namespaceDecl); 277 outputContent(element.getAttributes(), buf); 278 buf.append('>'); 279 return buf.toString(); 280 } 281 282 String getClosingTag(Element element) { 283 StringBuffer buf = new StringBuffer (); 284 buf.append("</"); 285 outputQualifiedName(element, buf); 286 buf.append('>'); 287 return buf.toString(); 288 } 289 } 290
| Popular Tags
|