我想将下面的示例代码段转换为多个元素。
<para font="Times" size="12" face="Bold Italic">This is some text.</para>
<para font="Times" size="12" face="Bold">This is some more text.</para>
我想把它转换成这样的东西:
<para>
<font name="Times" size="12">
<b>
<i>This is some text.</i>
</b>
</font>
</para>
<para>
<font name="Times" size="12">
<b>This is some text.</b>
</font>
</para>
有没有办法在不使用所有<xsl:choose>
块的母亲的情况下执行此操作..?以上是具有更多属性和属性值的简单示例。
我正在使用XSLT 1.0(xsltproc)
答案 0 :(得分:1)
我认为你可能仍然会在这里找到 xsl:choose ,将“Bold”和“Italic”等字词映射到“b”和“I”的元素名称
因此,您将从一个与 @face 属性相匹配的模板开始,但是也会有一个名称,因此可以递归调用它,并且还有待处理的'face'值
<xsl:template match="@face" name="face">
<xsl:param name="face" select="." />
您将使用一些简单的字符串处理提取要处理的第一个面名称
<xsl:variable name="facename" select="substring-before(concat($face, ' '), ' ')" />
(这里的concat是允许参数中的单个单词)
然后你可以映射到像这样的元素名称
<xsl:variable name="element">
<xsl:choose>
<xsl:when test="$facename = 'Bold'">b</xsl:when>
<xsl:when test="$facename = 'Italic'">i</xsl:when>
</xsl:choose>
</xsl:variable>
话虽如此,理论上您可以将映射保存在单独的XML文件中,并使用文档功能查找它们。
最后,你会有 xsl:choose 来输出元素(如果找到),或者处理父元素的子元素
<xsl:choose>
<xsl:when test="$element != ''">
<xsl:element name="{$element}">
<xsl:call-template name="face">
<xsl:with-param name="face" select="normalize-space(substring-after($face, $facename))" />
</xsl:call-template>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="../node()" />
</xsl:otherwise>
</xsl:choose>
试试这个XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[@font]">
<xsl:copy>
<font>
<xsl:apply-templates select="@*[name() != 'face']"/>
<xsl:apply-templates select="@face" />
</font>
</xsl:copy>
</xsl:template>
<xsl:template match="@face" name="face">
<xsl:param name="face" select="." />
<xsl:variable name="facename" select="substring-before(concat($face, ' '), ' ')" />
<xsl:variable name="element">
<xsl:choose>
<xsl:when test="$facename = 'Bold'">b</xsl:when>
<xsl:when test="$facename = 'Italic'">i</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$element != ''">
<xsl:element name="{$element}">
<xsl:call-template name="face">
<xsl:with-param name="face" select="normalize-space(substring-after($face, $facename))" />
</xsl:call-template>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="../node()" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
假设@face的值实际上对应于输出中的元素名称(有几个人已对此进行了评论),您可以这样做。
递归命名模板实际上标记了@face
属性的内容以确定嵌套顺序。
<强>样式表强>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:strip-space elements="*"/>
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="para">
<xsl:copy>
<font name="{@font}" size="{@size}">
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="@face"/>
<xsl:with-param name="delim" select="' '"/>
</xsl:call-template>
</font>
</xsl:copy>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="string" />
<xsl:param name="delim" />
<xsl:choose>
<xsl:when test="contains($string, $delim)">
<xsl:element name="{substring-before($string,$delim)}">
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="substring-after($string, $delim)" />
<xsl:with-param name="delim" select="$delim" />
</xsl:call-template>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{$string}">
<xsl:apply-templates/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
它处理@face
内的任意数量的令牌。例如,应用于以下输入时:
<?xml version="1.0"?>
<root>
<para font="Times" size="12" face="i b u s">This is some text.</para>
<para font="Times" size="12" face="i b">This is some more text.</para>
</root>
结果是:
<root>
<para>
<font name="Times" size="12">
<i>
<b>
<u>
<s>This is some text.</s>
</u>
</b>
</i>
</font>
</para>
<para>
<font name="Times" size="12">
<i>
<b>This is some more text.</b>
</i>
</font>
</para>
</root>
答案 2 :(得分:0)
我编写了一个包含表格的样式表,您可以在其中添加样式并将其与标记相关联。例如,您可以替换<b>
的{{1}}或添加<strong>
之类的新<tag name="strike" style="Strike-through"/>
。该表可通过$tags
变量访问,并用于选择与face
属性样式名称对应的标记。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my-namespace" exclude-result-prefixes="my" version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<my:styles>
<tag name="b" style="Bold"/>
<tag name="i" style="Italic"/>
<tag name="u" style="Underline"/>
</my:styles>
<xsl:variable name="tags" select="document('')//tag" />
<xsl:template match="/">
<xsl:apply-templates select="document/para" mode="initial" />
</xsl:template>
<xsl:template match="para" mode="initial">
<xsl:copy>
<font name="{@font}" size="{@size}">
<xsl:choose>
<xsl:when test="@face">
<xsl:call-template name="add-style">
<xsl:with-param name="styles" select="concat(@face,' ')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</font>
</xsl:copy>
</xsl:template>
<xsl:template name="add-style">
<xsl:param name="styles"/>
<xsl:param name="current-style" select="substring-before($styles, ' ')"/>
<xsl:message>value:<xsl:value-of select="$styles"/>:</xsl:message>
<xsl:if test="$current-style">
<xsl:element name="{$tags[@style = $current-style]/@name}">
<xsl:call-template name="add-style">
<xsl:with-param name="styles" select="substring-after($styles, ' ')"/>
</xsl:call-template>
<xsl:if test="not(contains(substring-after($styles, ' '), ' '))">
<xsl:value-of select="." />
</xsl:if>
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
如果您将此作为输入:
<document>
<para font="Times" size="12" face="Bold Italic">This is some text.</para>
<para font="Times" size="12" face="Bold">This is some more text.</para>
<para font="Times" size="12" face="Italic Bold Underline">This is some text 3.</para>
<para font="Times" size="12" face="Italic">This is some more text 4.</para>
<para font="Times" size="12">This is some more text 4.</para>
</document>
你得到这个结果:
<para>
<font name="Times" size="12">
<b>
<i>This is some text.</i>
</b>
</font>
</para>
<para>
<font name="Times" size="12">
<b>This is some more text.</b>
</font>
</para>
<para>
<font name="Times" size="12">
<i>
<b>
<u>This is some text 3.</u>
</b>
</i>
</font>
</para>
<para>
<font name="Times" size="12">
<i>This is some more text 4.</i>
</font>
</para>
<para>
<font name="Times" size="12">This is some more text 4.</font>
</para>
我没有使用大的选择,但我必须使用一个来说明face
属性可能不存在的情况。
如果face
属性中有额外的空格,它将失败,因为我使用空格(甚至添加一个)来控制递归。但这可以通过normalize-space()
修正。