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     *******************************************************************************/
011    package org.fusesource.hawtjni.generator;
012    
013    import java.io.PrintStream;
014    import java.util.Arrays;
015    import java.util.Comparator;
016    
017    import org.w3c.dom.Attr;
018    import org.w3c.dom.Document;
019    import org.w3c.dom.NamedNodeMap;
020    import org.w3c.dom.Node;
021    import org.w3c.dom.NodeList;
022    
023    /**
024     * 
025     * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
026     */
027    public 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    }