XPathRule.java
01 /**
02  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
03  */
04 package net.sourceforge.pmd.lang.rule;
05 
06 import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_1_0;
07 import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_1_0_COMPATIBILITY;
08 import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_2_0;
09 
10 import java.util.List;
11 
12 import net.sourceforge.pmd.RuleContext;
13 import net.sourceforge.pmd.lang.ast.Node;
14 import net.sourceforge.pmd.lang.rule.properties.EnumeratedProperty;
15 import net.sourceforge.pmd.lang.rule.properties.StringProperty;
16 import net.sourceforge.pmd.lang.rule.xpath.JaxenXPathRuleQuery;
17 import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery;
18 import net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery;
19 
20 /**
21  * Rule that tries to match an XPath expression against a DOM view of an AST.
22  <p/>
23  * This rule needs a property "xpath".
24  */
25 public class XPathRule extends AbstractRule {
26 
27     public static final StringProperty XPATH_DESCRIPTOR = new StringProperty("xpath""XPath expression"""1.0f);
28     public static final EnumeratedProperty<String> VERSION_DESCRIPTOR = new EnumeratedProperty<String>("version",
29       "XPath specification version"new String[] { XPATH_1_0, XPATH_1_0_COMPATIBILITY, XPATH_2_0 },
30       new String[] { XPATH_1_0, XPATH_1_0_COMPATIBILITY, XPATH_2_0 }02.0f);
31 
32     private XPathRuleQuery xpathRuleQuery;
33 
34     public XPathRule() {
35   definePropertyDescriptor(XPATH_DESCRIPTOR);
36   definePropertyDescriptor(VERSION_DESCRIPTOR);
37     }
38 
39     /**
40      * Apply the rule to all nodes.
41      */
42     public void apply(List<? extends Node> nodes, RuleContext ctx) {
43   for (Node node : nodes) {
44       evaluate(node, ctx);
45   }
46     }
47 
48     /**
49      * Evaluate the XPath query with the AST node.
50      * All matches are reported as violations.
51      *
52      @param node The Node that to be checked.
53      @param data The RuleContext.
54      */
55     public void evaluate(Node node, RuleContext data) {
56   init();
57   List<Node> nodes = xpathRuleQuery.evaluate(node, data);
58   if (nodes != null) {
59       for (Node n : nodes) {
60     addViolation(data, n, n.getImage());
61       }
62   }
63 
64     }
65 
66     @Override
67     public List<String> getRuleChainVisits() {
68   if (init()) {
69       for (String nodeName : xpathRuleQuery.getRuleChainVisits()) {
70     super.addRuleChainVisit(nodeName);
71       }
72   }
73   return super.getRuleChainVisits();
74     }
75 
76     private boolean init() {
77   if (xpathRuleQuery == null) {
78       String xpath = getProperty(XPATH_DESCRIPTOR);
79       String version = (StringgetProperty(VERSION_DESCRIPTOR);
80       if (XPATH_1_0.equals(version)) {
81     xpathRuleQuery = new JaxenXPathRuleQuery();
82       else {
83     xpathRuleQuery = new SaxonXPathRuleQuery();
84       }
85       xpathRuleQuery.setXPath(xpath);
86       xpathRuleQuery.setVersion(version);
87       xpathRuleQuery.setProperties(this.getPropertiesByPropertyDescriptor());
88       return true;
89   }
90   return false;
91     }
92 }