This page describes XPath rule support in more details
This page describes some points of XPath rule support in more details. See also the tutorial about how to write an XPath rule.
XPath versionPMD uses XPath 3.1 for its XPath rules since PMD 7. Before then, the default version was XPath 1.0, with opt-in support for XPath 2.0.
See the Saxonica documentation for an introduction to new features in XPath 3.1.
The property version
of XPathRule is deprecated and will be removed.
XPath rules view the AST as an XML-like DOM, which is what the XPath language is defined on. Concretely, this means:
getXPathNodeName
for the given node@SimpleName
of the Java node EnumDeclaration
is backed by the Java getter getSimpleName
.To represent attributes, we must map Java values to XPath Data Model (XDM) values. In the following table we refer to the type conversion function as conv
, a function from Java types to XDM types.
T
XSD type conv(T)
int
xs:integer
long
xs:integer
double
xs:decimal
float
xs:decimal
boolean
xs:boolean
String
xs:string
Character
xs:string
Enum<E>
xs:string
(uses Object::toString
) List<E>
conv(E)*
(a sequence type)
The same conv
function is used to translate rule property values to XDM values.
Warning: Lists are only supported for rule properties, not attributes.
Migrating from 1.0 to 2.0XPath 1.0 and 2.0 have some incompatibilities. The XPath 2.0 specification describes them precisely. Those are however mostly corner cases and XPath rules usually donât feature any of them.
The incompatibilities that are most relevant to migrating your rules are not caused by the specification, but by the different engines we use to run XPath 1.0 and 2.0 queries. Hereâs a list of known incompatibilities:
fn:
and string:
should not be mentioned explicitly. In XPath 2.0 mode, the engine will complain about an undeclared namespace, but the functions are in the default namespace. Removing the namespace prefixes fixes it.
fn:substring("Foo", 1)
â substring("Foo", 1)
typeIs
must be prefixed with the namespace of the declaring module (pmd-java
).
typeIs("Foo")
â pmd-java:typeIs("Foo")
"true"
and "false"
. In 2.0 mode though, boolean values are truly represented as boolean values, which in XPath may only be obtained through the functions true()
and false()
. If your XPath 1.0 rule tests an attribute like @Private="true"
, then it just needs to be changed to @Private=true()
when migrating. A type error will warn you that you must update the comparison. More is explained on issue #1244.
"true"
, 'true'
â true()
"false"
, 'false'
â false()
@BeginLine > "1"
worked âthatâs not the case in 2.0 mode.
@ArgumentCount > '1'
â @ArgumentCount > 1
/Foo
matches the children of the root named Foo
. In XPath 2.0, that expression matches the root, if it is named Foo
. Consider the following tree:
Foo
ââ Foo
ââ Foo
Then /Foo
will match the root in XPath 2, and the other nodes (but not the root) in XPath 1. See eg an issue caused by this in Apex, with nested classes.
PMD provides some language-specific XPath functions to access semantic information from the AST.
On XPath 2.0, the namespace of custom PMD function must be explicitly mentioned.
All languagesFunctions available to all languages are in the namespace pmd
.
//b[pmd:fileName() = 'Foo.xml']
<b>
tags in files called Foo.xml
.
//b[pmd:startLine(.) > 5]
<b>
node which starts after the fifth line.
//b[pmd:endLine(.) == pmd:startLine(.)]
<b>
node which doesn't span more than one line.
//b[pmd:startColumn(.) = 1]
<b>
node which starts on the first column of a line
//b[pmd:startLine(.) = pmd:endLine(.) and pmd:endColumn(.) - pmd:startColumn(.) = 1]
<b>
node which spans exactly one character
Java functions are in the namespace pmd-java
.
5d
) has type ASTNumericLiteral, and this function will ignore the static type of the expression (double)
net.sourceforge.pmd.lang.java.ast
, without the 'AST' prefix
//*[pmd-java:nodeIs("Expression")]
ASTExpression
//*[pmd-java:nodeIs("AnyTypeDeclaration")]
ASTAnyTypeDeclaration
//*[pmd-java:nodeIs("Foo")]
5d
) has type ASTNumericLiteral, however this function will compare the type of the literal (eg here, double
) against the argument.
TypeNode
//FormalParameter[pmd-java:typeIs("java.lang.String[]")]
String[]
(including vararg parameters)
//VariableDeclaratorId[pmd-java:typeIs("java.lang.List")]
List
or any of its subtypes (including e.g. ArrayList
)
TypeNode
//VariableDeclaratorId[pmd-java:typeIsExactly("java.lang.List")]
List
(but not e.g. ArrayList
)
JavaMetrics
(or an alias thereof).
//ClassOrInterfaceDeclaration[metric('NCSS') > 200]
//MethodDeclaration[metric('CYCLO') > 10 and metric('NCSS') > 20]
//TypeParameter[metric('idontexist') > 50]
Annotatable
, otherwise this returns false
//MethodDeclaration[pmd-java:hasAnnotation("java.lang.Override")]
getEffectiveModifiers
.
AccessNode
, otherwise this returns an empty sequence
//MethodDeclaration[pmd-java:modifiers() = "native"]
//MethodDeclaration[pmd-java:modifiers() = ("native", "static")]
//MethodDeclaration[pmd-java:modifiers() = "public"]
explicitModifiers
function if you don't want the implicit part. Also note that @Visibility = 'public'
is a better use of the API, in this particular instance.
getExplicitModifiers
.
AccessNode
, otherwise this returns an empty sequence
//MethodDeclaration[pmd-java:explicitModifiers() = "public"]
TypeTestUtil.InvocationMatcher
to test the method signature called by the context node. The format of the parameter is described on that class.
InvocationNode
, otherwise this returns false
TypeTestUtil.InvocationMatcher
//MethodCall[pmd-java:matchesSig("_#equals(java.lang.Object)")]
equals
on any receiver type
//MethodCall[pmd-java:matchesSig("java.lang.Enum#equals(java.lang.Object)")]
equals
on receiver that is a subtype of Enum
//MethodCall[pmd-java:matchesSig("java.lang.String#toString()")]
toString
on String receivers
//MethodCall[pmd-java:matchesSig("_#_(int,int)")]
int
parameters (!= argument)
//ConstructorCall[pmd-java:matchesSig("java.util.ArrayList#new(int)")]
Note: There is also a typeOf
function which is deprecated and whose usages should be replaced with uses of typeIs
or typeIsExactly
. That one will be removed with PMD 7.0.0.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4