1 56 package org.jboss.util.xml; 57 58 60 import java.io.OutputStream ; 61 import java.io.OutputStreamWriter ; 62 import java.io.PrintWriter ; 63 import java.io.StringWriter ; 64 import java.io.UnsupportedEncodingException ; 65 import java.io.Writer ; 66 import java.util.HashMap ; 67 import java.util.Iterator ; 68 import java.util.Map ; 69 70 import org.w3c.dom.Attr ; 71 import org.w3c.dom.Element ; 72 import org.w3c.dom.NamedNodeMap ; 73 import org.w3c.dom.Node ; 74 import org.w3c.dom.NodeList ; 75 76 83 public class DOMWriter 84 { 85 private PrintWriter out; 87 private boolean canonical; 89 private boolean prettyprint; 91 private boolean writeXMLDeclaration; 93 private String charsetName; 95 private int prettyIndent; 97 private boolean wroteXMLDeclaration; 99 private Node rootNode; 101 private boolean completeNamespaces = true; 103 104 public DOMWriter(Writer w) 105 { 106 this.out = new PrintWriter (w); 107 } 108 109 public DOMWriter(Writer w, String charsetName) 110 { 111 this.out = new PrintWriter (w); 112 this.charsetName = charsetName; 113 this.writeXMLDeclaration = true; 114 } 115 116 public DOMWriter(OutputStream stream) 117 { 118 try 119 { 120 this.out = new PrintWriter (new OutputStreamWriter (stream, "UTF-8")); 121 } 122 catch (UnsupportedEncodingException e) 123 { 124 } 126 } 127 128 public DOMWriter(OutputStream stream, String charsetName) 129 { 130 try 131 { 132 this.out = new PrintWriter (new OutputStreamWriter (stream, charsetName)); 133 this.charsetName = charsetName; 134 this.writeXMLDeclaration = true; 135 } 136 catch (UnsupportedEncodingException e) 137 { 138 throw new IllegalArgumentException ("Unsupported encoding: " + charsetName); 139 } 140 } 141 142 147 public static String printNode(Node node, boolean prettyprint) 148 { 149 StringWriter strw = new StringWriter (); 150 new DOMWriter(strw).setPrettyprint(prettyprint).print(node); 151 return strw.toString(); 152 } 153 154 public boolean isCanonical() 155 { 156 return canonical; 157 } 158 159 163 public DOMWriter setCanonical(boolean canonical) 164 { 165 this.canonical = canonical; 166 return this; 167 } 168 169 174 public DOMWriter setCompleteNamespaces(boolean complete) 175 { 176 this.completeNamespaces = complete; 177 return this; 178 } 179 180 public boolean isPrettyprint() 181 { 182 return prettyprint; 183 } 184 185 189 public DOMWriter setPrettyprint(boolean prettyprint) 190 { 191 this.prettyprint = prettyprint; 192 return this; 193 } 194 195 public boolean isWriteXMLDeclaration() 196 { 197 return writeXMLDeclaration; 198 } 199 200 204 public DOMWriter setWriteXMLDeclaration(boolean flag) 205 { 206 this.writeXMLDeclaration = flag; 207 return this; 208 } 209 210 public void print(Node node) 211 { 212 rootNode = node; 213 printInternal(node, false); 214 } 215 216 private void printInternal(Node node, boolean indentEndMarker) 217 { 218 if (node == null) 220 { 221 return; 222 } 223 224 227 if (wroteXMLDeclaration == false && writeXMLDeclaration == true && canonical == false) 228 { 229 out.print("<?xml version='1.0'"); 230 if (charsetName != null) 231 out.print(" encoding='" + charsetName + "'"); 232 233 out.print("?>"); 234 if (prettyprint) 235 out.println(); 236 237 wroteXMLDeclaration = true; 238 } 239 240 int type = node.getNodeType(); 241 boolean hasChildNodes = node.getChildNodes().getLength() > 0; 242 243 String nodeName = node.getNodeName(); 244 switch (type) 245 { 246 case Node.DOCUMENT_NODE: 248 { 249 NodeList children = node.getChildNodes(); 250 for (int iChild = 0; iChild < children.getLength(); iChild++) 251 { 252 printInternal(children.item(iChild), false); 253 } 254 out.flush(); 255 break; 256 } 257 258 case Node.ELEMENT_NODE: 260 { 261 Element element = (Element )node; 262 if (prettyprint) 263 { 264 for (int i = 0; i < prettyIndent; i++) 265 { 266 out.print(' '); 267 } 268 prettyIndent++; 269 } 270 271 out.print('<'); 272 out.print(nodeName); 273 274 Map nsMap = new HashMap (); 275 String elPrefix = node.getPrefix(); 276 if (elPrefix != null) 277 { 278 String nsURI = getNamespaceURI(elPrefix, element, rootNode); 279 nsMap.put(elPrefix, nsURI); 280 } 281 282 Attr attrs[] = sortAttributes(node.getAttributes()); 283 for (int i = 0; i < attrs.length; i++) 284 { 285 Attr attr = attrs[i]; 286 String atPrefix = attr.getPrefix(); 287 String atName = attr.getNodeName(); 288 String atValue = normalize(attr.getNodeValue(), canonical); 289 290 if (atPrefix != null && (atPrefix.equals("xmlns") || atPrefix.equals("xml")) == false) 291 { 292 String nsURI = getNamespaceURI(atPrefix, element, rootNode); 293 nsMap.put(atPrefix, nsURI); 294 } 295 296 out.print(" " + atName + "='" + atValue + "'"); 297 } 298 299 if (completeNamespaces) 301 { 302 Iterator itPrefix = nsMap.keySet().iterator(); 303 while (itPrefix.hasNext()) 304 { 305 String prefix = (String )itPrefix.next(); 306 String nsURI = (String )nsMap.get(prefix); 307 if (nsURI == null) 308 { 309 nsURI = getNamespaceURI(prefix, element, null); 310 out.print(" xmlns:" + prefix + "='" + nsURI + "'"); 311 } 312 } 313 } 314 315 if (hasChildNodes) 316 { 317 out.print('>'); 318 } 319 320 indentEndMarker = isEndMarkerIndented(node); 322 323 if (indentEndMarker) 324 { 325 out.print('\n'); 326 } 327 328 NodeList childNodes = node.getChildNodes(); 329 int len = childNodes.getLength(); 330 for (int i = 0; i < len; i++) 331 { 332 Node childNode = childNodes.item(i); 333 printInternal(childNode, false); 334 } 335 break; 336 } 337 338 case Node.ENTITY_REFERENCE_NODE: 340 { 341 if (canonical) 342 { 343 NodeList children = node.getChildNodes(); 344 if (children != null) 345 { 346 int len = children.getLength(); 347 for (int i = 0; i < len; i++) 348 { 349 printInternal(children.item(i), false); 350 } 351 } 352 } 353 else 354 { 355 out.print('&'); 356 out.print(nodeName); 357 out.print(';'); 358 } 359 break; 360 } 361 362 case Node.CDATA_SECTION_NODE: 364 { 365 if (canonical) 366 { 367 out.print(normalize(node.getNodeValue(), canonical)); 368 } 369 else 370 { 371 out.print("<![CDATA["); 372 out.print(node.getNodeValue()); 373 out.print("]]>"); 374 } 375 break; 376 } 377 378 case Node.TEXT_NODE: 380 { 381 String text = normalize(node.getNodeValue(), canonical); 382 if (prettyprint == false || text.trim().length() > 0) 383 out.print(text); 384 break; 385 } 386 387 case Node.PROCESSING_INSTRUCTION_NODE: 389 { 390 out.print("<?"); 391 out.print(nodeName); 392 String data = node.getNodeValue(); 393 if (data != null && data.length() > 0) 394 { 395 out.print(' '); 396 out.print(data); 397 } 398 out.print("?>"); 399 break; 400 } 401 402 case Node.COMMENT_NODE: 404 { 405 for (int i = 0; i < prettyIndent; i++) 406 { 407 out.print(' '); 408 } 409 410 out.print("<!--"); 411 String data = node.getNodeValue(); 412 if (data != null) 413 { 414 out.print(data); 415 } 416 out.print("-->"); 417 418 if (prettyprint) 419 { 420 out.print('\n'); 421 } 422 423 break; 424 } 425 } 426 427 if (type == Node.ELEMENT_NODE) 428 { 429 if (prettyprint) 430 prettyIndent--; 431 432 if (hasChildNodes == false) 433 { 434 out.print("/>"); 435 } 436 else 437 { 438 if (indentEndMarker) 439 { 440 for (int i = 0; i < prettyIndent; i++) 441 { 442 out.print(' '); 443 } 444 } 445 446 out.print("</"); 447 out.print(nodeName); 448 out.print('>'); 449 } 450 451 if (prettyIndent > 0) 452 { 453 out.print('\n'); 454 } 455 } 456 out.flush(); 457 } 458 459 private String getNamespaceURI(String prefix, Element element, Node stopNode) 460 { 461 Node parent = element.getParentNode(); 462 String nsURI = element.getAttribute("xmlns:" + prefix); 463 if (nsURI.length() == 0 && element != stopNode && parent instanceof Element ) 464 return getNamespaceURI(prefix, (Element )parent, stopNode); 465 466 return (nsURI.length() > 0 ? nsURI : null); 467 } 468 469 private boolean isEndMarkerIndented(Node node) 470 { 471 if (prettyprint) 472 { 473 NodeList childNodes = node.getChildNodes(); 474 int len = childNodes.getLength(); 475 for (int i = 0; i < len; i++) 476 { 477 Node children = childNodes.item(i); 478 if (children.getNodeType() == Node.ELEMENT_NODE) 479 { 480 return true; 481 } 482 } 483 } 484 return false; 485 } 486 487 488 private Attr [] sortAttributes(NamedNodeMap attrs) 489 { 490 491 int len = (attrs != null) ? attrs.getLength() : 0; 492 Attr array[] = new Attr [len]; 493 for (int i = 0; i < len; i++) 494 { 495 array[i] = (Attr )attrs.item(i); 496 } 497 for (int i = 0; i < len - 1; i++) 498 { 499 String name = array[i].getNodeName(); 500 int index = i; 501 for (int j = i + 1; j < len; j++) 502 { 503 String curName = array[j].getNodeName(); 504 if (curName.compareTo(name) < 0) 505 { 506 name = curName; 507 index = j; 508 } 509 } 510 if (index != i) 511 { 512 Attr temp = array[i]; 513 array[i] = array[index]; 514 array[index] = temp; 515 } 516 } 517 return (array); 518 } 519 520 521 public static String normalize(String s, boolean canonical) 522 { 523 StringBuffer str = new StringBuffer (); 524 525 int len = (s != null) ? s.length() : 0; 526 for (int i = 0; i < len; i++) 527 { 528 char ch = s.charAt(i); 529 switch (ch) 530 { 531 case '<': 532 { 533 str.append("<"); 534 break; 535 } 536 case '>': 537 { 538 str.append(">"); 539 break; 540 } 541 case '&': 542 { 543 str.append("&"); 544 break; 545 } 546 case '"': 547 { 548 str.append("""); 549 break; 550 } 551 case '\r': 552 case '\n': 553 { 554 if (canonical) 555 { 556 str.append("&#"); 557 str.append(Integer.toString(ch)); 558 str.append(';'); 559 break; 560 } 561 } 563 default: 564 { 565 str.append(ch); 566 } 567 } 568 } 569 return (str.toString()); 570 } 571 } 572 | Popular Tags |