Simplified parsing for double quoted strings
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.quantum.sql / src / com / quantum / util / xml / XMLRenderer.java
1 package com.quantum.util.xml;
2
3 import org.w3c.dom.Attr;
4 import org.w3c.dom.NamedNodeMap;
5 import org.w3c.dom.Node;
6 import org.w3c.dom.NodeList;
7
8 /**
9  * @author BC Holmes
10  */
11 public class XMLRenderer {
12
13     protected boolean insertNewLine = false;
14     protected int numberOfTabs;
15
16     protected final static String LINE_SEPARATOR = System
17             .getProperty("line.separator");
18
19     protected final static String INDENT_STRING = "\t";
20
21     /** Returns a sorted list of attributes. */
22     protected Attr[] sortAttributes(NamedNodeMap attrs) {
23
24         int len = (attrs != null) ? attrs.getLength() : 0;
25         Attr array[] = new Attr[len];
26         for (int i = 0; i < len; i++) {
27             array[i] = (Attr) attrs.item(i);
28         }
29         for (int i = 0; i < len - 1; i++) {
30             String name = array[i].getNodeName();
31             int index = i;
32             for (int j = i + 1; j < len; j++) {
33                 String curName = array[j].getNodeName();
34                 if (curName.compareTo(name) < 0) {
35                     name = curName;
36                     index = j;
37                 }
38             }
39             if (index != i) {
40                 Attr temp = array[i];
41                 array[i] = array[index];
42                 array[index] = temp;
43             }
44         }
45
46         return (array);
47
48     }
49
50     protected XMLRenderer() {
51         this.numberOfTabs = 0;
52         this.insertNewLine = true;
53     }
54
55     protected void newLine(StringBuffer buffer) {
56         if (this.insertNewLine) {
57             buffer.append(LINE_SEPARATOR);
58             for (int i = 0; i < this.numberOfTabs; i++) {
59                 buffer.append(INDENT_STRING);
60             }
61         }
62     }
63
64     /** Prints the specified node, recursively. */
65     protected void print(Node node, StringBuffer buffer) {
66         // is there anything to do?
67         if (node != null) {
68             int type = node.getNodeType();
69             switch (type) {
70
71             case Node.DOCUMENT_NODE:
72                 printDocumentNode(node, buffer);
73                 break;
74
75             // print element with attributes
76             case Node.ELEMENT_NODE:
77                 printElementNode(node, buffer);
78                 break;
79             // handle entity reference nodes
80             case Node.ENTITY_REFERENCE_NODE:
81                 printEntityReferenceNode(node, buffer);
82                 break;
83
84             // print cdata sections
85             case Node.CDATA_SECTION_NODE:
86                 printCDataSectionNode(node, buffer);
87                 break;
88
89             // print text
90             case Node.TEXT_NODE:
91                 printTextNode(node, buffer);
92                 break;
93
94             // print processing instruction
95             case Node.PROCESSING_INSTRUCTION_NODE:
96                 printProcessingInstructionNode(node, buffer);
97                 break;
98             }
99         }
100     }
101
102     protected void printProcessingInstructionNode(Node node, StringBuffer buffer) {
103         buffer.append("<?");
104         buffer.append(node.getNodeName());
105         String data = node.getNodeValue();
106         if (data != null && data.length() > 0) {
107             buffer.append(' ');
108             buffer.append(data);
109         }
110         buffer.append("?>");
111     }
112
113     protected void printTextNode(Node node, StringBuffer buffer) {
114         printString(node.getNodeValue(), buffer);
115         this.insertNewLine = false;
116     }
117
118     protected void printCDataSectionNode(Node node, StringBuffer buffer) {
119         buffer.append("<![CDATA[");
120         buffer.append(node.getNodeValue());
121         buffer.append("]]>");
122     }
123
124     protected void printEntityReferenceNode(Node node, StringBuffer buffer) {
125         buffer.append('&');
126         buffer.append(node.getNodeName());
127         buffer.append(';');
128     }
129
130     protected void printElementNode(Node node, StringBuffer buffer) {
131         newLine(buffer);
132         this.numberOfTabs++;
133         buffer.append('<');
134         buffer.append(node.getNodeName());
135         Attr attrs[] = sortAttributes(node.getAttributes());
136         for (int i = 0; i < attrs.length; i++) {
137             Attr attr = attrs[i];
138             buffer.append(' ');
139             buffer.append(attr.getNodeName());
140             buffer.append("=\"");
141             printString(attr.getNodeValue(), buffer);
142             buffer.append('"');
143         }
144
145         if (!node.hasChildNodes()) {
146             buffer.append(" />");
147             this.numberOfTabs--;
148         } else {
149             buffer.append(">");
150             printAllChildNodes(node, buffer);
151             this.numberOfTabs--;
152             newLine(buffer);
153
154             buffer.append("</");
155             buffer.append(node.getNodeName());
156             buffer.append(">");
157         }
158         this.insertNewLine = true;
159     }
160
161     protected void printDocumentNode(Node node, StringBuffer buffer) {
162         buffer.append("<?xml version=\"1.0\" ?>");
163
164         printAllChildNodes(node, buffer);
165     }
166
167     protected void printAllChildNodes(Node node, StringBuffer buffer) {
168         NodeList children = node.getChildNodes();
169         for (int i = 0; i < children.getLength(); i++) {
170             print(children.item(i), buffer);
171         }
172     }
173
174     /** Normalizes the given string. */
175     protected void printString(String s, StringBuffer buffer) {
176
177         int len = (s != null) ? s.length() : 0;
178         for (int i = 0; i < len; i++) {
179             char ch = s.charAt(i);
180             switch (ch) {
181             case '<': {
182                 buffer.append("&lt;");
183                 break;
184             }
185             case '>': {
186                 buffer.append("&gt;");
187                 break;
188             }
189             case '&': {
190                 buffer.append("&amp;");
191                 break;
192             }
193             case '"':
194                 buffer.append("&quot;");
195                 break;
196             case '\r':
197             case '\n':
198             default: {
199                 buffer.append(ch);
200             }
201             }
202         }
203     }
204
205     public static String render(Node node) {
206         XMLRenderer renderer = new XMLRenderer();
207         StringBuffer buffer = new StringBuffer();
208         renderer.print(node, buffer);
209
210         return buffer.toString();
211     }
212
213     /**
214      * <p>
215      * Renders a String in a format that it would appear in a text node. That is
216      * to say, special characters (such as &amp;) are converted into entity
217      * references (&amp;amp;).
218      */
219     public static String render(String string) {
220         XMLRenderer renderer = new XMLRenderer();
221         StringBuffer buffer = new StringBuffer();
222         renderer.printString(string, buffer);
223         return buffer.toString();
224     }
225 }