如何修复XSLT以按预期正确地将XML转换为HTML?
我正在使用XSLT将XML转换为HTML XML是:如何修复XSLT以按预期正确地将XML转换为HTML?,xml,xslt,Xml,Xslt,我正在使用XSLT将XML转换为HTML XML是: <PARA> 1050 <EMPH STYLE="min_max"> <EMPH HL="LOW">-50</EMPH> <EMPH HL="HIGH">+50</EMPH> </EMPH> min <EMPH BOLD="0" HL="HIGH" ITAL="0" SMALLCA
<PARA>
1050
<EMPH STYLE="min_max">
<EMPH HL="LOW">-50</EMPH>
<EMPH HL="HIGH">+50</EMPH>
</EMPH>
min
<EMPH BOLD="0" HL="HIGH" ITAL="0" SMALLCAPS="0">-1</EMPH>
</PARA>
1050
-50
+50
闵
-1
如何将输出正确呈现为:
1050-50+50分钟-1
目前我获得了1050分钟-50+50-1
我的XSLT是:
<xsl:template match="PARA">
<xsl:value-of select="text()"/>
<xsl:choose>
<xsl:when test="EMPH">
<xsl:apply-templates select="EMPH"/>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="EMPH">
<xsl:choose>
<xsl:when test="@BOLD=1"><b><xsl:value-of select="."/></b></xsl:when>
<xsl:when test="@HL='HIGH'"><sup><xsl:value-of select="."/></sup></xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
我发现这是可行的:
<xsl:template match="PARA">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="EMPH">
<xsl:choose>
<xsl:when test="@BOLD=1"><b><xsl:value-of select="text()"/></b></xsl:when>
<xsl:when test="@HL='HIGH'"><sup><xsl:value-of select="text()"/></sup></xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
我想知道是否有比
更好的方法来处理EMPH
元素的多个属性,因为这种方法必须将所有组合作为唯一的
检查来处理
例如,我必须将“bold”、“superscript”和“bold and superscript”作为三个不同的子句进行检查。我将尝试使用递归模板处理属性,并在映射中保留从属性名称到HTML元素的映射(在自Saxon 9.8以来支持的XSLT中,您可以使用XPath 3.1映射,但在XSLT 2中,如果您需要使用相当旧的Saxon版本,您当然可以定义一些包含映射名称的XML结构的变量,例如
由于我猜SMALLCAPPS不能用简单的属性到元素名称映射进行转换,因此可能还需要编写更多的模板以允许更大的灵活性,下面使用一个基本模板进行递归处理,其他描述属性转换的更专门的模板用
调用它s至要素:
<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>
最后,进行两步转换可能会更简单,第一步是规范化输入,您必须去除不指示某些特殊HTML样式或包装的任何属性,并将属性转换为规范化元素,然后第二步可以更轻松地使用基于元素的标准应用模板
,以简化将嵌套输入转换为嵌套HTML。那么确切的规则是什么呢?为什么+50
没有转换为+50
?您使用哪个版本的XSLT,哪个XSLT处理器?@MartinHonnen是的,根据我的假设,您是正确的,如果HL=“HIGH”
是上标,那么HL=“LOW”
应该用于下标。然后输出应该类似于1010-50+50min-1
。但我不是为STYLE=“min\u max”这样做的
。我正在使用Saxonica提供的xslt版本2.0和Saxon 9.1.0.8J。感谢您提供了一个漂亮的答案!我正在尝试为我的Saxon 9.1版本降级。我已经定义了映射,但现在我需要弄清楚如何迭代找到的每个属性以应用映射。我没有head()
和tail()
函数。@KevinM,正如我所说,head($seq)
是$seq[1]
或子序列($seq,1,1)
和tail($seq)
是$seq[position()gt 1]
或子序列($seq,2)
。至于映射,假设您有,例如,我已经为XSLT 2解释了“降级”。
<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"/>
<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>