Я бы попытался обработать атрибуты с помощью рекурсивного шаблона и сохранить сопоставление имен атрибутов с HTML элементами на карте (в XSLT, поддерживаемом с Saxon 9.8, вы можете использовать карту XPath 3.1, но в XSLT 2, если вы необходимо использовать эту довольно старую версию Saxon, вы, конечно, можете определить некоторую переменную, содержащую структуру XML, отображающую имена, например, <map><att name="BOLD">b</att></map>
):
<xsl:param name="att-map" as="map(xs:string, xs:string)"
select="map { 'BOLD' : 'b', 'HL' : 'sup', 'ITAL' : 'i' }"/>
<xsl:template match="PARA">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="EMPH[@STYLE = 'min_max']/EMPH">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="EMPH">
<xsl:param name="atts" select="@*[. = ('1', 'HIGH')]"/>
<xsl:choose>
<xsl:when test="head($atts)">
<xsl:element name="{$att-map(local-name(head($atts)))}">
<xsl:apply-templates select=".">
<xsl:with-param name="atts" select="tail($atts)"/>
</xsl:apply-templates>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
https://xsltfiddle.liberty-development.net/jxDjims/1
Я также использовал функции XSLT / XPath 3 head
и tail
, но вы, конечно, можете использовать эквиваленты XPath 2 subsequence
или $atts[1]
и $atts[position() gt 1]
.
Другой вариант - написать шаблоны для атрибутов, которые вы хотите преобразовать:
<xsl:param name="att-map" as="map(xs:string, xs:string)"
select="map { 'BOLD' : 'b', 'HL' : 'sup', 'ITAL' : 'i' }"/>
<xsl:template match="PARA">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="EMPH[@STYLE = 'min_max']/EMPH" priority="5">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="@BOLD[. = 1] | @ITAL[. = 1] | @HL[. = 'HIGH']">
<xsl:param name="atts"/>
<xsl:element name="{$att-map(local-name())}">
<xsl:choose>
<xsl:when test="$atts">
<xsl:apply-templates select="head($atts)">
<xsl:with-param name="atts" select="tail($atts)"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="../node()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
<xsl:template match="EMPH[@*[. = ('1', 'HIGH')]]">
<xsl:apply-templates select="head(@*[. = ('1', 'HIGH')])">
<xsl:with-param name="atts" select="tail(@*[. = ('1', 'HIGH')])"/>
</xsl:apply-templates>
</xsl:template>
<xsl:mode on-no-match="text-only-copy"/>
https://xsltfiddle.liberty-development.net/jxDjims/2
Как я предполагаю, SMALLCAPPS не может быть преобразован с помощью простой атрибут для карты имени элемента, это также может помочь написать еще несколько шаблонов для большей гибкости, ниже используется базовый шаблон для рекурсивной обработки, он вызывается с <xsl:next-match/>
другим, более специализированным шаблоном es, описывающие преобразование атрибутов в элементы:
<xsl:param name="att-map" as="map(xs:string, xs:string)"
select="map { 'BOLD' : 'b', 'HL' : 'sup', 'ITAL' : 'i' }"/>
<xsl:template match="PARA">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="EMPH[@STYLE = 'min_max']/EMPH" priority="5">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="@BOLD[. = 1] | @ITAL[. = 1] | @HL[. = 'HIGH']" mode="attributes-to-elements">
<xsl:element name="{$att-map(local-name())}">
<xsl:next-match/>
</xsl:element>
</xsl:template>
<xsl:template match="@SMALLCAPS[. = 1]" mode="attributes-to-elements">
<span style="font-variant: small-caps">
<xsl:next-match/>
</span>
</xsl:template>
<xsl:template match="@*" mode="attributes-to-elements">
<xsl:param name="remaining-atts" tunnel="yes"/>
<xsl:choose>
<xsl:when test="$remaining-atts">
<xsl:apply-templates select="head($remaining-atts)" mode="#current">
<xsl:with-param name="remaining-atts" tunnel="yes" select="tail($remaining-atts)"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="../node()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="EMPH[@*[. = ('1', 'HIGH')]]">
<xsl:apply-templates select="head(@*[. = ('1', 'HIGH')])" mode="attributes-to-elements">
<xsl:with-param name="remaining-atts" tunnel="yes" select="tail(@*[. = ('1', 'HIGH')])"/>
</xsl:apply-templates>
</xsl:template>
https://xsltfiddle.liberty-development.net/jxDjims/3
В конце, может быть проще выполнить двухэтапное преобразование, которое сначала нормализует input вы должны удалить любые атрибуты, не указывающие на какой-то особый стиль или упаковку HTML, а также преобразовать атрибуты в нормализованные элементы, тогда на втором шаге можно будет проще использовать обычный apply-templates
на основе элементов, чтобы просто преобразовать вложенный ввод в вложенный HTML.