1
2
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
24
25
26
27 public final class XMLRenderer implements Renderer {
28
29 private String encoding;
30
31
32
33
34 public XMLRenderer() {
35 this(null);
36 }
37
38
39
40
41
42
43
44 public XMLRenderer(String encoding) {
45 setEncoding(encoding);
46 }
47
48 public void setEncoding(String encoding) {
49 if (encoding != null) {
50 this.encoding = encoding;
51 } else {
52 this.encoding = System.getProperty("file.encoding");
53 }
54 }
55
56 public String getEncoding() {
57 return this.encoding;
58 }
59
60 private Document createDocument() {
61 try {
62 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
63 DocumentBuilder parser = factory.newDocumentBuilder();
64 return parser.newDocument();
65 } catch (ParserConfigurationException e) {
66 throw new IllegalStateException(e);
67 }
68 }
69
70 private String xmlDocToString(Document doc) {
71 try {
72 TransformerFactory tf = TransformerFactory.newInstance();
73 Transformer transformer = tf.newTransformer();
74 transformer.setOutputProperty(OutputKeys.METHOD, "xml");
75 transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
76 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
77 transformer.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, "codefragment");
78 StringWriter writer = new StringWriter();
79 transformer.transform(new DOMSource(doc), new StreamResult(writer));
80 return writer.getBuffer().toString();
81 } catch (TransformerException e) {
82 throw new IllegalStateException(e);
83 }
84 }
85
86 public String render(Iterator<Match> matches) {
87 Document doc = createDocument();
88 Element root = doc.createElement("pmd-cpd");
89 doc.appendChild(root);
90
91 Match match;
92 while (matches.hasNext()) {
93 match = matches.next();
94 root.appendChild(addCodeSnippet(doc,
95 addFilesToDuplicationElement(doc, createDuplicationElement(doc, match), match), match));
96 }
97 return xmlDocToString(doc);
98 }
99
100 private Element addFilesToDuplicationElement(Document doc, Element duplication, Match match) {
101 Mark mark;
102 for (Iterator<Mark> iterator = match.iterator(); iterator.hasNext();) {
103 mark = iterator.next();
104 Element file = doc.createElement("file");
105 file.setAttribute("line", String.valueOf(mark.getBeginLine()));
106 file.setAttribute("path", mark.getFilename());
107 duplication.appendChild(file);
108 }
109 return duplication;
110 }
111
112 private Element addCodeSnippet(Document doc, Element duplication, Match match) {
113 String codeSnipet = match.getSourceCodeSlice();
114 if (codeSnipet != null) {
115 Element codefragment = doc.createElement("codefragment");
116 codefragment.appendChild(doc.createCDATASection(codeSnipet));
117 duplication.appendChild(codefragment);
118 }
119 return duplication;
120 }
121
122 private Element createDuplicationElement(Document doc, Match match) {
123 Element duplication = doc.createElement("duplication");
124 duplication.setAttribute("lines", String.valueOf(match.getLineCount()));
125 duplication.setAttribute("tokens", String.valueOf(match.getTokenCount()));
126 return duplication;
127 }
128 }