| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.catalina.util; |
| |
| import java.io.PrintWriter; |
| import java.io.Writer; |
| |
| import org.apache.tomcat.util.security.Escape; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| |
| /** |
| * A DOM writer optimised for use by WebDAV. |
| */ |
| public class DOMWriter { |
| |
| private final PrintWriter out; |
| |
| |
| public DOMWriter(Writer writer) { |
| out = new PrintWriter(writer); |
| } |
| |
| |
| /** |
| * Prints the specified node, recursively. |
| * |
| * @param node The node to output |
| */ |
| public void print(Node node) { |
| |
| // is there anything to do? |
| if (node == null) { |
| return; |
| } |
| |
| int type = node.getNodeType(); |
| switch (type) { |
| // print document |
| case Node.DOCUMENT_NODE: |
| print(((Document) node).getDocumentElement()); |
| out.flush(); |
| break; |
| |
| // print element with attributes |
| case Node.ELEMENT_NODE: |
| out.print('<'); |
| out.print(node.getLocalName()); |
| Attr[] attrs = sortAttributes(node.getAttributes()); |
| boolean xmlns = false; |
| for (Attr attr : attrs) { |
| if ("xmlns".equals(attr.getPrefix())) { |
| // Skip namespace prefixes as they are removed |
| continue; |
| } |
| out.print(' '); |
| out.print(attr.getLocalName()); |
| if ("xmlns".equals(attr.getLocalName())) { |
| xmlns = true; |
| } |
| out.print("=\""); |
| out.print(Escape.xml("", true, attr.getNodeValue())); |
| out.print('"'); |
| } |
| if (!xmlns && node.getNamespaceURI() != null) { |
| out.print(" xmlns=\""); |
| out.print(Escape.xml(node.getNamespaceURI())); |
| out.print('"'); |
| } |
| out.print('>'); |
| printChildren(node); |
| break; |
| |
| // handle entity reference nodes |
| case Node.ENTITY_REFERENCE_NODE: |
| printChildren(node); |
| break; |
| |
| // print cdata sections |
| case Node.CDATA_SECTION_NODE: |
| out.print(Escape.xml("", true, node.getNodeValue())); |
| break; |
| |
| // print text |
| case Node.TEXT_NODE: |
| out.print(Escape.xml("", false, node.getNodeValue())); |
| break; |
| |
| // print processing instruction |
| case Node.PROCESSING_INSTRUCTION_NODE: |
| out.print("<?"); |
| out.print(node.getLocalName()); |
| |
| String data = node.getNodeValue(); |
| if (data != null && !data.isEmpty()) { |
| out.print(' '); |
| out.print(data); |
| } |
| out.print("?>"); |
| break; |
| } |
| |
| if (type == Node.ELEMENT_NODE) { |
| out.print("</"); |
| out.print(node.getLocalName()); |
| out.print('>'); |
| } |
| |
| out.flush(); |
| |
| } // print(Node) |
| |
| |
| private void printChildren(Node node) { |
| NodeList children = node.getChildNodes(); |
| if (children != null) { |
| int len = children.getLength(); |
| for (int i = 0; i < len; i++) { |
| print(children.item(i)); |
| } |
| } |
| } |
| |
| |
| /** |
| * Returns a sorted list of attributes. |
| * |
| * @param attrs The map to sort |
| * |
| * @return a sorted attribute array |
| */ |
| private Attr[] sortAttributes(NamedNodeMap attrs) { |
| if (attrs == null) { |
| return new Attr[0]; |
| } |
| |
| int len = attrs.getLength(); |
| Attr[] array = new Attr[len]; |
| for (int i = 0; i < len; i++) { |
| array[i] = (Attr) attrs.item(i); |
| } |
| for (int i = 0; i < len - 1; i++) { |
| String name = array[i].getLocalName(); |
| int index = i; |
| for (int j = i + 1; j < len; j++) { |
| String curName = array[j].getLocalName(); |
| if (curName.compareTo(name) < 0) { |
| name = curName; |
| index = j; |
| } |
| } |
| if (index != i) { |
| Attr temp = array[i]; |
| array[i] = array[index]; |
| array[index] = temp; |
| } |
| } |
| |
| return array; |
| } |
| } |