001/*******************************************************************************
002 * Copyright (C) 2009-2011 FuseSource Corp.
003 * Copyright (c) 2008 IBM Corporation and others.
004 *
005 * All rights reserved. This program and the accompanying materials
006 * are made available under the terms of the Eclipse Public License v1.0
007 * which accompanies this distribution, and is available at
008 * http://www.eclipse.org/legal/epl-v10.html
009 *
010 *******************************************************************************/
011package org.fusesource.hawtjni.generator;
012
013import java.io.PrintStream;
014import java.util.Arrays;
015import java.util.Comparator;
016
017import org.w3c.dom.Attr;
018import org.w3c.dom.Document;
019import org.w3c.dom.NamedNodeMap;
020import org.w3c.dom.Node;
021import org.w3c.dom.NodeList;
022
023/**
024 * 
025 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
026 */
027public class DOMWriter {
028
029        static String ENCONDING = "UTF8";
030        PrintStream out;
031        String[] attributeFilter;
032        String nodeFilter;
033
034        public DOMWriter(PrintStream out) {
035                this.out = new PrintStream(out);
036        }
037
038        String nodeName(Node node) {
039                // TODO use getLocalName()?
040                return node.getNodeName();
041        }
042        
043        boolean filter(Attr attr) {
044                if (attributeFilter == null) return false;
045                String name = attr.getNodeName();
046                for (int i = 0; i < attributeFilter.length; i++) {
047                        if (name.matches(attributeFilter[i])) return false;
048                }
049                return true;
050        }
051        
052        void print(String str) {
053                out.print(str);
054        }
055        void println() {
056                out.println();
057        }
058
059        public void print(Node node) {
060                print(node, 0);
061        }
062        
063        public void print(Node node, int level) {
064                if (node == null)
065                        return;
066                int type = node.getNodeType();
067                switch (type) {
068                        case Node.DOCUMENT_NODE: {
069                                print("<?xml version=\"1.0\" encoding=\"");
070                                print(ENCONDING);
071                                print("\"?>");
072                                println();
073                                print(((Document) node).getDocumentElement());
074                                break;
075                        }
076                        case Node.ELEMENT_NODE: {
077                                Attr attrs[] = sort(node.getAttributes());
078                                String name = nodeName(node);
079                                boolean gen = name.equals("arg") || name.equals("retval");
080                                for (int i = 0; i < attrs.length && !gen; i++) {
081                                        Attr attr = attrs[i];
082                                        if (nodeName(attr).startsWith(nodeFilter)) gen = true;
083                                }
084                                if (!gen) break;
085                                for (int i = 0; i < level; i++) print("\t");
086                                print("<");
087                                print(name);
088                                for (int i = 0; i < attrs.length; i++) {
089                                        Attr attr = attrs[i];
090                                        if (filter(attr)) continue;
091                                        print(" ");
092                                        print(nodeName(attr));
093                                        print("=\"");
094                                        print(normalize(attr.getNodeValue()));
095                                        print("\"");
096                                }
097                                print(">");
098                                NodeList children = node.getChildNodes();
099                                int count = 0;
100                                if (children != null) {
101                                        int len = children.getLength();
102                                        for (int i = 0; i < len; i++) {
103                                                if (children.item(i).getNodeType() == Node.ELEMENT_NODE) count++;
104                                        }
105                                        if (count > 0) println();
106                                        for (int i = 0; i < len; i++) {
107                                                print(children.item(i), level + 1);
108                                        }
109                                        if (count > 0) {
110                                                for (int i = 0; i < level; i++) print("\t");
111                                        }
112                                }
113                                print("</");
114                                print(nodeName(node));
115                                print(">");
116                                println();
117                                break;
118                        }
119                }
120                out.flush();
121        }
122
123        Attr[] sort(NamedNodeMap attrs) {
124                if (attrs == null)
125                        return new Attr[0];
126                Attr result[] = new Attr[attrs.getLength()];
127                for (int i = 0; i < result.length; i++) {
128                        result[i] = (Attr) attrs.item(i);
129                }
130                Arrays.sort(result, new Comparator<Node>() {
131                        public int compare(Node arg0, Node arg1) {
132                                return nodeName(arg0).compareTo(nodeName(arg1));
133                        }
134                });
135                return result;
136        }
137
138        String normalize(String s) {
139                if (s == null) return "";
140                StringBuffer str = new StringBuffer();
141                for (int i = 0, length = s.length(); i < length; i++) {
142                        char ch = s.charAt(i);
143                        switch (ch) {
144                                case '"': str.append("\""); break;
145                                case '\r':
146                                case '\n':
147                                        // FALL THROUGH
148                                default: str.append(ch);
149                        }
150                }
151                return str.toString();
152        }
153        
154        public void setNodeFilter(String filter) {
155                
156                nodeFilter = filter;
157        }
158        
159        public void setAttributeFilter(String[] filter) {
160                attributeFilter = filter;
161        }
162}