View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.cpd;
5   
6   import java.io.StringWriter;
7   import java.util.Iterator;
8   
9   import javax.xml.parsers.DocumentBuilder;
10  import javax.xml.parsers.DocumentBuilderFactory;
11  import javax.xml.parsers.ParserConfigurationException;
12  import javax.xml.transform.OutputKeys;
13  import javax.xml.transform.Transformer;
14  import javax.xml.transform.TransformerException;
15  import javax.xml.transform.TransformerFactory;
16  import javax.xml.transform.dom.DOMSource;
17  import javax.xml.transform.stream.StreamResult;
18  
19  import org.w3c.dom.Document;
20  import org.w3c.dom.Element;
21  
22  /**
23   * @author Philippe T'Seyen - original implementation
24   * @author Romain Pelisse - javax.xml implementation 
25   * 
26   */
27  public final class XMLRenderer implements Renderer {
28  
29  	private final String encoding;
30  
31  	/**
32  	 * Creates a XML Renderer with the default (platform dependent) encoding.
33  	 */
34  	public XMLRenderer() {
35  		this(System.getProperty("file.encoding"));
36  	}
37  
38  	/**
39  	 * Creates a XML Renderer with a specific output encoding.
40  	 * @param encoding the encoding to use
41  	 */
42  	public XMLRenderer(String encoding) {
43  		this.encoding = encoding;
44  	}
45  
46  	private Document createDocument() {
47      	try {
48  			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
49  			DocumentBuilder parser = factory.newDocumentBuilder();
50  			return parser.newDocument();
51  		} catch (ParserConfigurationException e) {
52  			throw new IllegalStateException(e);
53  		}
54  	}
55  	
56  	private String xmlDocToString(Document doc) {
57          try {
58  	        TransformerFactory tf = TransformerFactory.newInstance();
59  	        Transformer transformer = tf.newTransformer();
60  	        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
61  	        transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
62  	        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
63  	        transformer.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, "codefragment");
64  	        StringWriter writer = new StringWriter();
65  	        transformer.transform(new DOMSource(doc), new StreamResult(writer));
66  	        return writer.getBuffer().toString();
67          }  catch (TransformerException e) {
68          	throw new IllegalStateException(e);
69  		}
70  	}
71  	
72      public String render(Iterator<Match> matches) {
73      	Document doc = createDocument();
74  		Element root = doc.createElement("pmd-cpd");
75  		doc.appendChild(root);
76  
77          Match match;
78          while (matches.hasNext()) {
79              match = matches.next();
80              root.appendChild( addCodeSnippet(doc, addFilesToDuplicationElement(doc, createDuplicationElement(doc, match), match), match ) );
81          }
82          return xmlDocToString(doc);
83      }
84      
85      private Element addFilesToDuplicationElement(Document doc, Element duplication, Match match) {
86      	TokenEntry mark;
87          for (Iterator<TokenEntry> iterator = match.iterator(); iterator.hasNext();) {
88              mark = iterator.next();
89              Element file = doc.createElement("file");
90              file.setAttribute("line", String.valueOf(mark.getBeginLine()));
91              file.setAttribute("path", mark.getTokenSrcID());
92              duplication.appendChild(file);
93          }
94          return duplication;
95      }
96  
97      private Element addCodeSnippet(Document doc, Element duplication, Match match) {
98          String codeSnipet = match.getSourceCodeSlice();
99          if (codeSnipet != null) {
100         	Element codefragment = doc.createElement("codefragment");
101             codefragment.appendChild(doc.createCDATASection(codeSnipet));
102             duplication.appendChild(codefragment);
103         }
104         return duplication;
105     }
106     
107     private Element createDuplicationElement(Document doc, Match match) {
108         Element duplication = doc.createElement("duplication");
109         duplication.setAttribute("lines", String.valueOf(match.getLineCount()));
110         duplication.setAttribute("tokens", String.valueOf(match.getTokenCount()));
111         return duplication;
112     }
113 }