@neo, the XPath expression you list doesn't work when I test it. Try a different data set and you'll see:
<root>
<item>
<d>2003-05-30T09:00:00</d>
</item>
<item>
<d>2002-05-30T09:00:00</d>
</item>
<item>
<d>2005-05-30T09:00:00</d>
</item>
</root>
Your XPath produces 2003-05-30T09:00:00
, which obviously is not the max.
And it makes sense that it doesn't work, because the preceding-sibling:: and following-sibling:: axes inside the translate() functions will only yield one sibling each. You're trying to go a general (set) comparison over all the siblings on each axis, but the first argument to translate() has to get converted to a string, before the general comparison operator has a chance to do its thing. Converting a nodeset to a string ignores all nodes except the first one in document order.
Furthermore, translate(./d, 'TZ:-', '.')
gives you results like 2003.05.30.09.00.00
. That's not a valid number, beyond the '5'. Your test data only works because the years are all different. You would get better results with translate(./d, 'TZ:-', '')
which would yield 20030530090000
.
Alejandro says it's not possible to do this in XPath 1.0, and he may be right. Let's try it, and maybe we'll learn something even if we don't succeed.
Next, I would try to use the general comparison outside the translate function, so that it can compare whole node-sets. Something like this naive attempt:
/root/item[
not(following-sibling::item[
translate($current/d, 'TZ:-', '') <= translate(./d, 'TZ:-', '')])
and not(preceding-sibling::item[
translate($current/d, 'TZ:-', '') <= translate(./d, 'TZ:-', '')])]
However this is incomplete as shown by the pseudo-variable $current, which is supposed to refer to the outermost item, the one that is the context node outside all predicates. Unfortunately, XPath 1.0 does not give us a way to refer to that outer context when another context has been pushed on the stack by an inner predicate.
(I seem to recall that \some implementations of XSLT, such as maybe MSXML, allow you to do this using an extended feature like current(1)
, but I can't find information on that at the moment. Anyway you asked for an XPath solution, and current()
is not XPath.)
At this point I'm going to agree with Alejandro that it's impossible in pure, standard XSLT 1.0.
If you specify the environment you're using XPath in, e.g. XSLT, or Javascript, or XQuery, we can probably suggest an efficient way to get what you need. If it's XPath 2.0, Alejandro has your answer.
If you have XQuery 1.0, it should support XPath 2.0, so you can use Alejandro's solution, with doc() to access your input XML document:
max(doc("myInput.xml")/root/item/d/xs:dateTime(.))