1 18 19 package org.apache.tools.ant.util; 20 21 import java.io.IOException ; 22 import java.io.OutputStream ; 23 import java.io.OutputStreamWriter ; 24 import java.io.Writer ; 25 import java.util.ArrayList ; 26 import java.util.HashMap ; 27 import java.util.Iterator ; 28 import org.w3c.dom.Attr ; 29 import org.w3c.dom.Element ; 30 import org.w3c.dom.NamedNodeMap ; 31 import org.w3c.dom.Node ; 32 import org.w3c.dom.NodeList ; 33 import org.w3c.dom.Text ; 34 35 44 public class DOMElementWriter { 45 46 47 private static final String NS = "ns"; 48 49 50 private boolean xmlDeclaration = true; 51 52 55 private XmlNamespacePolicy namespacePolicy = XmlNamespacePolicy.IGNORE; 56 57 60 private HashMap nsPrefixMap = new HashMap (); 61 62 65 private int nextPrefix = 0; 66 67 70 private HashMap nsURIByElement = new HashMap (); 71 72 77 public static class XmlNamespacePolicy { 78 private boolean qualifyElements; 79 private boolean qualifyAttributes; 80 81 84 public static final XmlNamespacePolicy IGNORE = 85 new XmlNamespacePolicy(false, false); 86 87 90 public static final XmlNamespacePolicy ONLY_QUALIFY_ELEMENTS = 91 new XmlNamespacePolicy(true, false); 92 93 96 public static final XmlNamespacePolicy QUALIFY_ALL = 97 new XmlNamespacePolicy(true, true); 98 99 103 public XmlNamespacePolicy(boolean qualifyElements, 104 boolean qualifyAttributes) { 105 this.qualifyElements = qualifyElements; 106 this.qualifyAttributes = qualifyAttributes; 107 } 108 } 109 110 114 public DOMElementWriter() { 115 } 116 117 124 public DOMElementWriter(boolean xmlDeclaration) { 125 this(xmlDeclaration, XmlNamespacePolicy.IGNORE); 126 } 127 128 136 public DOMElementWriter(boolean xmlDeclaration, 137 XmlNamespacePolicy namespacePolicy) { 138 this.xmlDeclaration = xmlDeclaration; 139 this.namespacePolicy = namespacePolicy; 140 } 141 142 private static String lSep = System.getProperty("line.separator"); 143 144 149 protected String [] knownEntities = {"gt", "amp", "lt", "apos", "quot"}; 150 152 153 162 public void write(Element root, OutputStream out) throws IOException { 163 Writer wri = new OutputStreamWriter (out, "UTF8"); 164 writeXMLDeclaration(wri); 165 write(root, wri, 0, " "); 166 wri.flush(); 167 } 168 169 175 public void writeXMLDeclaration(Writer wri) throws IOException { 176 if (xmlDeclaration) { 177 wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 178 } 179 } 180 181 191 public void write(Element element, Writer out, int indent, 192 String indentWith) 193 throws IOException { 194 195 NodeList children = element.getChildNodes(); 197 boolean hasChildren = (children.getLength() > 0); 198 boolean hasChildElements = false; 199 openElement(element, out, indent, indentWith, hasChildren); 200 201 if (hasChildren) { 202 for (int i = 0; i < children.getLength(); i++) { 203 Node child = children.item(i); 204 205 switch (child.getNodeType()) { 206 207 case Node.ELEMENT_NODE: 208 hasChildElements = true; 209 if (i == 0) { 210 out.write(lSep); 211 } 212 write((Element ) child, out, indent + 1, indentWith); 213 break; 214 215 case Node.TEXT_NODE: 216 out.write(encode(child.getNodeValue())); 217 break; 218 219 case Node.COMMENT_NODE: 220 out.write("<!--"); 221 out.write(encode(child.getNodeValue())); 222 out.write("-->"); 223 break; 224 225 case Node.CDATA_SECTION_NODE: 226 out.write("<![CDATA["); 227 out.write(encodedata(((Text ) child).getData())); 228 out.write("]]>"); 229 break; 230 231 case Node.ENTITY_REFERENCE_NODE: 232 out.write('&'); 233 out.write(child.getNodeName()); 234 out.write(';'); 235 break; 236 237 case Node.PROCESSING_INSTRUCTION_NODE: 238 out.write("<?"); 239 out.write(child.getNodeName()); 240 String data = child.getNodeValue(); 241 if (data != null && data.length() > 0) { 242 out.write(' '); 243 out.write(data); 244 } 245 out.write("?>"); 246 break; 247 default: 248 } 250 } 251 closeElement(element, out, indent, indentWith, hasChildElements); 252 } 253 } 254 255 266 public void openElement(Element element, Writer out, int indent, 267 String indentWith) 268 throws IOException { 269 openElement(element, out, indent, indentWith, true); 270 } 271 272 285 public void openElement(Element element, Writer out, int indent, 286 String indentWith, boolean hasChildren) 287 throws IOException { 288 for (int i = 0; i < indent; i++) { 290 out.write(indentWith); 291 } 292 293 out.write("<"); 295 if (namespacePolicy.qualifyElements) { 296 String uri = getNamespaceURI(element); 297 String prefix = (String ) nsPrefixMap.get(uri); 298 if (prefix == null) { 299 if (nsPrefixMap.isEmpty()) { 300 prefix = ""; 302 } else { 303 prefix = NS + (nextPrefix++); 304 } 305 nsPrefixMap.put(uri, prefix); 306 addNSDefinition(element, uri); 307 } 308 if (!"".equals(prefix)) { 309 out.write(prefix); 310 out.write(":"); 311 } 312 } 313 out.write(element.getTagName()); 314 315 NamedNodeMap attrs = element.getAttributes(); 317 for (int i = 0; i < attrs.getLength(); i++) { 318 Attr attr = (Attr ) attrs.item(i); 319 out.write(" "); 320 if (namespacePolicy.qualifyAttributes) { 321 String uri = getNamespaceURI(attr); 322 String prefix = (String ) nsPrefixMap.get(uri); 323 if (prefix == null) { 324 prefix = NS + (nextPrefix++); 325 nsPrefixMap.put(uri, prefix); 326 addNSDefinition(element, uri); 327 } 328 out.write(prefix); 329 out.write(":"); 330 } 331 out.write(attr.getName()); 332 out.write("=\""); 333 out.write(encode(attr.getValue())); 334 out.write("\""); 335 } 336 337 ArrayList al = (ArrayList ) nsURIByElement.get(element); 339 if (al != null) { 340 Iterator iter = al.iterator(); 341 while (iter.hasNext()) { 342 String uri = (String ) iter.next(); 343 String prefix = (String ) nsPrefixMap.get(uri); 344 out.write(" xmlns"); 345 if (!"".equals(prefix)) { 346 out.write(":"); 347 out.write(prefix); 348 } 349 out.write("=\""); 350 out.write(uri); 351 out.write("\""); 352 } 353 } 354 355 if (hasChildren) { 356 out.write(">"); 357 } else { 358 removeNSDefinitions(element); 359 out.write(" />"); 360 out.write(lSep); 361 out.flush(); 362 } 363 } 364 365 376 public void closeElement(Element element, Writer out, int indent, 377 String indentWith, boolean hasChildren) 378 throws IOException { 379 if (hasChildren) { 383 for (int i = 0; i < indent; i++) { 384 out.write(indentWith); 385 } 386 } 387 388 out.write("</"); 390 if (namespacePolicy.qualifyElements) { 391 String uri = getNamespaceURI(element); 392 String prefix = (String ) nsPrefixMap.get(uri); 393 if (prefix != null && !"".equals(prefix)) { 394 out.write(prefix); 395 out.write(":"); 396 } 397 removeNSDefinitions(element); 398 } 399 out.write(element.getTagName()); 400 out.write(">"); 401 out.write(lSep); 402 out.flush(); 403 } 404 405 411 public String encode(String value) { 412 StringBuffer sb = new StringBuffer (); 413 int len = value.length(); 414 for (int i = 0; i < len; i++) { 415 char c = value.charAt(i); 416 switch (c) { 417 case '<': 418 sb.append("<"); 419 break; 420 case '>': 421 sb.append(">"); 422 break; 423 case '\'': 424 sb.append("'"); 425 break; 426 case '\"': 427 sb.append("""); 428 break; 429 case '&': 430 int nextSemi = value.indexOf(";", i); 431 if (nextSemi < 0 432 || !isReference(value.substring(i, nextSemi + 1))) { 433 sb.append("&"); 434 } else { 435 sb.append('&'); 436 } 437 break; 438 default: 439 if (isLegalCharacter(c)) { 440 sb.append(c); 441 } 442 break; 443 } 444 } 445 return sb.substring(0); 446 } 447 448 464 public String encodedata(final String value) { 465 StringBuffer sb = new StringBuffer (); 466 int len = value.length(); 467 for (int i = 0; i < len; ++i) { 468 char c = value.charAt(i); 469 if (isLegalCharacter(c)) { 470 sb.append(c); 471 } 472 } 473 474 String result = sb.substring(0); 475 int cdEnd = result.indexOf("]]>"); 476 while (cdEnd != -1) { 477 sb.setLength(cdEnd); 478 sb.append("]]>") 479 .append(result.substring(cdEnd + 3)); 480 result = sb.substring(0); 481 cdEnd = result.indexOf("]]>"); 482 } 483 484 return result; 485 } 486 487 492 public boolean isReference(String ent) { 493 if (!(ent.charAt(0) == '&') || !ent.endsWith(";")) { 494 return false; 495 } 496 497 if (ent.charAt(1) == '#') { 498 if (ent.charAt(2) == 'x') { 499 try { 500 Integer.parseInt(ent.substring(3, ent.length() - 1), 16); 501 return true; 502 } catch (NumberFormatException nfe) { 503 return false; 504 } 505 } else { 506 try { 507 Integer.parseInt(ent.substring(2, ent.length() - 1)); 508 return true; 509 } catch (NumberFormatException nfe) { 510 return false; 511 } 512 } 513 } 514 515 String name = ent.substring(1, ent.length() - 1); 516 for (int i = 0; i < knownEntities.length; i++) { 517 if (name.equals(knownEntities[i])) { 518 return true; 519 } 520 } 521 return false; 522 } 523 524 534 public boolean isLegalCharacter(char c) { 535 if (c == 0x9 || c == 0xA || c == 0xD) { 536 return true; 537 } else if (c < 0x20) { 538 return false; 539 } else if (c <= 0xD7FF) { 540 return true; 541 } else if (c < 0xE000) { 542 return false; 543 } else if (c <= 0xFFFD) { 544 return true; 545 } 546 return false; 547 } 548 549 private void removeNSDefinitions(Element element) { 550 ArrayList al = (ArrayList ) nsURIByElement.get(element); 551 if (al != null) { 552 Iterator iter = al.iterator(); 553 while (iter.hasNext()) { 554 nsPrefixMap.remove(iter.next()); 555 } 556 nsURIByElement.remove(element); 557 } 558 } 559 560 private void addNSDefinition(Element element, String uri) { 561 ArrayList al = (ArrayList ) nsURIByElement.get(element); 562 if (al == null) { 563 al = new ArrayList (); 564 nsURIByElement.put(element, al); 565 } 566 al.add(uri); 567 } 568 569 private static String getNamespaceURI(Node n) { 570 String uri = n.getNamespaceURI(); 571 if (uri == null) { 572 uri = ""; 574 } 575 return uri; 576 } 577 } 578 | Popular Tags |