pmd/pmd_userdocs_extending_writing_xpath_rules.html

2425 lines
77 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="This page describes XPath rule support in more details">
<meta name="keywords" content="extendinguserdocs, ">
<title>Writing XPath rules | PMD Source Code Analyzer</title>
<link rel="stylesheet" href="css/syntax.css">
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<!--<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">-->
<link rel="stylesheet" href="css/modern-business.css">
<link rel="stylesheet" href="css/lavish-bootstrap.css">
<link rel="stylesheet" href="css/customstyles.css">
<link rel="stylesheet" href="css/theme-blue.css">
<link rel="stylesheet" href="css/pmd-customstyles.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="js/jquery.navgoco.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/anchor-js/2.0.0/anchor.min.js"></script>
<script src="js/toc.js"></script>
<script src="js/customscripts.js"></script>
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon">
<link rel="icon" href="images/favicon.ico" type="image/x-icon">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<link rel="alternate" type="application/rss+xml" title="" href="https://pmd.github.io/pmd/feed.xml">
<script>
$(document).ready(function() {
// Initialize navgoco with default options
$("#mysidebar").navgoco({
caretHtml: '',
accordion: true,
openClass: 'active', // open
save: false, // leave false or nav highlighting doesn't work right
cookie: {
name: 'navgoco',
expires: false,
path: '/'
},
slide: {
duration: 400,
easing: 'swing'
}
});
$("#collapseAll").click(function(e) {
e.preventDefault();
$("#mysidebar").navgoco('toggle', false);
});
$("#expandAll").click(function(e) {
e.preventDefault();
$("#mysidebar").navgoco('toggle', true);
});
});
</script>
<script>
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
</script>
<script>
$(document).ready(function() {
$("#tg-sb-link").click(function() {
$("#tg-sb-sidebar").toggle();
$("#tg-sb-content").toggleClass('col-md-9');
$("#tg-sb-content").toggleClass('col-md-12');
$("#tg-sb-icon").toggleClass('fa-toggle-on');
$("#tg-sb-icon").toggleClass('fa-toggle-off');
});
});
</script>
</head>
<body>
<!-- Content is offset by the height of the topnav bar. -->
<!-- There's already a padding-top rule in modern-business.css, but it apparently doesn't work on Firefox 60 and Chrome 67 -->
<div id="topbar-content-offset">
<!-- Navigation -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container topnavlinks">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="fa fa-home fa-lg navbar-brand" href="index.html">&nbsp;<span class="projectTitle"> PMD Source Code Analyzer Project</span></a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<!-- toggle sidebar button -->
<li><a id="tg-sb-link" href="#"><i id="tg-sb-icon" class="fa fa-toggle-on"></i> Nav</a></li>
<!-- entries without drop-downs appear here -->
<li><a href="https://github.com/pmd/pmd/releases/latest" target="_blank">Download</a></li>
<li><a href="https://github.com/pmd/pmd" target="_blank">Fork us on github</a></li>
<!-- entries with drop-downs appear here -->
<!-- conditional logic to control which topnav appears for the audience defined in the configuration file.-->
<!--comment out this block if you want to hide search-->
<li>
<!--start search-->
<div id="search-demo-container">
<input type="text" id="search-input" placeholder="search...">
<ul id="results-container"></ul>
</div>
<script src="js/jekyll-search.js" type="text/javascript"></script>
<script type="text/javascript">
SimpleJekyllSearch.init({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
dataSource: 'search.json',
searchResultTemplate: '<li><a href="{url}" title="Writing XPath rules">{title}</a></li>',
noResultsText: 'No results found.',
limit: 10,
fuzzy: true,
})
</script>
<!--end search-->
</li>
</ul>
</div>
</div>
<!-- /.container -->
</nav>
<!-- Page Content -->
<div class="container-toc-wrapper">
<div class="container">
<div class="col-lg-12">&nbsp;</div>
<!-- Content Row -->
<div class="row">
<!-- Sidebar Column -->
<div class="col-md-3" id="tg-sb-sidebar">
<ul id="mysidebar" class="nav">
<li class="sidebarTitle">PMD 6.50.0-SNAPSHOT</li>
<div class="sidebarTitleDate">Release date: 30-September-2022</div>
<li>
<a href="#">About</a>
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="pmd_release_notes.html">Release notes</a></li>
<li><a href="pmd_next_major_development.html">PMD 7.0.0 development</a></li>
<li><a href="pmd_about_help.html">Getting help</a></li>
</ul>
</li>
<li>
<a href="#">User Documentation</a>
<ul>
<li><a href="pmd_userdocs_installation.html">Installation and basic CLI usage</a></li>
<li><a href="pmd_userdocs_making_rulesets.html">Making rulesets</a></li>
<li><a href="pmd_userdocs_configuring_rules.html">Configuring rules</a></li>
<li><a href="pmd_userdocs_best_practices.html">Best practices</a></li>
<li><a href="pmd_userdocs_suppressing_warnings.html">Suppressing warnings</a></li>
<li><a href="pmd_userdocs_incremental_analysis.html">Incremental analysis</a></li>
<li><a href="pmd_userdocs_cli_reference.html">PMD CLI reference</a></li>
<li><a href="pmd_userdocs_report_formats.html">PMD Report formats</a></li>
<li class="subfolders">
<a href="#">CPD reference</a>
<ul>
<li><a href="pmd_userdocs_cpd.html">Copy-paste detection</a></li>
<li><a href="pmd_userdocs_cpd_report_formats.html">CPD Report formats</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">Extending PMD</a>
<ul>
<li><a href="pmd_userdocs_extending_writing_rules_intro.html">Introduction to writing rules</a></li>
<li><a href="pmd_userdocs_extending_your_first_rule.html">Your first rule</a></li>
<li class="active"><a href="pmd_userdocs_extending_writing_xpath_rules.html">XPath rules</a></li>
<li><a href="pmd_userdocs_extending_writing_java_rules.html">Java rules</a></li>
<li><a href="pmd_userdocs_extending_designer_reference.html">Rule designer reference</a></li>
<li><a href="pmd_userdocs_extending_defining_properties.html">Defining rule properties</a></li>
<li><a href="pmd_userdocs_extending_metrics_howto.html">Using and defining code metrics</a></li>
<li><a href="pmd_userdocs_extending_rule_guidelines.html">Rule guidelines</a></li>
<li><a href="pmd_userdocs_extending_testing.html">Testing your rules</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">Tools / Integrations</a>
<ul>
<li><a href="pmd_userdocs_tools_maven.html">Maven PMD Plugin</a></li>
<li><a href="pmd_userdocs_tools_gradle.html">Gradle</a></li>
<li><a href="pmd_userdocs_tools_ant.html">Ant</a></li>
<li><a href="pmd_userdocs_tools_java_api.html">PMD Java API</a></li>
<li><a href="pmd_userdocs_tools_ci.html">CI integrations</a></li>
<li><a href="pmd_userdocs_tools.html">Other Tools / Integrations</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#">Rule Reference</a>
<ul>
<li class="subfolders">
<a href="#">Apex Rules</a>
<ul>
<li><a href="pmd_rules_apex.html">Index</a></li>
<li><a href="pmd_rules_apex_bestpractices.html">Best Practices</a></li>
<li><a href="pmd_rules_apex_codestyle.html">Code Style</a></li>
<li><a href="pmd_rules_apex_design.html">Design</a></li>
<li><a href="pmd_rules_apex_documentation.html">Documentation</a></li>
<li><a href="pmd_rules_apex_errorprone.html">Error Prone</a></li>
<li><a href="pmd_rules_apex_performance.html">Performance</a></li>
<li><a href="pmd_rules_apex_security.html">Security</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">Ecmascript Rules</a>
<ul>
<li><a href="pmd_rules_ecmascript.html">Index</a></li>
<li><a href="pmd_rules_ecmascript_bestpractices.html">Best Practices</a></li>
<li><a href="pmd_rules_ecmascript_codestyle.html">Code Style</a></li>
<li><a href="pmd_rules_ecmascript_errorprone.html">Error Prone</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">HTML Rules</a>
<ul>
<li><a href="pmd_rules_html.html">Index</a></li>
<li><a href="pmd_rules_html_bestpractices.html">Best Practices</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">Java Rules</a>
<ul>
<li><a href="pmd_rules_java.html">Index</a></li>
<li><a href="pmd_rules_java_bestpractices.html">Best Practices</a></li>
<li><a href="pmd_rules_java_codestyle.html">Code Style</a></li>
<li><a href="pmd_rules_java_design.html">Design</a></li>
<li><a href="pmd_rules_java_documentation.html">Documentation</a></li>
<li><a href="pmd_rules_java_errorprone.html">Error Prone</a></li>
<li><a href="pmd_rules_java_multithreading.html">Multithreading</a></li>
<li><a href="pmd_rules_java_performance.html">Performance</a></li>
<li><a href="pmd_rules_java_security.html">Security</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">Java Server Pages Rules</a>
<ul>
<li><a href="pmd_rules_jsp.html">Index</a></li>
<li><a href="pmd_rules_jsp_bestpractices.html">Best Practices</a></li>
<li><a href="pmd_rules_jsp_codestyle.html">Code Style</a></li>
<li><a href="pmd_rules_jsp_design.html">Design</a></li>
<li><a href="pmd_rules_jsp_errorprone.html">Error Prone</a></li>
<li><a href="pmd_rules_jsp_security.html">Security</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">Maven POM Rules</a>
<ul>
<li><a href="pmd_rules_pom.html">Index</a></li>
<li><a href="pmd_rules_pom_errorprone.html">Error Prone</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">Modelica Rules</a>
<ul>
<li><a href="pmd_rules_modelica.html">Index</a></li>
<li><a href="pmd_rules_modelica_bestpractices.html">Best Practices</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">PLSQL Rules</a>
<ul>
<li><a href="pmd_rules_plsql.html">Index</a></li>
<li><a href="pmd_rules_plsql_bestpractices.html">Best Practices</a></li>
<li><a href="pmd_rules_plsql_codestyle.html">Code Style</a></li>
<li><a href="pmd_rules_plsql_design.html">Design</a></li>
<li><a href="pmd_rules_plsql_errorprone.html">Error Prone</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">Salesforce VisualForce Rules</a>
<ul>
<li><a href="pmd_rules_vf.html">Index</a></li>
<li><a href="pmd_rules_vf_security.html">Security</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">VM Rules</a>
<ul>
<li><a href="pmd_rules_vm.html">Index</a></li>
<li><a href="pmd_rules_vm_bestpractices.html">Best Practices</a></li>
<li><a href="pmd_rules_vm_design.html">Design</a></li>
<li><a href="pmd_rules_vm_errorprone.html">Error Prone</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">XML Rules</a>
<ul>
<li><a href="pmd_rules_xml.html">Index</a></li>
<li><a href="pmd_rules_xml_errorprone.html">Error Prone</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">XSL Rules</a>
<ul>
<li><a href="pmd_rules_xsl.html">Index</a></li>
<li><a href="pmd_rules_xsl_codestyle.html">Code Style</a></li>
<li><a href="pmd_rules_xsl_performance.html">Performance</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#">Language Specific Documentation</a>
<ul>
<li><a href="pmd_languages_jsp.html">JSP Support</a></li>
<li class="subfolders">
<a href="#">Java Support</a>
<ul>
<li><a href="pmd_languages_java.html">Java Versions</a></li>
<li><a href="pmd_java_metrics_index.html">Java Code Metrics</a></li>
</ul>
</li>
<li><a href="pmd_apex_metrics_index.html">Apex code metrics</a></li>
<li><a href="pmd_languages_plsql.html">PLSQL</a></li>
<li><a href="pmd_languages_visualforce.html">Visualforce</a></li>
<li><a href="pmd_languages_xml.html">XML and XML dialects</a></li>
<li><a href="pmd_languages_html.html">HTML</a></li>
<li><a href="pmd_languages_gherkin.html">Gherkin</a></li>
</ul>
</li>
<li>
<a href="#">Developer Documentation</a>
<ul>
<li><a href="pmd_devdocs_development.html">Developer resources</a></li>
<li><a href="pmd_devdocs_building.html">Building PMD from source</a></li>
<li><a href="https://github.com/pmd/pmd/blob/master/CONTRIBUTING.md" target="_blank">Contributing</a></li>
<li><a href="pmd_devdocs_writing_documentation.html">Writing documentation</a></li>
<li><a href="pmd_devdocs_roadmap.html">Roadmap</a></li>
<li><a href="pmd_devdocs_how_pmd_works.html">How PMD works</a></li>
<li><a href="pmd_devdocs_pmdtester.html">Pmdtester</a></li>
<li><a href="pmd_devdocs_rule_deprecation_policy.html">Rule Deprecation Policy</a></li>
<li class="subfolders">
<a href="#">Major contributions</a>
<ul>
<li><a href="pmd_devdocs_major_rule_guidelines.html">Rule Guidelines</a></li>
<li><a href="pmd_devdocs_major_adding_new_language.html">Adding a new language</a></li>
<li><a href="pmd_devdocs_major_adding_new_cpd_language.html">Adding a new CPD language</a></li>
<li><a href="pmd_devdocs_major_adding_new_metrics_framework.html">Adding metrics support to a language</a></li>
</ul>
</li>
<li class="subfolders">
<a href="#">Experimental features</a>
<ul>
<li><a href="pmd_devdocs_experimental_ast_dump.html">Creating (XML) dump of the AST</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#">Project documentation</a>
<ul>
<li class="subfolders">
<a href="#">Trivia about PMD</a>
<ul>
<li><a href="pmd_projectdocs_trivia_news.html">PMD in the press</a></li>
<li><a href="pmd_projectdocs_trivia_products.html">Products & books related to PMD</a></li>
<li><a href="pmd_projectdocs_trivia_similarprojects.html">Similar projects</a></li>
<li><a href="pmd_projectdocs_trivia_meaning.html">What does 'PMD' mean?</a></li>
</ul>
</li>
<li><a href="pmd_projectdocs_faq.html">FAQ</a></li>
<li><a href="license.html">License</a></li>
<li><a href="pmd_projectdocs_credits.html">Credits</a></li>
<li><a href="pmd_release_notes_old.html">Old release notes</a></li>
<li class="subfolders">
<a href="#">Project management</a>
<ul>
<li><a href="pmd_projectdocs_committers_infrastructure.html">Infrastructure</a></li>
<li><a href="pmd_projectdocs_committers_releasing.html">Release process</a></li>
<li><a href="pmd_projectdocs_committers_merging_pull_requests.html">Merging pull requests</a></li>
<li><a href="pmd_projectdocs_committers_main_landing_page.html">Main Landing page</a></li>
</ul>
</li>
</ul>
</li>
<!-- if you aren't using the accordion, uncomment this block:
<p class="external">
<a href="#" id="collapseAll">Collapse All</a> | <a href="#" id="expandAll">Expand All</a>
</p>
-->
</ul>
<!-- this highlights the active parent class in the navgoco sidebar. this is critical so that the parent expands when you're viewing a page. This must appear below the sidebar code above. Otherwise, if placed inside customscripts.js, the script runs before the sidebar code runs and the class never gets inserted.-->
<script>$("li.active").parents('li').toggleClass("active");</script>
</div>
<!-- Content Column -->
<div class="col-md-9" id="tg-sb-content">
<header>
<div class="row">
<div class="col-lg-12">
<a href="./" role="button"
><i class="fa fa-home fa-lg"></i
></a>
» Writing XPath rules
<a
target="_blank"
href="https://github.com/pmd/pmd/blob/master/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md"
class="pull-right"
role="button"
><i class="fa fa-github fa-lg"></i> Edit on GitHub</a
>
</div>
</div>
<hr />
</header>
<div class="post-header">
<h1 class="post-title-main">Writing XPath rules</h1>
</div>
<div class="post-content" data-github-edit-url="https://github.com/pmd/pmd/blob/master/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md">
<div class="summary">This page describes XPath rule support in more details</div>
<div id="inline-toc"><!-- empty, move TOC here when screen size too small --></div>
<p>This page describes some points of XPath rule support in more details. See
also <a href="pmd_userdocs_extending_your_first_rule.html">the tutorial about how to write an XPath rule</a>.</p>
<!-- Later we can document the specific subset of XPath features our wrappers support -->
<h2 id="xpath-version">XPath version</h2>
<p>PMD supports three XPath versions for now: 1.0, 2.0, and 1.0 compatibility mode.
The version can be specified with the <code class="language-plaintext highlighter-rouge">version</code> property in the rule definition, like so:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;property</span> <span class="na">version=</span><span class="s">"2.0"</span> <span class="nt">/&gt;</span> <span class="c">&lt;!-- or "1.0", or "1.0 compatibility" --&gt;</span>
</code></pre></div></div>
<p>The default has always been version 1.0.</p>
<p><strong>As of PMD version 6.22.0, XPath versions 1.0 and the 1.0 compatibility mode are
deprecated</strong>. XPath 2.0 is superior in many ways, for example for its support for
type checking, sequence values, or quantified expressions. For a detailed
but approachable review of the features of XPath 2.0 and above, see <a href="https://www.saxonica.com/documentation/index.html#!expressions">the Saxon documentation</a>.</p>
<p>It is recommended that you migrate to 2.0 before 7.0.0, but we expect
to be able to provide an automatic migration tool when releasing 7.0.0.
See <a href="#migrating-from-10-to-20">the migration guide</a> below.</p>
<h2 id="dom-representation-of-asts">DOM representation of ASTs</h2>
<p>XPath rules view the AST as an XML-like DOM, which is what the XPath language is
defined on. Concretely, this means:</p>
<ul>
<li>Every AST node is viewed as an XML element
<ul>
<li>The element has for local name the value of <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.50.0-SNAPSHOT/net/sourceforge/pmd/lang/ast/Node.html#getXPathNodeName()"><code>getXPathNodeName</code></a>
for the given node</li>
</ul>
</li>
<li>Some Java getters are exposed as XML attributes on those elements
<ul>
<li>This means, that documentation for attributes can be found in our Javadocs. For
example, the attribute <code class="language-plaintext highlighter-rouge">@SimpleName</code> of the Java node <code class="language-plaintext highlighter-rouge">EnumDeclaration</code> is backed
by the Java getter <a href="https://docs.pmd-code.org/apidocs/pmd-java/6.50.0-SNAPSHOT/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.html#getSimpleName()"><code>getSimpleName</code></a>.</li>
</ul>
</li>
</ul>
<h3 id="value-conversion">Value conversion</h3>
<p>To represent attributes, we must map Java values to <a href="https://www.w3.org/TR/xpath-datamodel/">XPath Data Model (XDM)</a> values. The conversion
depends on the XPath version used.</p>
<h4 id="xpath-10">XPath 1.0</h4>
<p>On XPath 1.0 we map every Java value to an <code class="language-plaintext highlighter-rouge">xs:string</code> value by using the <code class="language-plaintext highlighter-rouge">toString</code>
of the object. Since XPath 1.0 allows many implicit conversions this works, but it
causes some incompatibilities with XPath 2.0 (see the section about migration further
down).</p>
<h4 id="xpath-20">XPath 2.0</h4>
<p>XPath 2.0 is a strongly typed language, and so we use more precise type annotations.
In the following table we refer to the type conversion function as <code class="language-plaintext highlighter-rouge">conv</code>, a
function from Java types to XDM types.</p>
<table>
<thead>
<tr>
<th>Java type <code class="language-plaintext highlighter-rouge">T</code></th>
<th>XSD type <code class="language-plaintext highlighter-rouge">conv(T)</code></th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="language-plaintext highlighter-rouge">int</code></td>
<td><code class="language-plaintext highlighter-rouge">xs:integer</code></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">long</code></td>
<td><code class="language-plaintext highlighter-rouge">xs:integer</code></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">double</code></td>
<td><code class="language-plaintext highlighter-rouge">xs:decimal</code></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">float</code></td>
<td><code class="language-plaintext highlighter-rouge">xs:decimal</code></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">boolean</code></td>
<td><code class="language-plaintext highlighter-rouge">xs:boolean</code></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">String</code></td>
<td><code class="language-plaintext highlighter-rouge">xs:string</code></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">Character</code></td>
<td><code class="language-plaintext highlighter-rouge">xs:string</code></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">Enum&lt;E&gt;</code></td>
<td><code class="language-plaintext highlighter-rouge">xs:string</code> (uses <code class="language-plaintext highlighter-rouge">Object::toString</code>)</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">List&lt;E&gt;</code></td>
<td><code class="language-plaintext highlighter-rouge">conv(E)*</code> (a sequence type) <br /> ⚠️ List support is deprecated with 6.25.0. See below.</td>
</tr>
</tbody>
</table>
<p>The same <code class="language-plaintext highlighter-rouge">conv</code> function is used to translate rule property values to XDM values.</p>
<div class="alert alert-danger" role="alert"><i class="fa fa-exclamation-circle"></i> <b>Warning:</b> Support for attributes of type <code class="language-plaintext highlighter-rouge">List&lt;E&gt;</code> has been deprecated
with PMD 6.25.0 and will be removed completely with PMD 7. The reason is that newer Saxon
versions dont support sequences as attributes anymore. Lists are still possible in Java-based
rules but not with XPath.
<a href="pmd_userdocs_extending_defining_properties.html#multivalued-properties">Multivalued rule properties</a>
are still supported.</div>
<h2 id="migrating-from-10-to-20">Migrating from 1.0 to 2.0</h2>
<p>XPath 1.0 and 2.0 have some incompatibilities. The <a href="https://www.w3.org/TR/xpath20/#id-incompat-in-false-mode">XPath 2.0 specification</a>
describes them precisely. Those are however mostly corner cases and XPath
rules usually dont feature any of them.</p>
<p>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. Heres a list of known incompatibilities:</p>
<ul>
<li>The namespace prefixes <code class="language-plaintext highlighter-rouge">fn:</code> and <code class="language-plaintext highlighter-rouge">string:</code> 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.
<ul>
<li><code><b style="color:red">fn:</b>substring("Foo", 1)</code><code class="language-plaintext highlighter-rouge">substring("Foo", 1)</code></li>
</ul>
</li>
<li>Conversely, calls to custom PMD functions like <code class="language-plaintext highlighter-rouge">typeIs</code> <em>must</em> be prefixed
with the namespace of the declaring module (<code class="language-plaintext highlighter-rouge">pmd-java</code>).
<ul>
<li><code class="language-plaintext highlighter-rouge">typeIs("Foo")</code><code><b style="color:green">pmd-java:</b>typeIs("Foo")</code></li>
</ul>
</li>
<li>Boolean attribute values on our 1.0 engine are represented as the string values
<code class="language-plaintext highlighter-rouge">"true"</code> and <code class="language-plaintext highlighter-rouge">"false"</code>. In 2.0 mode though, boolean values are truly represented
as boolean values, which in XPath may only be obtained through the functions
<code class="language-plaintext highlighter-rouge">true()</code> and <code class="language-plaintext highlighter-rouge">false()</code>.
If your XPath 1.0 rule tests an attribute like <code class="language-plaintext highlighter-rouge">@Private="true"</code>, then it just
needs to be changed to <code class="language-plaintext highlighter-rouge">@Private=true()</code> when migrating. A type error will warn
you that you must update the comparison. More is explained on <a href="https://github.com/pmd/pmd/issues/1244">issue #1244</a>.
<ul>
<li><code class="language-plaintext highlighter-rouge">"true"</code>, <code class="language-plaintext highlighter-rouge">'true'</code><code class="language-plaintext highlighter-rouge">true()</code></li>
<li><code class="language-plaintext highlighter-rouge">"false"</code>, <code class="language-plaintext highlighter-rouge">'false'</code><code class="language-plaintext highlighter-rouge">false()</code></li>
</ul>
</li>
<li>In XPath 1.0, comparing a number to a string coerces the string to a number.
In XPath 2.0, a type error occurs. Like for boolean values, numeric values are
represented by our 1.0 implementation as strings, meaning that <code class="language-plaintext highlighter-rouge">@BeginLine &gt; "1"</code>
worked —thats not the case in 2.0 mode.
<ul>
<li><code>@ArgumentCount &gt; <b style="color:red">'</b>1<b style="color:red">'</b></code><code class="language-plaintext highlighter-rouge">@ArgumentCount &gt; 1</code></li>
</ul>
</li>
<li>In XPath 1.0, the expression <code class="language-plaintext highlighter-rouge">/Foo</code> matches the <em>children</em> of the root named <code class="language-plaintext highlighter-rouge">Foo</code>.
In XPath 2.0, that expression matches the root, if it is named <code class="language-plaintext highlighter-rouge">Foo</code>. Consider the following tree:
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Foo</span>
<span class="err">└─</span> <span class="nc">Foo</span>
<span class="err">└─</span> <span class="nc">Foo</span>
</code></pre></div> </div>
<p>Then <code class="language-plaintext highlighter-rouge">/Foo</code> will match the root in XPath 2, and the other nodes (but not the root) in XPath 1.
See eg <a href="https://github.com/pmd/pmd/issues/1919#issuecomment-512865434">an issue caused by this</a> in Apex,
with nested classes.</p>
</li>
</ul>
<h2 id="rule-properties">Rule properties</h2>
<p><strong>See <a href="pmd_userdocs_extending_defining_properties.html#for-xpath-rules">Defining rule properties</a></strong></p>
<h2 id="pmd-extension-functions">PMD extension functions</h2>
<p>PMD provides some language-specific XPath functions to access semantic
information from the AST.</p>
<p>On XPath 2.0, the namespace of custom PMD function must be explicitly mentioned.</p>
<!-- Generates the documentation of XPath functions. -->
<h3 id="all-languages">All languages</h3>
<p>Functions available to all languages are in the namespace <code>pmd</code>.</p>
<div class="table-responsive">
<table width="100%">
<thead>
<tr>
<th>Function name</th>
<th>Description (click for details)</th>
<th></th>
</tr>
</thead>
<tr data-toggle="collapse" id="pmd-fileName" data-target="#pmd-fileName-expand" class="accordion-toggle">
<td>fileName</td>
<td>Returns the simple name of the current file</td>
<td>
<button type="button" class="btn btn-link"><i class="fa fa-ellipsis-h"></i></button>
</td>
</tr>
<tr>
<td colspan="4" class="hiddenRow">
<div class="accordion-body collapse" id="pmd-fileName-expand">
<div style="margin-left: 15px" class="xpath-fun-doc">
<!-- Yeah the ID is duplicated but it's ok on my browser and makes -->
<!--links somehow work when details are collapsed -->
<h4 class="fun-details-header" id="pmd-fileName">
<span class="fun-ns">pmd:</span><span class="fun-name">fileName</span><span class="fun-ns">() as xs:string</span>
</h4>
<div style="margin-left: 30px">
<dl>
<dd>Returns the current simple file name, without path but including the extension.
This can be used to write rules that check file naming conventions.
</dd>
<dt>Since</dt>
<dd>PMD 6.38.0</dd>
<dt>Remarks</dt>
<dd>The requires the context node to be an element</dd>
<dt>Examples</dt>
<dd>
<dl class="code-examples">
<dt><code>//b[pmd:fileName() = 'Foo.xml']</code></dt>
<dd>Matches any <code>&lt;b&gt;</code> tags in files called <code>Foo.xml</code>.</dd>
</dl>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>
<tr data-toggle="collapse" id="pmd-startLine" data-target="#pmd-startLine-expand" class="accordion-toggle">
<td>startLine</td>
<td>Returns the start line of the given node</td>
<td>
<button type="button" class="btn btn-link"><i class="fa fa-ellipsis-h"></i></button>
</td>
</tr>
<tr>
<td colspan="4" class="hiddenRow">
<div class="accordion-body collapse" id="pmd-startLine-expand">
<div style="margin-left: 15px" class="xpath-fun-doc">
<!-- Yeah the ID is duplicated but it's ok on my browser and makes -->
<!--links somehow work when details are collapsed -->
<h4 class="fun-details-header" id="pmd-startLine">
<span class="fun-ns">pmd:</span><span class="fun-name">startLine</span><span class="fun-ns">(xs:element) as xs:int</span>
</h4>
<div style="margin-left: 30px">
<dl>
<dd>Returns the line where the node starts in the source file.
Line numbers are 1-based.
</dd>
<dt>Since</dt>
<dd>PMD 6.44.0</dd>
<dt>Remarks</dt>
<dd>The function is not context-dependent, but takes a node as its first parameter.
The function is only available in XPath 2.0.
</dd>
<dt>Parameters</dt>
<dd>
<dl>
<dt>
<span class="param-name">element</span>
<span class="param-type"> as xs:element</span>
</dt>
<dd>Any element node</dd>
</dl>
</dd>
<dt>Examples</dt>
<dd>
<dl class="code-examples">
<dt><code>//b[pmd:startLine(.) &gt; 5]</code></dt>
<dd>Matches any <code>&lt;b&gt;</code> node which starts after the fifth line.</dd>
</dl>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>
<tr data-toggle="collapse" id="pmd-endLine" data-target="#pmd-endLine-expand" class="accordion-toggle">
<td>endLine</td>
<td>Returns the end line of the given node</td>
<td>
<button type="button" class="btn btn-link"><i class="fa fa-ellipsis-h"></i></button>
</td>
</tr>
<tr>
<td colspan="4" class="hiddenRow">
<div class="accordion-body collapse" id="pmd-endLine-expand">
<div style="margin-left: 15px" class="xpath-fun-doc">
<!-- Yeah the ID is duplicated but it's ok on my browser and makes -->
<!--links somehow work when details are collapsed -->
<h4 class="fun-details-header" id="pmd-endLine">
<span class="fun-ns">pmd:</span><span class="fun-name">endLine</span><span class="fun-ns">(xs:element) as xs:int</span>
</h4>
<div style="margin-left: 30px">
<dl>
<dd>Returns the line where the node ends in the source file.
Line numbers are 1-based.
</dd>
<dt>Since</dt>
<dd>PMD 6.44.0</dd>
<dt>Remarks</dt>
<dd>The function is not context-dependent, but takes a node as its first parameter.
The function is only available in XPath 2.0.
</dd>
<dt>Parameters</dt>
<dd>
<dl>
<dt>
<span class="param-name">element</span>
<span class="param-type"> as xs:element</span>
</dt>
<dd>Any element node</dd>
</dl>
</dd>
<dt>Examples</dt>
<dd>
<dl class="code-examples">
<dt><code>//b[pmd:endLine(.) == pmd:startLine(.)]</code></dt>
<dd>Matches any <code>&lt;b&gt;</code> node which doesn't span more than one line.</dd>
</dl>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>
<tr data-toggle="collapse" id="pmd-startColumn" data-target="#pmd-startColumn-expand" class="accordion-toggle">
<td>startColumn</td>
<td>Returns the start column of the given node (inclusive)</td>
<td>
<button type="button" class="btn btn-link"><i class="fa fa-ellipsis-h"></i></button>
</td>
</tr>
<tr>
<td colspan="4" class="hiddenRow">
<div class="accordion-body collapse" id="pmd-startColumn-expand">
<div style="margin-left: 15px" class="xpath-fun-doc">
<!-- Yeah the ID is duplicated but it's ok on my browser and makes -->
<!--links somehow work when details are collapsed -->
<h4 class="fun-details-header" id="pmd-startColumn">
<span class="fun-ns">pmd:</span><span class="fun-name">startColumn</span><span class="fun-ns">(xs:element) as xs:int</span>
</h4>
<div style="margin-left: 30px">
<dl>
<dd>Returns the column number where the node starts in the source file.
Column numbers are 1-based. The start column is inclusive.
</dd>
<dt>Since</dt>
<dd>PMD 6.44.0</dd>
<dt>Remarks</dt>
<dd>The function is not context-dependent, but takes a node as its first parameter.
The function is only available in XPath 2.0.
</dd>
<dt>Parameters</dt>
<dd>
<dl>
<dt>
<span class="param-name">element</span>
<span class="param-type"> as xs:element</span>
</dt>
<dd>Any element node</dd>
</dl>
</dd>
<dt>Examples</dt>
<dd>
<dl class="code-examples">
<dt><code>//b[pmd:startColumn(.) = 1]</code></dt>
<dd>Matches any <code>&lt;b&gt;</code> node which starts on the first column of a line</dd>
</dl>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>
<tr data-toggle="collapse" id="pmd-endColumn" data-target="#pmd-endColumn-expand" class="accordion-toggle">
<td>endColumn</td>
<td>Returns the end column of the given node (exclusive)</td>
<td>
<button type="button" class="btn btn-link"><i class="fa fa-ellipsis-h"></i></button>
</td>
</tr>
<tr>
<td colspan="4" class="hiddenRow">
<div class="accordion-body collapse" id="pmd-endColumn-expand">
<div style="margin-left: 15px" class="xpath-fun-doc">
<!-- Yeah the ID is duplicated but it's ok on my browser and makes -->
<!--links somehow work when details are collapsed -->
<h4 class="fun-details-header" id="pmd-endColumn">
<span class="fun-ns">pmd:</span><span class="fun-name">endColumn</span><span class="fun-ns">(xs:element) as xs:int</span>
</h4>
<div style="margin-left: 30px">
<dl>
<dd>Returns the column number where the node ends in the source file.
Column numbers are 1-based. The end column is exclusive.
</dd>
<dt>Since</dt>
<dd>PMD 6.44.0</dd>
<dt>Remarks</dt>
<dd>The function is not context-dependent, but takes a node as its first parameter.
The function is only available in XPath 2.0.
</dd>
<dt>Parameters</dt>
<dd>
<dl>
<dt>
<span class="param-name">element</span>
<span class="param-type"> as xs:element</span>
</dt>
<dd>Any element node</dd>
</dl>
</dd>
<dt>Examples</dt>
<dd>
<dl class="code-examples">
<dt><code>//b[pmd:startLine(.) = pmd:endLine(.) and pmd:endColumn(.) - pmd:startColumn(.) = 1]</code></dt>
<dd>Matches any <code>&lt;b&gt;</code> node which spans exactly one character</dd>
</dl>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>
</table>
</div>
<!-- Generates the documentation of XPath functions. -->
<h3 id="java">Java</h3>
<p>Java functions are in the namespace <code class="language-plaintext highlighter-rouge">pmd-java</code>.</p>
<div class="table-responsive">
<table width="100%">
<thead>
<tr>
<th>Function name</th>
<th>Description (click for details)</th>
<th></th>
</tr>
</thead>
<tr data-toggle="collapse" id="pmd-java-typeIs" data-target="#pmd-java-typeIs-expand" class="accordion-toggle">
<td>typeIs</td>
<td>Tests a node's static type</td>
<td>
<button type="button" class="btn btn-link"><i class="fa fa-ellipsis-h"></i></button>
</td>
</tr>
<tr>
<td colspan="4" class="hiddenRow">
<div class="accordion-body collapse" id="pmd-java-typeIs-expand">
<div style="margin-left: 15px" class="xpath-fun-doc">
<!-- Yeah the ID is duplicated but it's ok on my browser and makes -->
<!--links somehow work when details are collapsed -->
<h4 class="fun-details-header" id="pmd-java-typeIs">
<span class="fun-ns">pmd-java:</span><span class="fun-name">typeIs</span><span class="fun-ns">(xs:string) as xs:boolean</span>
</h4>
<div style="margin-left: 30px">
<dl>
<dd>Returns true if the context node's static Java type is a subtype of the given type. This tests for the resolved type of the Java construct, not the type of the AST node. For example, the AST node for a literal (e.g. <code>5d</code>) has type ASTLiteral, however this function will compare the type of the literal (eg here, <code>double</code>) against the argument.</dd>
<dt>Remarks</dt>
<dd>The context node must be a <a href="https://docs.pmd-code.org/apidocs/pmd-java/6.50.0-SNAPSHOT/net/sourceforge/pmd/lang/java/ast/TypeNode.html#"><code>TypeNode</code></a></dd>
<dt>Parameters</dt>
<dd>
<dl>
<dt>
<span class="param-name">javaQualifiedName</span>
<span class="param-type"> as xs:string</span>
</dt>
<dd>The qualified name of a Java class, possibly with pairs of brackets to indicate an array type. Can also be a primitive type name.</dd>
</dl>
</dd>
<dt>Examples</dt>
<dd>
<dl class="code-examples">
<dt><code>//FormalParameter[pmd-java:typeIs("java.lang.String[]")]</code></dt>
<dd>Matches formal parameters of type <code>String[]</code> (including vararg parameters)</dd>
<dt><code>//VariableDeclaratorId[pmd-java:typeIs("java.lang.List")]</code></dt>
<dd>Matches variable declarators of type <code>List</code> or any of its subtypes (including e.g. <code>ArrayList</code>)</dd>
</dl>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>
<tr data-toggle="collapse" id="pmd-java-typeIsExactly" data-target="#pmd-java-typeIsExactly-expand" class="accordion-toggle">
<td>typeIsExactly</td>
<td>Tests a node's static type, ignoring subtypes</td>
<td>
<button type="button" class="btn btn-link"><i class="fa fa-ellipsis-h"></i></button>
</td>
</tr>
<tr>
<td colspan="4" class="hiddenRow">
<div class="accordion-body collapse" id="pmd-java-typeIsExactly-expand">
<div style="margin-left: 15px" class="xpath-fun-doc">
<!-- Yeah the ID is duplicated but it's ok on my browser and makes -->
<!--links somehow work when details are collapsed -->
<h4 class="fun-details-header" id="pmd-java-typeIsExactly">
<span class="fun-ns">pmd-java:</span><span class="fun-name">typeIsExactly</span><span class="fun-ns">(xs:string) as xs:boolean</span>
</h4>
<div style="margin-left: 30px">
<dl>
<dd>Returns true if the context node's static type is exactly the given type. In particular, returns false if the context node's type is a subtype of the given type.</dd>
<dt>Remarks</dt>
<dd>The context node must be a <a href="https://docs.pmd-code.org/apidocs/pmd-java/6.50.0-SNAPSHOT/net/sourceforge/pmd/lang/java/ast/TypeNode.html#"><code>TypeNode</code></a></dd>
<dt>Parameters</dt>
<dd>
<dl>
<dt>
<span class="param-name">javaQualifiedName</span>
<span class="param-type"> as xs:string</span>
</dt>
<dd>The qualified name of a Java class, possibly with pairs of brackets to indicate an array type. Can also be a primitive type name.</dd>
</dl>
</dd>
<dt>Examples</dt>
<dd>
<dl class="code-examples">
<dt><code>//VariableDeclaratorId[pmd-java:typeIsExactly("java.lang.List")]</code></dt>
<dd>Matches variable declarators of type <code>List</code> (but not e.g. <code>ArrayList</code>)</dd>
</dl>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>
<tr data-toggle="collapse" id="pmd-java-metric" data-target="#pmd-java-metric-expand" class="accordion-toggle">
<td>metric</td>
<td>Computes and returns the value of a metric</td>
<td>
<button type="button" class="btn btn-link"><i class="fa fa-ellipsis-h"></i></button>
</td>
</tr>
<tr>
<td colspan="4" class="hiddenRow">
<div class="accordion-body collapse" id="pmd-java-metric-expand">
<div style="margin-left: 15px" class="xpath-fun-doc">
<!-- Yeah the ID is duplicated but it's ok on my browser and makes -->
<!--links somehow work when details are collapsed -->
<h4 class="fun-details-header" id="pmd-java-metric">
<span class="fun-ns">pmd-java:</span><span class="fun-name">metric</span><span class="fun-ns">(xs:string) as xs:decimal?</span>
</h4>
<div style="margin-left: 30px">
<dl>
<dd>Returns the value of the metric as evaluated on the context node</dd>
<dt>Remarks</dt>
<dd>The context node must be a <a href="https://docs.pmd-code.org/apidocs/pmd-java/6.50.0-SNAPSHOT/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.html#"><code>ASTAnyTypeDeclaration</code></a> or a <a href="https://docs.pmd-code.org/apidocs/pmd-java/6.50.0-SNAPSHOT/net/sourceforge/pmd/lang/java/ast/MethodLikeNode.html#"><code>MethodLikeNode</code></a></dd>
<dt>Parameters</dt>
<dd>
<dl>
<dt>
<span class="param-name">metricKey</span>
<span class="param-type"> as xs:string</span>
</dt>
<dd>The name of an enum constant in <a href="https://docs.pmd-code.org/apidocs/pmd-java/6.50.0-SNAPSHOT/net/sourceforge/pmd/lang/java/metrics/api/JavaOperationMetricKey.html#"><code>JavaOperationMetricKey</code></a> or <a href="https://docs.pmd-code.org/apidocs/pmd-java/6.50.0-SNAPSHOT/net/sourceforge/pmd/lang/java/metrics/api/JavaClassMetricKey.html#"><code>JavaClassMetricKey</code></a></dd>
</dl>
</dd>
</dl>
</div>
</div>
</div>
</td>
</tr>
</table>
</div>
<div class="alert alert-info" role="alert"><i class="fa fa-info-circle"></i> <b>Note:</b> There is also a <code class="language-plaintext highlighter-rouge">typeOf</code> function which is
deprecated and whose usages should be replaced with uses of <code class="language-plaintext highlighter-rouge">typeIs</code> or
<code class="language-plaintext highlighter-rouge">typeIsExactly</code>. That one will be removed with PMD 7.0.0.</div>
<div class="tags">
<b>Tags: </b>
<a href="tag_extending.html" class="btn btn-default navbar-btn cursorNorm" role="button">extending</a>
<a href="tag_userdocs.html" class="btn btn-default navbar-btn cursorNorm" role="button">userdocs</a>
</div>
</div>
<footer>
<hr />
<div>
This documentation is written in markdown. <br />
If there is something missing or can be improved, edit this page on
github and create a PR:
<a
target="_blank"
href="https://github.com/pmd/pmd/blob/master/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md"
role="button"
><i class="fa fa-github fa-lg"></i> Edit on GitHub</a
>
</div>
<hr />
<div class="row">
<div class="col-lg-12 footer">
&copy;2022 PMD Open Source Project. All rights
reserved. <br />
<span>Page last updated:</span>
February 2020 (6.22.0)<br /> Site last generated: Sep 10, 2022 <br />
<p>
<img src="images/pmd-logo-small.png" alt="Company
logo"/>
</p>
</div>
</div>
</footer>
</div>
<!-- /.row -->
</div>
<!-- /.container -->
</div>
<!-- Sticky TOC column -->
<div class="toc-col">
<div id="toc"></div>
</div>
<!-- /.toc-container-wrapper -->
</div>
</div>
</body>
</html>