View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.wss4j.common.util;
21  
22  import org.w3c.dom.Attr;
23  import org.w3c.dom.Element;
24  import org.w3c.dom.NamedNodeMap;
25  import org.w3c.dom.Node;
26  
27  import java.io.PrintWriter;
28  import java.io.StringWriter;
29  import java.io.Writer;
30  
31  /**
32   * This class is a utility to serialize a DOM node as XML. This class
33   * uses the <code>DOM Level 2</code> APIs.
34   * The main difference between this class and DOMWriter is that this class
35   * generates and prints out namespace declarations.
36   */
37  public final class DOM2Writer {
38      public static final char NL = '\n';
39      public static final String LS = System.getProperty("line.separator",
40              Character.valueOf(NL).toString());
41  
42      private DOM2Writer() {
43          // Complete
44      }
45  
46      /**
47       * Return a string containing this node serialized as XML.
48       */
49      public static String nodeToString(Node node) {
50          StringWriter sw = new StringWriter();
51          serializeAsXML(node, sw, true);
52          return sw.toString();
53      }
54  
55      /**
56       * Return a string containing this node serialized as XML.
57       */
58      public static String nodeToString(Node node, boolean omitXMLDecl) {
59          StringWriter sw = new StringWriter();
60          serializeAsXML(node, sw, omitXMLDecl);
61          return sw.toString();
62      }
63  
64      /**
65       * Serialize this node into the writer as XML.
66       */
67      public static void serializeAsXML(Node node, Writer writer,
68                                        boolean omitXMLDecl) {
69          serializeAsXML(node, writer, omitXMLDecl, false);
70      }
71  
72      /**
73       * Serialize this node into the writer as XML.
74       */
75      public static void serializeAsXML(Node node, Writer writer,
76                                        boolean omitXMLDecl,
77                                        boolean pretty) {
78          PrintWriter out = new PrintWriter(writer);
79          if (!omitXMLDecl) {
80              out.print("<?xml version=\"1.0\" encoding=UTF-8 ?>");
81          }
82          NSStack namespaceStack = new NSStack();
83          print(node, namespaceStack, out, pretty, 0);
84          out.flush();
85      }
86  
87      private static void print(Node node, NSStack namespaceStack,
88                                PrintWriter out, boolean pretty,
89                                int indent) {
90          if (node == null) {
91              return;
92          }
93          boolean hasChildren = false;
94          int type = node.getNodeType();
95          switch (type) {
96              case Node.DOCUMENT_NODE:
97                  Node child = node.getFirstChild();
98                  while (child != null) {
99                      print(child, namespaceStack, out, pretty, indent);
100                     child = child.getNextSibling();
101                 }
102                 break;
103             case Node.ELEMENT_NODE:
104                 namespaceStack.push();
105                 if (pretty) {
106                     for (int i = 0; i < indent; i++) {
107                         out.print(' ');
108                     }
109                 }
110                 out.print('<' + node.getNodeName());
111                 String elPrefix = node.getPrefix();
112                 String elNamespaceURI = node.getNamespaceURI();
113                 if (elPrefix != null && elNamespaceURI != null && elPrefix.length() > 0) {
114                     boolean prefixIsDeclared = false;
115                     try {
116                         String namespaceURI = namespaceStack.getNamespaceURI(elPrefix);
117                         if (elNamespaceURI.equals(namespaceURI)) {
118                             prefixIsDeclared = true;
119                         }
120                     } catch (IllegalArgumentException e) { //NOPMD
121                         //
122                     }
123                     if (!prefixIsDeclared) {
124                         printNamespaceDecl(node, namespaceStack, out);
125                     }
126                 }
127                 NamedNodeMap attrs = node.getAttributes();
128                 int len = (attrs != null) ? attrs.getLength() : 0;
129                 for (int i = 0; i < len; i++) {
130                     Attr attr = (Attr) attrs.item(i);
131                     out.print(' ' + attr.getNodeName() + "=\"");
132                     normalize(attr.getValue(), out);
133                     out.print('\"');
134                     String attrPrefix = attr.getPrefix();
135                     String attrNamespaceURI = attr.getNamespaceURI();
136                     if (attrPrefix != null && attrNamespaceURI != null) {
137                         boolean prefixIsDeclared = false;
138                         try {
139                             String namespaceURI = namespaceStack.getNamespaceURI(attrPrefix);
140                             if (attrNamespaceURI.equals(namespaceURI)) {
141                                 prefixIsDeclared = true;
142                             }
143                         } catch (IllegalArgumentException e) { //NOPMD
144                             //
145                         }
146                         if (!prefixIsDeclared) {
147                             printNamespaceDecl(attr, namespaceStack, out);
148                         }
149                     }
150                 }
151                 child = node.getFirstChild();
152                 if (child != null) {
153                     hasChildren = true;
154                     out.print('>');
155                     if (pretty) {
156                         out.print(LS);
157                     }
158                     while (child != null) {
159                         print(child, namespaceStack, out, pretty, indent + 1);
160                         child = child.getNextSibling();
161                     }
162                 } else {
163                     hasChildren = false;
164                     out.print("/>");
165                     if (pretty) {
166                         out.print(LS);
167                     }
168                 }
169                 namespaceStack.pop();
170                 break;
171             case Node.ENTITY_REFERENCE_NODE:
172                 out.print('&');
173                 out.print(node.getNodeName());
174                 out.print(';');
175                 break;
176             case Node.CDATA_SECTION_NODE:
177                 out.print("<![CDATA[");
178                 out.print(node.getNodeValue());
179                 out.print("]]>");
180                 break;
181             case Node.TEXT_NODE:
182                 normalize(node.getNodeValue(), out);
183                 break;
184             case Node.COMMENT_NODE:
185                 out.print("<!--");
186                 out.print(node.getNodeValue());
187                 out.print("-->");
188                 if (pretty) {
189                     out.print(LS);
190                 }
191                 break;
192             case Node.PROCESSING_INSTRUCTION_NODE:
193                 out.print("<?");
194                 out.print(node.getNodeName());
195                 String data = node.getNodeValue();
196                 if (data != null && data.length() > 0) {
197                     out.print(' ');
198                     out.print(data);
199                 }
200                 out.println("?>");
201                 if (pretty) {
202                     out.print(LS);
203                 }
204                 break;
205         }
206         if (type == Node.ELEMENT_NODE && hasChildren) {
207             if (pretty) {
208                 for (int i = 0; i < indent; i++) {
209                     out.print(' ');
210                 }
211             }
212             out.print("</");
213             out.print(node.getNodeName());
214             out.print('>');
215             if (pretty) {
216                 out.print(LS);
217             }
218             hasChildren = false;
219         }
220     }
221 
222     private static void printNamespaceDecl(Node node,
223                                            NSStack namespaceStack,
224                                            PrintWriter out) {
225         switch (node.getNodeType()) {   //NOPMD
226             case Node.ATTRIBUTE_NODE:
227                 printNamespaceDecl(((Attr) node).getOwnerElement(), node,
228                                    namespaceStack, out);
229                 break;
230             case Node.ELEMENT_NODE:
231                 printNamespaceDecl((Element) node, node, namespaceStack, out);
232                 break;
233         }
234     }
235 
236     private static void printNamespaceDecl(Element owner, Node node,
237                                            NSStack namespaceStack,
238                                            PrintWriter out) {
239         String namespaceURI = node.getNamespaceURI();
240         String prefix = node.getPrefix();
241         if (!(namespaceURI.equals(XMLUtils.XMLNS_NS) && "xmlns".equals(prefix))
242             && !(namespaceURI.equals(XMLUtils.XML_NS) && "xml".equals(prefix))) {
243             if (XMLUtils.getNamespace(prefix, owner) == null) {
244                 out.print(" xmlns:" + prefix + "=\"" + namespaceURI + '\"');
245             }
246         } else {
247             prefix = node.getLocalName();
248             namespaceURI = node.getNodeValue();
249         }
250         namespaceStack.add(namespaceURI, prefix);
251     }
252 
253     /**
254      * Normalizes and prints the given string.
255      */
256     public static void normalize(String s, PrintWriter fOut) {
257         int len = (s != null) ? s.length() : 0;
258         for (int i = 0; i < len; i++) {
259             char c = s.charAt(i);
260             switch (c) {
261                 case '<':
262                     fOut.print("&lt;");
263                     break;
264                 case '>':
265                     fOut.print("&gt;");
266                     break;
267                 case '&':
268                     fOut.print("&amp;");
269                     break;
270                 case '"':
271                     fOut.print("&quot;");
272                     break;
273                 default:
274                     fOut.print(c);
275                     break;
276             }
277         }
278     }
279 }