<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:d="http://www.daisy.org/ns/pipeline/data" xmlns:pf="http://www.daisy.org/ns/pipeline/functions" version="3.0" exclude-result-prefixes="#all"> <xsl:include href="http://www.daisy.org/pipeline/modules/common-utils/generate-id.xsl"/> <xsl:variable name="no-skippable-marker" select="'no-skippable'"/> <xsl:variable name="sentence-ids" select="collection()[2]"/> <xsl:variable name="namespace" select="namespace-uri(/*)"/> <xsl:key name="in-scope" match="*[@skippable]" use="concat(@skippable, @n)"/> <xsl:key name="sentence" match="*[@id]" use="@id"/> <xsl:key name="skippables" match="*" use="@id"/> <xsl:template match="/"> <xsl:variable name="sentences" as="map(xs:string,document-node())"> <xsl:map> <xsl:for-each select="//*[@id][not(@skippable)][key('sentence',@id,$sentence-ids)]"> <xsl:map-entry key="string(@id)"> <xsl:document> <xsl:copy-of select="."/> </xsl:document> </xsl:map-entry> </xsl:for-each> </xsl:map> </xsl:variable> <xsl:variable name="scopes" as="map(xs:string,document-node(element(d:scope)))"> <xsl:map> <xsl:for-each select="map:keys($sentences)"> <xsl:map-entry key="."> <xsl:document> <d:scope> <xsl:apply-templates mode="find-scopes" select="$sentences(.)"/> </d:scope> </xsl:document> </xsl:map-entry> </xsl:for-each> </xsl:map> </xsl:variable> <xsl:variable name="generate-spans-for-scope-entries" as="element()*"> <xsl:for-each select="map:keys($scopes)"> <xsl:for-each select="$scopes(.)/*"> <xsl:if test="*[@skippable!=$no-skippable-marker]"> <xsl:for-each-group select="*" group-adjacent="@skippable"> <xsl:sequence select="."/> </xsl:for-each-group> </xsl:if> </xsl:for-each> </xsl:for-each> </xsl:variable> <xsl:call-template name="pf:next-match-with-generated-ids"> <xsl:with-param name="prefix" select="'id_'"/> <xsl:with-param name="for-elements" select="$generate-spans-for-scope-entries"/> <xsl:with-param name="sentences" tunnel="yes" select="$sentences"/> <xsl:with-param name="scopes" tunnel="yes" select="$scopes"/> </xsl:call-template> </xsl:template> <xsl:template match="@*|node()" mode="#default copy"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="@skippable" mode="#default copy"/> <xsl:template match="*[@id and key('sentence', @id, $sentence-ids)]"> <xsl:param name="sentences" tunnel="yes" as="map(xs:string,document-node())"/> <xsl:param name="scopes" tunnel="yes" as="map(xs:string,document-node(element(d:scope)))"/> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:choose> <xsl:when test="@skippable"> <xsl:copy-of select="node()"/> </xsl:when> <xsl:otherwise> <xsl:variable name="scope" as="document-node(element(d:scope))" select="$scopes(@id)"/> <xsl:choose> <xsl:when test="not($scope/*/*[@skippable != $no-skippable-marker])"> <xsl:copy-of select="node()"/> </xsl:when> <xsl:otherwise> <xsl:variable name="sentence" as="document-node()" select="$sentences(@id)"/> <xsl:for-each-group select="$scope/*/*" group-adjacent="@skippable"> <xsl:if test="position() > 1"> <xsl:apply-templates select="$sentence/*/*" mode="copy-skippable"> <xsl:with-param name="scope" select="$scope"/> <xsl:with-param name="skippable" select="current-grouping-key()"/> <xsl:with-param name="skippable-ancestors" select="key('skippables', current-grouping-key(), $sentence)/ancestor::*"/> </xsl:apply-templates> </xsl:if> <xsl:element name="span" namespace="{$namespace}"> <xsl:call-template name="pf:generate-id"/> <xsl:apply-templates select="$sentence/*/node()" mode="copy-sentence"> <xsl:with-param name="scope" select="$scope"/> <xsl:with-param name="skippable" select="current-grouping-key()"/> </xsl:apply-templates> </xsl:element> </xsl:for-each-group> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:template> <xsl:template match="node()" mode="find-scopes"> <xsl:call-template name="add-scope-entry"> <xsl:with-param name="prev-skippable" select="preceding::*[@skippable][1]"/> </xsl:call-template> <xsl:apply-templates mode="#current"/> </xsl:template> <xsl:template match="*[@skippable]" mode="find-scopes"> <xsl:call-template name="add-scope-entry"> <xsl:with-param name="prev-skippable" select="."/> </xsl:call-template> </xsl:template> <xsl:template name="add-scope-entry"> <xsl:param name="prev-skippable" as="element()?"/> <xsl:variable name="prev-skippable-id" select="if ($prev-skippable) then $prev-skippable/@id else $no-skippable-marker"/> <d:a skippable="{$prev-skippable-id}" n="{generate-id()}"/> <xsl:for-each select="ancestor::*"> <d:a skippable="{$prev-skippable-id}" n="{generate-id(current())}"/> </xsl:for-each> </xsl:template> <xsl:template match="node()" mode="copy-skippable"> <xsl:param name="skippable-ancestors"/> <xsl:param name="scope" as="document-node(element(d:scope))"/> <xsl:param name="skippable"/> <xsl:choose> <xsl:when test="@id[.=$skippable]"> <xsl:copy> <xsl:apply-templates select="@*|node()" mode="copy"/> </xsl:copy> </xsl:when> <xsl:when test="count($skippable-ancestors intersect .) = 1"> <xsl:variable name="id" select="generate-id()"/> <xsl:variable name="scope-entry" select="key('in-scope', concat($skippable, $id), $scope)[1]"/> <xsl:copy> <xsl:apply-templates select="@* except @id"/> <xsl:if test="@id and not($scope-entry/preceding-sibling::*[@n = $id][1])"> <xsl:copy-of select="@id"/> </xsl:if> <xsl:apply-templates select="*" mode="#current"> <xsl:with-param name="skippable-ancestors" select="$skippable-ancestors"/> <xsl:with-param name="scope" select="$scope"/> <xsl:with-param name="skippable" select="$skippable"/> </xsl:apply-templates> </xsl:copy> </xsl:when> </xsl:choose> </xsl:template> <xsl:template match="node()" mode="copy-sentence"> <xsl:param name="scope" as="document-node(element(d:scope))"/> <xsl:param name="skippable"/> <xsl:if test="not(@skippable)"> <xsl:variable name="id" select="generate-id()"/> <xsl:variable name="scope-entry" select="key('in-scope', concat($skippable, $id), $scope)[1]"/> <xsl:if test="$scope-entry"> <xsl:copy> <xsl:apply-templates select="@* except @id"/> <xsl:if test="@id and not($scope-entry/preceding-sibling::*[@n = $id][1])"> <xsl:copy-of select="@id"/> </xsl:if> <xsl:apply-templates mode="#current"> <xsl:with-param name="scope" select="$scope"/> <xsl:with-param name="skippable" select="$skippable"/> </xsl:apply-templates> </xsl:copy> </xsl:if> </xsl:if> </xsl:template> </xsl:stylesheet>