The problem
Our Jaxen adapter treats boolean attribute values as strings, ie an attribute with the Java value true will have the XPath string value 'true', and same for false.
The problem with that is that it's inconsistent with the XPath spec. In XPath, strings are truthy if they are non-empty. That means the string 'false' is in fact truthy. Moreover, the only way to obtain boolean values in both XPath 1.0 and 2.0 is through the functions true() and false().
So for example, given:
class Foo {} // the @Interface attribute is of course false
and the XPath query (<val> is a placeholder):
//ClassOrInterfaceDeclaration[@Interface=<val>]
We have the following evaluation results, depending on the value of <val> and the XPath engine used.
n means no match
y means a match
- Bold table cells mean inconsistent behaviour
<val>: |
'true' |
'false' |
true() |
false() |
| Jaxen |
n |
y |
y |
n |
| Saxon |
type error |
type error |
n |
y |
Saxon's behaviour is expected, it even has a type error when we try to compare the boolean with a string (at least in the designer).
Jaxen, on the other hand, is confused when using the boolean XPath functions:
'false' is truthy so @Interface=true() is true, because @Interface is 'false'
- For the same reason,
@Interface=false() is false
This is the inverse of what we'd expect.
So what?
Due to that inconsistency, all XPath 1.0 rules (so nearly all our XPath rules, and probably the majority of user rules as well) compare boolean attributes with string values.
The problem is that it's incompatibile with the correct behaviour of Saxon
Because of that, Jaxen rules cannot be transparently ported to Saxon without transforming at least these comparisons to use the boolean value functions. If they aren't transformed, we get type errors/ unseen failures, e.g. #902
Possible solution
If we want to drop Jaxen, we'd probably need to transform the faulty comparisons before feeding the expression to Saxon. #1243 could be a way to do that
Source
The faulty source is here:
|
public String getStringValue() { |
|
if (stringValue != null) { |
|
return stringValue; |
|
} |
|
Object v = this.value; |
|
if (this.value == null) { |
|
v = getValue(); |
|
} |
|
stringValue = v == null ? "" : String.valueOf(v); |
|
return stringValue; |
|
} |
Instead of returning just String.valueOf, this function should be returning a falsy (empty) string for false values, instead of 'false'.
The same happens for properties:
|
final Object value = e.getValue(); |
|
vc.setVariableValue(propName, value != null ? value.toString() : null); |
The problem
Our Jaxen adapter treats boolean attribute values as strings, ie an attribute with the Java value
truewill have the XPath string value'true', and same forfalse.The problem with that is that it's inconsistent with the XPath spec. In XPath, strings are truthy if they are non-empty. That means the string
'false'is in fact truthy. Moreover, the only way to obtain boolean values in both XPath 1.0 and 2.0 is through the functionstrue()andfalse().So for example, given:
and the XPath query (
<val>is a placeholder):We have the following evaluation results, depending on the value of
<val>and the XPath engine used.nmeans no matchymeans a match<val>:'true''false'true()false()Saxon's behaviour is expected, it even has a type error when we try to compare the boolean with a string (at least in the designer).
Jaxen, on the other hand, is confused when using the boolean XPath functions:
'false'is truthy so@Interface=true()is true, because@Interfaceis'false'@Interface=false()is falseThis is the inverse of what we'd expect.
So what?
Due to that inconsistency, all XPath 1.0 rules (so nearly all our XPath rules, and probably the majority of user rules as well) compare boolean attributes with string values.
The problem is that it's incompatibile with the correct behaviour of Saxon
Because of that, Jaxen rules cannot be transparently ported to Saxon without transforming at least these comparisons to use the boolean value functions. If they aren't transformed, we get type errors/ unseen failures, e.g. #902
Possible solution
If we want to drop Jaxen, we'd probably need to transform the faulty comparisons before feeding the expression to Saxon. #1243 could be a way to do that
Source
The faulty source is here:
pmd/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java
Lines 84 to 94 in 64ee977
Instead of returning just String.valueOf, this function should be returning a falsy (empty) string for
falsevalues, instead of'false'.The same happens for properties:
pmd/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/JaxenXPathRuleQuery.java
Lines 256 to 257 in 64ee977