Один из способов сделать это, учитывая XSLT 3.0, состоит в том, чтобы просто взять все ваше выражение и обернуть его в атрибут выбора XSLT, но с корректировкой кавычек типа «один-против-двойных», например,
<xsl:variable name="result" select='
let
$duration := string(/test/@duration),
$components := analyze-string(
$duration,
"(((\d*):)?([0-5]?[0-9]):)?([0-5]?[0-9])(\.([0-9]?[0-9]?[0-9]?))?"
),
$hours := $components//fn:group[@nr="3"]/text(),
$hours := if ($hours != "") then $hours else 0,
$minutes := $components//fn:group[@nr="4"]/text(),
$minutes := if ($minutes != "") then $minutes else 0,
$seconds := $components//fn:group[@nr="5"]/text(),
$seconds := if ($seconds != "") then $seconds else 0,
$millis := $components//fn:group[@nr="7"]/text(),
$millis := if ($millis != "") then $millis else 0
return
xs:int($hours * 60 * 60 * 1000
+ $minutes * 60 * 1000
+ $seconds * 1000
+ $millis)'/>
Другой способ - переписать его, используя конструкции XSLT на более мелком уровне:
<xsl:variable name="duration" select="string(/test/@duration)"/>
<xsl:variable name="components" select='analyze-string(
$duration,
"(((\d*):)?([0-5]?[0-9]):)?([0-5]?[0-9])(\.([0-9]?[0-9]?[0-9]?))?"
)'/>
<xsl:variable name="hours" select="$components//fn:group[@nr='3']/text()'/>
et c
Третий способ - заменить вызов на fn:analyze-string()
чем-то который использует инструкцию XSLT xsl:analyze-string
; тогда у вас потенциально будет что-то, что работает под XSLT 2.0.