1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.ws.security.util;
21
22 import org.apache.ws.security.WSConstants;
23 import org.w3c.dom.Attr;
24 import org.w3c.dom.Element;
25 import org.w3c.dom.NamedNodeMap;
26 import org.w3c.dom.Node;
27
28 import java.io.PrintWriter;
29 import java.io.StringWriter;
30 import java.io.Writer;
31
32
33
34
35
36
37
38
39
40
41 public final class DOM2Writer {
42 public static final char NL = '\n';
43 public static final String LS = System.getProperty("line.separator",
44 (Character.valueOf(NL)).toString());
45
46 private DOM2Writer() {
47
48 }
49
50
51
52
53 public static String nodeToString(Node node) {
54 StringWriter sw = new StringWriter();
55 serializeAsXML(node, sw, true);
56 return sw.toString();
57 }
58
59
60
61
62 public static String nodeToString(Node node, boolean omitXMLDecl) {
63 StringWriter sw = new StringWriter();
64 serializeAsXML(node, sw, omitXMLDecl);
65 return sw.toString();
66 }
67
68
69
70
71 public static void serializeAsXML(Node node, Writer writer,
72 boolean omitXMLDecl) {
73 serializeAsXML(node, writer, omitXMLDecl, false);
74 }
75
76
77
78
79 public static void serializeAsXML(Node node, Writer writer,
80 boolean omitXMLDecl,
81 boolean pretty) {
82 PrintWriter out = new PrintWriter(writer);
83 if (!omitXMLDecl) {
84 out.print("<?xml version=\"1.0\" encoding=UTF-8 ?>");
85 }
86 NSStack namespaceStack = new NSStack();
87 print(node, namespaceStack, out, pretty, 0);
88 out.flush();
89 }
90
91 private static void print(Node node, NSStack namespaceStack,
92 PrintWriter out, boolean pretty,
93 int indent) {
94 if (node == null) {
95 return;
96 }
97 boolean hasChildren = false;
98 int type = node.getNodeType();
99 switch (type) {
100 case Node.DOCUMENT_NODE:
101 {
102 Node child = node.getFirstChild();
103 while (child != null) {
104 print(child, namespaceStack, out, pretty, indent);
105 child = child.getNextSibling();
106 }
107 break;
108 }
109 case Node.ELEMENT_NODE:
110 {
111 namespaceStack.push();
112 if (pretty) {
113 for (int i = 0; i < indent; i++) {
114 out.print(' ');
115 }
116 }
117 out.print('<' + node.getNodeName());
118 String elPrefix = node.getPrefix();
119 String elNamespaceURI = node.getNamespaceURI();
120 if (elPrefix != null &&
121 elNamespaceURI != null &&
122 elPrefix.length() > 0) {
123 boolean prefixIsDeclared = false;
124 try {
125 String namespaceURI = namespaceStack.getNamespaceURI(elPrefix);
126 if (elNamespaceURI.equals(namespaceURI)) {
127 prefixIsDeclared = true;
128 }
129 } catch (IllegalArgumentException e) {
130
131 }
132 if (!prefixIsDeclared) {
133 printNamespaceDecl(node, namespaceStack, out);
134 }
135 }
136 NamedNodeMap attrs = node.getAttributes();
137 int len = (attrs != null) ? attrs.getLength() : 0;
138 for (int i = 0; i < len; i++) {
139 Attr attr = (Attr) attrs.item(i);
140 out.print(' ' + attr.getNodeName() + "=\"");
141 normalize(attr.getValue(), out);
142 out.print('\"');
143 String attrPrefix = attr.getPrefix();
144 String attrNamespaceURI = attr.getNamespaceURI();
145 if (attrPrefix != null && attrNamespaceURI != null) {
146 boolean prefixIsDeclared = false;
147 try {
148 String namespaceURI = namespaceStack.getNamespaceURI(attrPrefix);
149 if (attrNamespaceURI.equals(namespaceURI)) {
150 prefixIsDeclared = true;
151 }
152 } catch (IllegalArgumentException e) {
153
154 }
155 if (!prefixIsDeclared) {
156 printNamespaceDecl(attr, namespaceStack, out);
157 }
158 }
159 }
160 Node child = node.getFirstChild();
161 if (child != null) {
162 hasChildren = true;
163 out.print('>');
164 if (pretty) {
165 out.print(LS);
166 }
167 while (child != null) {
168 print(child, namespaceStack, out, pretty, indent + 1);
169 child = child.getNextSibling();
170 }
171 } else {
172 hasChildren = false;
173 out.print("/>");
174 if (pretty) {
175 out.print(LS);
176 }
177 }
178 namespaceStack.pop();
179 break;
180 }
181 case Node.ENTITY_REFERENCE_NODE:
182 {
183 out.print('&');
184 out.print(node.getNodeName());
185 out.print(';');
186 break;
187 }
188 case Node.CDATA_SECTION_NODE:
189 {
190 out.print("<![CDATA[");
191 out.print(node.getNodeValue());
192 out.print("]]>");
193 break;
194 }
195 case Node.TEXT_NODE:
196 {
197 normalize(node.getNodeValue(), out);
198 break;
199 }
200 case Node.COMMENT_NODE:
201 {
202 out.print("<!--");
203 out.print(node.getNodeValue());
204 out.print("-->");
205 if (pretty) {
206 out.print(LS);
207 }
208 break;
209 }
210 case Node.PROCESSING_INSTRUCTION_NODE:
211 {
212 out.print("<?");
213 out.print(node.getNodeName());
214 String data = node.getNodeValue();
215 if (data != null && data.length() > 0) {
216 out.print(' ');
217 out.print(data);
218 }
219 out.println("?>");
220 if (pretty) {
221 out.print(LS);
222 }
223 break;
224 }
225 }
226 if (type == Node.ELEMENT_NODE && hasChildren) {
227 if (pretty) {
228 for (int i = 0; i < indent; i++) {
229 out.print(' ');
230 }
231 }
232 out.print("</");
233 out.print(node.getNodeName());
234 out.print('>');
235 if (pretty) {
236 out.print(LS);
237 }
238 hasChildren = false;
239 }
240 }
241
242 private static void printNamespaceDecl(Node node,
243 NSStack namespaceStack,
244 PrintWriter out) {
245 switch (node.getNodeType()) {
246 case Node.ATTRIBUTE_NODE:
247 {
248 printNamespaceDecl(((Attr) node).getOwnerElement(), node,
249 namespaceStack, out);
250 break;
251 }
252 case Node.ELEMENT_NODE:
253 {
254 printNamespaceDecl((Element) node, node, namespaceStack, out);
255 break;
256 }
257 }
258 }
259
260 private static void printNamespaceDecl(Element owner, Node node,
261 NSStack namespaceStack,
262 PrintWriter out) {
263 String namespaceURI = node.getNamespaceURI();
264 String prefix = node.getPrefix();
265 if (!(namespaceURI.equals(WSConstants.XMLNS_NS) && prefix.equals("xmlns")) &&
266 !(namespaceURI.equals(WSConstants.XML_NS) && prefix.equals("xml"))) {
267 if (WSSecurityUtil.getNamespace(prefix, owner) == null) {
268 out.print(" xmlns:" + prefix + "=\"" + namespaceURI + '\"');
269 }
270 } else {
271 prefix = node.getLocalName();
272 namespaceURI = node.getNodeValue();
273 }
274 namespaceStack.add(namespaceURI, prefix);
275 }
276
277
278
279
280 public static void normalize(String s, PrintWriter fOut) {
281 int len = (s != null) ? s.length() : 0;
282 for (int i = 0; i < len; i++) {
283 char c = s.charAt(i);
284 switch (c) {
285 case '<':
286 {
287 fOut.print("<");
288 break;
289 }
290 case '>':
291 {
292 fOut.print(">");
293 break;
294 }
295 case '&':
296 {
297 fOut.print("&");
298 break;
299 }
300 case '"':
301 {
302 fOut.print(""");
303 break;
304 }
305 case '\r':
306 case '\n':
307 default:
308 {
309 fOut.print(c);
310 }
311 }
312 }
313 }
314 }