1 /***
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.renderers;
5
6 import net.sourceforge.pmd.IRuleViolation;
7 import net.sourceforge.pmd.PMD;
8 import net.sourceforge.pmd.Report;
9 import net.sourceforge.pmd.util.StringUtil;
10
11 import java.io.IOException;
12 import java.io.Writer;
13 import java.text.SimpleDateFormat;
14 import java.util.Date;
15 import java.util.Iterator;
16
17 public class XMLRenderer extends AbstractRenderer {
18
19 public void render(Writer writer, Report report) throws IOException {
20
21 StringBuffer buf = new StringBuffer();
22 writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + PMD.EOL + createVersionAttr() + createTimestampAttr() + createTimeElapsedAttr(report) + '>' + PMD.EOL);
23 String filename = null;
24
25
26 for (Iterator i = report.iterator(); i.hasNext();) {
27 buf.setLength(0);
28 IRuleViolation rv = (IRuleViolation) i.next();
29 if (!rv.getFilename().equals(filename)) {
30 if (filename != null) {
31 buf.append("</file>").append(PMD.EOL);
32 }
33 filename = rv.getFilename();
34 buf.append("<file name=\"");
35 StringUtil.appendXmlEscaped(buf, filename);
36 buf.append("\">").append(PMD.EOL);
37 }
38
39 buf.append("<violation line=\"").append(rv.getBeginLine());
40 buf.append("\" rule=\"");
41 StringUtil.appendXmlEscaped(buf, rv.getRule().getName());
42 buf.append("\" ruleset=\"");
43 StringUtil.appendXmlEscaped(buf, rv.getRule().getRuleSetName());
44 buf.append('"');
45 maybeAdd("package", rv.getPackageName(), buf);
46 maybeAdd("class", rv.getClassName(), buf);
47 maybeAdd("method", rv.getMethodName(), buf);
48 maybeAdd("externalInfoUrl", rv.getRule().getExternalInfoUrl(), buf);
49 buf.append(" priority=\"");
50 buf.append(rv.getRule().getPriority());
51 buf.append("\">").append(PMD.EOL);
52 StringUtil.appendXmlEscaped(buf, rv.getDescription());
53
54 buf.append(PMD.EOL);
55 buf.append("</violation>");
56 buf.append(PMD.EOL);
57 writer.write(buf.toString());
58 }
59 if (filename != null) {
60 writer.write("</file>");
61 writer.write(PMD.EOL);
62 }
63
64
65 for (Iterator i = report.errors(); i.hasNext();) {
66 buf.setLength(0);
67 Report.ProcessingError pe = (Report.ProcessingError) i.next();
68 buf.append("<error ").append("filename=\"");
69 StringUtil.appendXmlEscaped(buf, pe.getFile());
70 buf.append("\" msg=\"");
71 StringUtil.appendXmlEscaped(buf, pe.getMsg());
72 buf.append("\"/>").append(PMD.EOL);
73 writer.write(buf.toString());
74 }
75
76
77 if (showSuppressedViolations) {
78 for (Iterator i = report.getSuppressedRuleViolations().iterator(); i.hasNext();) {
79 buf.setLength(0);
80 Report.SuppressedViolation suppressed = (Report.SuppressedViolation) i.next();
81 buf.append("<suppressedviolation ").append("filename=\"");
82 StringUtil.appendXmlEscaped(buf, suppressed.getRuleViolation().getFilename());
83 buf.append("\" suppressiontype=\"");
84 StringUtil.appendXmlEscaped(buf, suppressed.suppressedByNOPMD() ? "nopmd" : "annotation");
85 buf.append("\" msg=\"");
86 StringUtil.appendXmlEscaped(buf, suppressed.getRuleViolation().getDescription());
87 buf.append("\" usermsg=\"");
88 StringUtil.appendXmlEscaped(buf, suppressed.getUserMessage());
89 buf.append("\"/>").append(PMD.EOL);
90 writer.write(buf.toString());
91 }
92 }
93
94 writer.write("</pmd>");
95 }
96
97 private void maybeAdd(String attr, String value, StringBuffer buf) {
98 if (value != null && value.length() > 0) {
99 buf.append(' ').append(attr).append("=\"");
100 StringUtil.appendXmlEscaped(buf, value);
101 buf.append('"');
102 }
103 }
104
105 private String createVersionAttr() {
106 return "<pmd version=\"" + PMD.VERSION + "\"";
107 }
108
109 private String createTimestampAttr() {
110 return " timestamp=\"" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").format(new Date()) + "\"";
111 }
112
113 private String createTimeElapsedAttr(Report rpt) {
114 Report.ReadableDuration d = new Report.ReadableDuration(rpt.getElapsedTimeInMillis());
115 return " elapsedTime=\"" + d.getTime() + "\"";
116 }
117
118 }