Поскольку Тим возлагал на меня бремя и давление, чтобы попытаться найти какой-нибудь компактный/комплексный способ XSLT 3, я попытался использовать аккумуляторы плюс XPath:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text" indent="no"/>
<xsl:mode on-no-match="shallow-skip" use-accumulators="#all"/>
<xsl:accumulator name="person-codes" as="xs:string*" initial-value="()">
<xsl:accumulator-rule match="persons/person" select="()"/>
<xsl:accumulator-rule match="persons/person/types/type" select="$value, string(@code)"/>
</xsl:accumulator>
<xsl:accumulator name="permutations" as="xs:string*" initial-value="()">
<xsl:accumulator-rule phase="end" match="person"
select="
if (empty($value))
then
accumulator-after('person-codes')
else
for $v in $value,
$cv in accumulator-after('person-codes')
return $v || $cv"/>
</xsl:accumulator>
<xsl:template match="persons">
<xsl:apply-templates/>
<xsl:value-of select="accumulator-after('permutations')" separator=" "/>
</xsl:template>
</xsl:stylesheet>
Кажется, это дает правильный результат для Saxon 9.8 и 9.9 и в https://xsltfiddle.liberty-development.net/gWEamL3/4 для получения последней информации, но без учета различных других данных, которые необходимо собрать, а только атрибуты code
.
Аккумуляторный подход работает даже с Saxon EE и потоковой передачей:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text" indent="no"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip" use-accumulators="#all"/>
<xsl:accumulator name="person-codes" as="xs:string*" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="persons/person" select="()"/>
<xsl:accumulator-rule match="persons/person/types/type" select="$value, string(@code)"/>
</xsl:accumulator>
<xsl:accumulator name="permutations" as="xs:string*" initial-value="()" streamable="yes">
<xsl:accumulator-rule phase="end" match="person"
select="
if (empty($value))
then
accumulator-after('person-codes')
else
for $v in $value,
$cv in accumulator-after('person-codes')
return
$v || $cv"
/>
</xsl:accumulator>
<xsl:template match="persons">
<xsl:apply-templates/>
<xsl:value-of select="accumulator-after('permutations')" separator=" "/>
</xsl:template>
</xsl:stylesheet>
Версия, которая также фиксирует отдел и имена и должна работать без потоковой передачи (например, Saxon 9.8 или более поздней версии HE или PE) или с потоковой передачей (например, Saxon 9.8 или более поздней версии EE):
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:param name="sep" as="xs:string" select="';'"/>
<xsl:output method="text" indent="no"/>
<xsl:mode on-no-match="shallow-skip" streamable="yes" use-accumulators="#all"/>
<xsl:accumulator name="department" as="xs:string?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="persons/department/text()" select="string()"/>
</xsl:accumulator>
<xsl:accumulator name="person-name" as="xs:string?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="person" select="()"/>
<xsl:accumulator-rule match="person/name/text()" select="string()"/>
</xsl:accumulator>
<xsl:accumulator name="person-codes" as="xs:string*" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="persons/person" select="()"/>
<xsl:accumulator-rule match="persons/person/types/type"
select="$value, accumulator-before('person-name') || $sep || string(@code)"/>
</xsl:accumulator>
<xsl:accumulator name="permutations" as="xs:string*" initial-value="()" streamable="yes">
<xsl:accumulator-rule phase="end" match="person"
select="
if (empty($value))
then
for $iv in accumulator-after('person-codes')
return
accumulator-before('department') || $sep || $iv
else
for $v in $value,
$cv in accumulator-after('person-codes')
return
$v || $sep || $cv"
/>
</xsl:accumulator>
<xsl:template match="persons">
<xsl:apply-templates/>
<xsl:value-of select="accumulator-after('permutations')" separator=" "/>
</xsl:template>
</xsl:stylesheet>
person
Martin Honnen
schedule
15.10.2019