001: /*
002: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
003: *
004: * "The contents of this file are subject to the Mozilla Public License
005: * Version 1.1 (the "License"); you may not use this file except in
006: * compliance with the License. You may obtain a copy of the License at
007: * http://www.mozilla.org/MPL/
008: *
009: * Software distributed under the License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
011: * License for the specific language governing rights and limitations under
012: * the License.
013: *
014: * The Original Code is ICEfaces 1.5 open source software code, released
015: * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
016: * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
017: * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
018: *
019: * Contributor(s): _____________________.
020: *
021: * Alternatively, the contents of this file may be used under the terms of
022: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
023: * License), in which case the provisions of the LGPL License are
024: * applicable instead of those above. If you wish to allow use of your
025: * version of this file only under the terms of the LGPL License and not to
026: * allow others to use your version of this file under the MPL, indicate
027: * your decision by deleting the provisions above and replace them with
028: * the notice and other provisions required by the LGPL License. If you do
029: * not delete the provisions above, a recipient may use your version of
030: * this file under either the MPL or the LGPL License."
031: *
032: */
033:
034: package com.icesoft.faces.util;
035:
036: import org.w3c.dom.Attr;
037: import org.w3c.dom.CDATASection;
038: import org.w3c.dom.Comment;
039: import org.w3c.dom.Document;
040: import org.w3c.dom.Element;
041: import org.w3c.dom.Entity;
042: import org.w3c.dom.NamedNodeMap;
043: import org.w3c.dom.Node;
044: import org.w3c.dom.NodeList;
045: import org.w3c.dom.Text;
046:
047: import javax.faces.component.UIComponent;
048: import java.util.List;
049: import java.util.Vector;
050:
051: public class DOMUtils {
052: private static int DEFAULT_DOM_STRING_PRESIZE = 4096;
053: private static int DEFAULT_NODE_STRING_PRESIZE = 256;
054:
055: public static String DocumentTypetoString(String publicID,
056: String systemID, String root) {
057: return "<!DOCTYPE " + root + " PUBLIC \"" + publicID + "\" \""
058: + systemID + "\">";
059: }
060:
061: public static String DOMtoString(Document document) {
062: return printNode(document, new StringBuffer(
063: DEFAULT_DOM_STRING_PRESIZE));
064: }
065:
066: public static String nodeToString(Node node) {
067: return printNode(node, new StringBuffer(
068: DEFAULT_NODE_STRING_PRESIZE));
069: }
070:
071: public static String childrenToString(Node node) {
072: NodeList children = node.getChildNodes();
073: Node child;
074: StringBuffer stringbuffer = new StringBuffer(
075: DEFAULT_DOM_STRING_PRESIZE);
076: int l = children.getLength();
077: for (int i = 0; i < l; i++) {
078: child = children.item(i);
079: stringbuffer.append(nodeToString(child));
080: }
081: return stringbuffer.toString();
082: }
083:
084: private static String printNode(Node node, StringBuffer stringbuffer) {
085: printNode(node, stringbuffer, 0, true, false);
086: return stringbuffer.toString();
087: }
088:
089: private static void printNode(Node node, StringBuffer stringbuffer,
090: int depth, boolean allowAddingWhitespace,
091: boolean addTrailingNewline) {
092:
093: switch (node.getNodeType()) {
094:
095: case Node.DOCUMENT_NODE:
096: //stringbuffer.append("<xml version=\"1.0\">\n");
097: // recurse on each child
098: NodeList nodes = node.getChildNodes();
099: if (nodes != null) {
100: for (int i = 0; i < nodes.getLength(); i++) {
101: printNode(nodes.item(i), stringbuffer, depth + 1,
102: allowAddingWhitespace, false);
103: }
104: }
105: break;
106:
107: case Node.ELEMENT_NODE:
108: String name = node.getNodeName();
109: if (name.equalsIgnoreCase("br")) {
110: stringbuffer.append("<br>");
111: break;
112: }
113: stringbuffer.append("<");
114: stringbuffer.append(name);
115: NamedNodeMap attributes = node.getAttributes();
116: for (int i = 0; i < attributes.getLength(); i++) {
117: Node current = attributes.item(i);
118: stringbuffer.append(" ");
119: stringbuffer.append(current.getNodeName());
120: stringbuffer.append("=\"");
121: stringbuffer.append(escapeAnsi(current.getNodeValue()));
122: stringbuffer.append("\"");
123: }
124:
125: //recognize empty elements and close them
126: //Fine for XML, but confuses some browsers
127: /*
128: if ( !node.hasChildNodes() )
129: {
130: stringbuffer.append(" />\n");
131: break;
132: }
133: */
134:
135: stringbuffer.append(">");
136: // recurse on each child
137: NodeList children = node.getChildNodes();
138:
139: if (children != null) {
140: int childrenLength = children.getLength();
141: for (int i = 0; i < childrenLength; i++) {
142: boolean childAddTrailingNewline = false;
143: if (allowAddingWhitespace) {
144: if ((i + 1) < childrenLength) {
145: Node nextChild = children.item(i + 1);
146: // We don't add the newline if the next tag is a TD,
147: // because when rendering our tabbedPane, if there's
148: // any whitespace between the adjacent TDs, then
149: // Internet Explorer will add vertical spacing
150: // Also same for some other tags to avoid extra space (JIRA ICE-1351)
151: childAddTrailingNewline = !isWhitespaceText(nextChild)
152: && isNewlineAllowedTag(nextChild);
153: }
154: }
155: printNode(children.item(i), stringbuffer,
156: depth + 1, allowAddingWhitespace,
157: childAddTrailingNewline);
158: }
159: }
160:
161: stringbuffer.append("</");
162: stringbuffer.append(name);
163: stringbuffer.append(">");
164: if (allowAddingWhitespace && addTrailingNewline)
165: stringbuffer.append("\n");
166: break;
167:
168: case Node.TEXT_NODE:
169: stringbuffer.append(node.getNodeValue());
170: break;
171: }
172: }
173:
174: private static boolean isWhitespaceText(Node node) {
175: if (node.getNodeType() == Node.TEXT_NODE) {
176: String val = node.getNodeValue();
177: // Treat an empty string like whitespace
178: for (int i = val.length() - 1; i >= 0; i--) {
179: if (!Character.isWhitespace(val.charAt(i)))
180: return false;
181: }
182: return true;
183: }
184: return false;
185: }
186:
187: private static boolean isNewlineAllowedTag(Node node) {
188: String tags = "img, input, td";
189: short nodeType = node.getNodeType();
190: String nodeName = node.getNodeName().toLowerCase();
191: return !(nodeType == Node.ELEMENT_NODE && tags
192: .indexOf(nodeName) > -1);
193: }
194:
195: private static boolean isTD(Node node) {
196: if (node.getNodeType() == Node.ELEMENT_NODE) {
197: String name = node.getNodeName();
198: if (name != null && name.equalsIgnoreCase("td"))
199: return true;
200: }
201: return false;
202: }
203:
204: /* Return the first child of the given nodeName under the given node.
205: * @param node node to search under
206: * @param name nodeName to search for
207: */
208: public static Node getChildByNodeName(Node node, String name) {
209: NodeList children = node.getChildNodes();
210: Node child;
211: int l = children.getLength();
212: for (int i = 0; i < l; i++) {
213: child = children.item(i);
214: if (child.getNodeName().equalsIgnoreCase(name)) {
215: return child;
216: }
217: }
218: return null;
219: }
220:
221: /**
222: * Determine the set of top-level nodes in newDOM that are different from
223: * the corresponding nodes in oldDOM.
224: *
225: * @param oldDOM original dom Document
226: * @param newDOM changed dom Document
227: * @return array of top-level nodes in newDOM that differ from oldDOM
228: */
229: public static Node[] domDiff(Document oldDOM, Document newDOM) {
230: List nodeDiffs = new Vector();
231: compareNodes(nodeDiffs, oldDOM.getDocumentElement(), newDOM
232: .getDocumentElement());
233: return ((Node[]) nodeDiffs.toArray(new Node[0]));
234: }
235:
236: /**
237: * Nodes are equivalent if they have the same names, attributes, and
238: * children
239: *
240: * @param oldNode
241: * @param newNode
242: * @return true if oldNode and newNode are equivalent
243: */
244: public static boolean compareNodes(List nodeDiffs, Node oldNode,
245: Node newNode) {
246: if (!oldNode.getNodeName().equals(newNode.getNodeName())) {
247: //parent node needs to fix this
248: nodeDiffs.add(newNode.getParentNode());
249: return false;
250: }
251: if (!compareIDs(oldNode, newNode)) {
252: //parent node needs to fix this
253: nodeDiffs.add(newNode.getParentNode());
254: return false;
255: }
256: if (!compareAttributes(oldNode, newNode)) {
257: nodeDiffs.add(newNode);
258: return false;
259: }
260: if (!compareStrings(oldNode.getNodeValue(), newNode
261: .getNodeValue())) {
262: //might not have an id
263: nodeDiffs.add(newNode);
264: return false;
265: }
266:
267: NodeList oldChildNodes = oldNode.getChildNodes();
268: NodeList newChildNodes = newNode.getChildNodes();
269:
270: int oldChildLength = oldChildNodes.getLength();
271: int newChildLength = newChildNodes.getLength();
272:
273: if (oldChildLength != newChildLength) {
274: nodeDiffs.add(newNode);
275: return false;
276: }
277:
278: boolean allChildrenMatch = true;
279: for (int i = 0; i < newChildLength; i++) {
280: if (!compareNodes(nodeDiffs, oldChildNodes.item(i),
281: newChildNodes.item(i))) {
282: allChildrenMatch = false;
283: }
284: }
285:
286: return allChildrenMatch;
287: }
288:
289: private static boolean compareStrings(String oldString,
290: String newString) {
291: if ((null == oldString) && (null == newString)) {
292: return true;
293: }
294: try {
295: return (oldString.equals(newString));
296: } catch (NullPointerException e) {
297: }
298: return false;
299: }
300:
301: /**
302: * @param oldNode
303: * @param newNode
304: * @return true if Nodes have the same IDs
305: */
306: public static boolean compareIDs(Node oldNode, Node newNode) {
307: if (!(oldNode instanceof Element)
308: && !(newNode instanceof Element)) {
309: //both do not have an ID
310: return true;
311: }
312: try {
313: return ((Element) oldNode).getAttribute("id").equals(
314: ((Element) newNode).getAttribute("id"));
315: } catch (Exception e) {
316: }
317: return false;
318: }
319:
320: /**
321: * @param oldNode
322: * @param newNode
323: * @return true if Nodes have the same attributes
324: */
325: public static boolean compareAttributes(Node oldNode, Node newNode) {
326: boolean oldHasAttributes = oldNode.hasAttributes();
327: boolean newHasAttributes = newNode.hasAttributes();
328:
329: if (!oldHasAttributes && !newHasAttributes) {
330: return true;
331: }
332: if (oldHasAttributes != newHasAttributes) {
333: return false;
334: }
335:
336: NamedNodeMap oldMap = oldNode.getAttributes();
337: NamedNodeMap newMap = newNode.getAttributes();
338:
339: int oldLength = oldMap.getLength();
340: int newLength = newMap.getLength();
341:
342: if (oldLength != newLength) {
343: return false;
344: }
345:
346: Node newAttribute = null;
347: Node oldAttribute = null;
348: for (int i = 0; i < newLength; i++) {
349: newAttribute = newMap.item(i);
350: oldAttribute = oldMap.getNamedItem(newAttribute
351: .getNodeName());
352: if (null == oldAttribute) {
353: return false;
354: }
355: if (!(String.valueOf(oldAttribute.getNodeValue())
356: .equals(String.valueOf(newAttribute.getNodeValue())))) {
357: return false;
358: }
359: }
360:
361: return true;
362:
363: }
364:
365: public static Element ascendToNodeWithID(Node node) {
366: while (null != node) {
367: if (node instanceof Element) {
368: String id = ((Element) node).getAttribute("id");
369: if ((null != id) && (!"".equals(id))) {
370: return (Element) node;
371: }
372: }
373: node = node.getParentNode();
374: }
375: //it's going to be null at this point
376: return (Element) node;
377: }
378:
379: /**
380: * Escaping is required unless the escape attribute is present and is
381: * "false"
382: *
383: * @param uiComponent
384: * @param valueTextRequiresEscape
385: * @return
386: */
387: public static boolean escapeIsRequired(UIComponent uiComponent) {
388: Object escapeAttribute = uiComponent.getAttributes().get(
389: "escape");
390: if (escapeAttribute != null) {
391: if (escapeAttribute instanceof String) {
392: return Boolean.valueOf((String) escapeAttribute)
393: .booleanValue();
394: } else if (escapeAttribute instanceof Boolean) {
395: return ((Boolean) escapeAttribute).booleanValue();
396: }
397: }
398: return true; //default
399: }
400:
401: public static String escapeAnsi(String text) {
402: if (null == text) {
403: return "";
404: }
405: char[] chars = text.toCharArray();
406: StringBuffer buffer = new StringBuffer(chars.length);
407: for (int index = 0; index < chars.length; index++) {
408: char ch = chars[index];
409: //see: http://www.w3schools.com/tags/ref_ascii.asp
410: if (ch <= 31) {
411: if (ch == '\t' || ch == '\n' || ch == '\r') {
412: buffer.append(ch);
413: }
414: //skip any other control character
415: } else if (ch == 127) {
416: //skip 'escape' character
417: } else if (ch == '>') {
418: buffer.append(">");
419: } else if (ch == '<') {
420: buffer.append("<");
421: } else if (ch == '&') {
422: buffer.append("&");
423: } else if (ch == '\'') {
424: buffer.append("'");
425: } else if (ch == '"') {
426: buffer.append(""");
427: } else if (ch >= 0xA0 && ch <= 0xff) {
428: buffer.append("&" + escapeAnsi(ch) + ";");
429: } else if (ch == 0x20AC) {//special case for euro symbol
430: buffer.append("€");
431: } else {
432: buffer.append(ch);
433: }
434: }
435:
436: return buffer.toString();
437: }
438:
439: /**
440: * @param character
441: * @return
442: */
443: private static String escapeAnsi(char character) {
444: int indexOfEscapedCharacter = character - 0xA0;
445: return ansiCharacters[indexOfEscapedCharacter];
446: }
447:
448: /**
449: * from http://www.w3.org/TR/REC-html40/sgml/entities.html
450: * Portions Copyright International Organization for Standardization 1986
451: * Permission to copy in any form is granted for use with
452: * conforming SGML systems and applications as defined in
453: * ISO 8879, provided this notice is included in all copies.
454: */
455: private static String[] ansiCharacters = new String[] {
456: "nbsp"
457: /* " " -- no-break space = non-breaking space, U+00A0 ISOnum -->*/,
458: "iexcl" /* "¡" -- inverted exclamation mark, U+00A1 ISOnum */,
459: "cent" /* "¢" -- cent sign, U+00A2 ISOnum */,
460: "pound" /* "£" -- pound sign, U+00A3 ISOnum */,
461: "curren" /* "¤" -- currency sign, U+00A4 ISOnum */,
462: "yen" /* "¥" -- yen sign = yuan sign, U+00A5 ISOnum */,
463: "brvbar"
464: /* "¦" -- broken bar = broken vertical bar, U+00A6 ISOnum */,
465: "sect" /* "§" -- section sign, U+00A7 ISOnum */,
466: "uml"
467: /* "¨" -- diaeresis = spacing diaeresis, U+00A8 ISOdia */,
468: "copy" /* "©" -- copyright sign, U+00A9 ISOnum */,
469: "ordf"
470: /* "ª" -- feminine ordinal indicator, U+00AA ISOnum */,
471: "laquo"
472: /* "«" -- left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum */,
473: "not" /* "¬" -- not sign, U+00AC ISOnum */,
474: "shy"
475: /* "­" -- soft hyphen = discretionary hyphen, U+00AD ISOnum */,
476: "reg"
477: /* "®" -- registered sign = registered trade mark sign, U+00AE ISOnum */,
478: "macr"
479: /* "¯" -- macron = spacing macron = overline = APL overbar, U+00AF ISOdia */,
480: "deg" /* "°" -- degree sign, U+00B0 ISOnum */,
481: "plusmn"
482: /* "±" -- plus-minus sign = plus-or-minus sign, U+00B1 ISOnum */,
483: "sup2"
484: /* "²" -- superscript two = superscript digit two = squared, U+00B2 ISOnum */,
485: "sup3"
486: /* "³" -- superscript three = superscript digit three = cubed, U+00B3 ISOnum */,
487: "acute"
488: /* "´" -- acute accent = spacing acute, U+00B4 ISOdia */,
489: "micro" /* "µ" -- micro sign, U+00B5 ISOnum */,
490: "para"
491: /* "¶" -- pilcrow sign = paragraph sign, U+00B6 ISOnum */,
492: "middot"
493: /* "·" -- middle dot = Georgian comma = Greek middle dot, U+00B7 ISOnum */,
494: "cedil" /* "¸" -- cedilla = spacing cedilla, U+00B8 ISOdia */,
495: "sup1"
496: /* "¹" -- superscript one = superscript digit one, U+00B9 ISOnum */,
497: "ordm"
498: /* "º" -- masculine ordinal indicator, U+00BA ISOnum */,
499: "raquo"
500: /* "»" -- right-pointing double angle quotation mark = right pointing guillemet, U+00BB ISOnum */,
501: "frac14"
502: /* "¼" -- vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum --> */,
503: "frac12"
504: /* "½" -- vulgar fraction one half = fraction one half, U+00BD ISOnum */,
505: "frac34"
506: /* "¾" -- vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum */,
507: "iquest"
508: /* "¿" -- inverted question mark = turned question mark, U+00BF ISOnum */,
509: "Agrave"
510: /* "À" -- latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1 */,
511: "Aacute"
512: /* "Á" -- latin capital letter A with acute, U+00C1 ISOlat1 */,
513: "Acirc"
514: /* "Â" -- latin capital letter A with circumflex, U+00C2 ISOlat1 */,
515: "Atilde"
516: /* "Ã" -- latin capital letter A with tilde, U+00C3 ISOlat1 */,
517: "Auml"
518: /* "Ä" -- latin capital letter A with diaeresis, U+00C4 ISOlat1 */,
519: "Aring"
520: /* "Å" -- latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1 --> */,
521: "AElig"
522: /* "Æ" -- latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1 --> */,
523: "Ccedil"
524: /* "Ç" -- latin capital letter C with cedilla, U+00C7 ISOlat1 */,
525: "Egrave"
526: /* "È" -- latin capital letter E with grave, U+00C8 ISOlat1 */,
527: "Eacute"
528: /* "É" -- latin capital letter E with acute, U+00C9 ISOlat1 */,
529: "Ecirc"
530: /* "Ê" -- latin capital letter E with circumflex, U+00CA ISOlat1 */,
531: "Euml"
532: /* "Ë" -- latin capital letter E with diaeresis, U+00CB ISOlat1 */,
533: "Igrave"
534: /* "Ì" -- latin capital letter I with grave, U+00CC ISOlat1 */,
535: "Iacute"
536: /* "Í" -- latin capital letter I with acute, U+00CD ISOlat1 */,
537: "Icirc"
538: /* "Î" -- latin capital letter I with circumflex, U+00CE ISOlat1 */,
539: "Iuml"
540: /* "Ï" -- latin capital letter I with diaeresis, U+00CF ISOlat1 */,
541: "ETH" /* "Ð" -- latin capital letter ETH, U+00D0 ISOlat1 */,
542: "Ntilde"
543: /* "Ñ" -- latin capital letter N with tilde, U+00D1 ISOlat1 */,
544: "Ograve"
545: /* "Ò" -- latin capital letter O with grave, U+00D2 ISOlat1 */,
546: "Oacute"
547: /* "Ó" -- latin capital letter O with acute, U+00D3 ISOlat1 */,
548: "Ocirc"
549: /* "Ô" -- latin capital letter O with circumflex, U+00D4 ISOlat1 */,
550: "Otilde"
551: /* "Õ" -- latin capital letter O with tilde, U+00D5 ISOlat1 */,
552: "Ouml"
553: /* "Ö" -- latin capital letter O with diaeresis, U+00D6 ISOlat1 */,
554: "times" /* "×" -- multiplication sign, U+00D7 ISOnum */,
555: "Oslash"
556: /* "Ø" -- latin capital letter O with stroke = latin capital letter O slash, U+00D8 ISOlat1 */,
557: "Ugrave"
558: /* "Ù" -- latin capital letter U with grave, U+00D9 ISOlat1 */,
559: "Uacute"
560: /* "Ú" -- latin capital letter U with acute, U+00DA ISOlat1 */,
561: "Ucirc"
562: /* "Û" -- latin capital letter U with circumflex, U+00DB ISOlat1 */,
563: "Uuml"
564: /* "Ü" -- latin capital letter U with diaeresis, U+00DC ISOlat1 */,
565: "Yacute"
566: /* "Ý" -- latin capital letter Y with acute, U+00DD ISOlat1 */,
567: "THORN"
568: /* "Þ" -- latin capital letter THORN, U+00DE ISOlat1 */,
569: "szlig"
570: /* "ß" -- latin small letter sharp s = ess-zed, U+00DF ISOlat1 */,
571: "agrave"
572: /* "à" -- latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1 */,
573: "aacute"
574: /* "á" -- latin small letter a with acute, U+00E1 ISOlat1 */,
575: "acirc"
576: /* "â" -- latin small letter a with circumflex, U+00E2 ISOlat1 */,
577: "atilde"
578: /* "ã" -- latin small letter a with tilde, U+00E3 ISOlat1 */,
579: "auml"
580: /* "ä" -- latin small letter a with diaeresis, U+00E4 ISOlat1 */,
581: "aring"
582: /* "å" -- latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1 */,
583: "aelig"
584: /* "æ" -- latin small letter ae = latin small ligature ae, U+00E6 ISOlat1 */,
585: "ccedil"
586: /* "ç" -- latin small letter c with cedilla, U+00E7 ISOlat1 */,
587: "egrave"
588: /* "è" -- latin small letter e with grave, U+00E8 ISOlat1 */,
589: "eacute"
590: /* "é" -- latin small letter e with acute, U+00E9 ISOlat1 */,
591: "ecirc"
592: /* "ê" -- latin small letter e with circumflex, U+00EA ISOlat1 */,
593: "euml"
594: /* "ë" -- latin small letter e with diaeresis, U+00EB ISOlat1 */,
595: "igrave"
596: /* "ì" -- latin small letter i with grave, U+00EC ISOlat1 */,
597: "iacute"
598: /* "í" -- latin small letter i with acute, U+00ED ISOlat1 */,
599: "icirc"
600: /* "î" -- latin small letter i with circumflex, U+00EE ISOlat1 */,
601: "iuml"
602: /* "ï" -- latin small letter i with diaeresis, U+00EF ISOlat1 */,
603: "eth" /* "ð" -- latin small letter eth, U+00F0 ISOlat1 */,
604: "ntilde"
605: /* "ñ" -- latin small letter n with tilde, U+00F1 ISOlat1 */,
606: "ograve"
607: /* "ò" -- latin small letter o with grave, U+00F2 ISOlat1 */,
608: "oacute"
609: /* "ó" -- latin small letter o with acute, U+00F3 ISOlat1 */,
610: "ocirc"
611: /* "ô" -- latin small letter o with circumflex, U+00F4 ISOlat1 */,
612: "otilde"
613: /* "õ" -- latin small letter o with tilde, U+00F5 ISOlat1 */,
614: "ouml"
615: /* "ö" -- latin small letter o with diaeresis, U+00F6 ISOlat1 */,
616: "divide" /* "÷" -- division sign, U+00F7 ISOnum */,
617: "oslash"
618: /* "ø" -- latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1 */,
619: "ugrave"
620: /* "ù" -- latin small letter u with grave, U+00F9 ISOlat1 */,
621: "uacute"
622: /* "ú" -- latin small letter u with acute, U+00FA ISOlat1 */,
623: "ucirc"
624: /* "û" -- latin small letter u with circumflex, U+00FB ISOlat1 */,
625: "uuml"
626: /* "ü" -- latin small letter u with diaeresis, U+00FC ISOlat1 */,
627: "yacute"
628: /* "ý" -- latin small letter y with acute, U+00FD ISOlat1 */,
629: "thorn" /* "þ" -- latin small letter thorn,U+00FE ISOlat1 */,
630: "yuml"
631: /* "ÿ" -- latin small letter y with diaeresis, U+00FF ISOlat1 */, };
632:
633: public static String toDebugString(Node node) {
634: short type = node.getNodeType();
635: switch (type) {
636: case Node.ATTRIBUTE_NODE: {
637: Attr attr = (Attr) node;
638: return "attribute[name: " + attr.getName() + "; value: "
639: + attr.getValue() + "]";
640: }
641: case Node.ELEMENT_NODE: {
642: Element element = (Element) node;
643: StringBuffer buffer = new StringBuffer();
644: buffer.append("element[tag: ");
645: buffer.append(element.getTagName());
646: buffer.append("; attributes: ");
647: NamedNodeMap attributes = element.getAttributes();
648: for (int i = 0; i < attributes.getLength(); i++) {
649: Attr attr = (Attr) attributes.item(i);
650: buffer.append(attr.getName());
651: buffer.append("=");
652: buffer.append(attr.getValue());
653: buffer.append(' ');
654: }
655: buffer.append(']');
656:
657: return buffer.toString();
658: }
659: case Node.CDATA_SECTION_NODE: {
660: CDATASection cdataSection = (CDATASection) node;
661: return "cdata[" + cdataSection.getData() + "]";
662: }
663: case Node.TEXT_NODE: {
664: Text text = (Text) node;
665: return "text[" + text.getData() + "]";
666: }
667: case Node.COMMENT_NODE: {
668: Comment comment = (Comment) node;
669: return "comment[" + comment.getData() + "]";
670: }
671: case Node.ENTITY_NODE: {
672: Entity entity = (Entity) node;
673: return "entity[public: " + entity.getPublicId()
674: + "; system: " + entity.getSystemId() + "]";
675: }
676: default: {
677: return node.getNodeName();
678: }
679: }
680: }
681: }
|