I took over a project with files generated with Mapforce. I read something like :
*[local-name()='no_regnat' and namespace-uri()=''][not((not((translate(string(@xsi:nil), 'true ', '1') = '1')) and (string(.) = '')))]
It seems it can be writen like this
no_regnat[not((boolean(@xsi:nil) and (string(.) = '')))]
Why is it doing the former ?
Let us first consider the left side of the expressions,
*[local-name()='no_regnat' and namespace-uri()='']
and
no_regnat
In most contexts, they mean exactly the same, but in very specific situations, they do not yield the same result sequence:
If you define an xpath-default-namespace
in your XSLT 2.0 stylesheet, the expressions do not deliver the same results:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="www.no_regnat.com">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<results>
<xsl:apply-templates/>
</results>
</xsl:template>
<xsl:template match="*[local-name()='no_regnat' and namespace-uri()='']">
<!--Or: template match="no_regnat"-->
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
Test the above with, for instance,
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:r="www.no_regnat.com">
<no_regnat n="1"/>
<r:no_regnat n="2"/>
<other xmlns="www.no_regnat.com">
<no_regnat n="3"/>
</other>
</root>
And directly transform it online here.
So, we would need to see the context of those expressions to decide whether Mapforce is indeed generating code that is too verbose.
Then, the second predicate:
translate(string(@nil), 'true ', '1')
is really odd, in my opinion. The translate()
function only ever works with single characters, and that's why the strings that are the second and third argument of translate()
usually have the same length. Characters in the second argument that do not have a counterpart in the third argument are translated to the empty string.
So, what the function is doing here is mapping t
to 1
, and mapping r
, u
and e
and (whitespace) to nothing.
boolean()
is much more useful here.
But be careful with the semantics of those predicates:
[not((not((translate(string(@xsi:nil), 'true ', '1') = '1')) and (string(.) = '')))]
means
do not allow cases where
xsi:nil
isfalse
and the string value of the context element is empty
Whereas
[not((boolean(@xsi:nil) and (string(.) = '')))]
means
do not allow cases where
xsi:nil
istrue
and the string value of the context element is empty
Most likely, the correct constraint is: if xsi:nil = 'true'
, then the context element must be empty.