XSL normalize-space() 对嵌入式标签过于贪婪
XSL normalize-space() is too greedy around embedded tags
我认为这很简单。这是我的意见。我无法控制它的布局。
<?xml version="1.0" encoding="UTF-8"?>
<topic>
<title>The Torments of Hell</title>
<body>
<p>Life is a <xref href="dungeon.xml">dungeon
</xref> and
an <xref href="abyss.xml">abyss</xref>.
</p>
</body>
</topic>
我试图获得的输出:
...
Life is a<ref>[[dungeon|dungeon.xml]]</ref> and an <ref>[[abyss|abyss.xml]]</ref>.
...
所以所见即所得(另一个工具的输出,我无法控制,它将 ref
标签转换为带引用的脚注)看起来像这样:
生活是地牢1也是深渊2.
这是我开始使用的 xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="topic">
<xsl:text>
=</xsl:text>
<xsl:value-of select="title"/>
<xsl:text>=</xsl:text>
<xsl:apply-templates select="body/p"/>
</xsl:template>
<xsl:template match="p">
<xsl:text>

</xsl:text>
<xsl:apply-templates select="node()"/>
</xsl:template>
<xsl:template match="xref">
<xsl:text disable-output-escaping="yes"><ref></xsl:text>
<xsl:text>[[</xsl:text>
<xsl:value-of select="."/>
<xsl:text>|</xsl:text>
<xsl:value-of select="@href"/>
<xsl:text>]]</xsl:text>
<xsl:text disable-output-escaping="yes"></ref></xsl:text>
</xsl:template>
</xsl:stylesheet>
这是我得到的输出:
...
Life is a <ref>[[dungeon|dungeon.xml]]</ref> and
an <ref>[[abyss|abyss.xml]]</ref>.
...
没问题,我将使用 normalize-space
去掉换行符:
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
现在我的输出如下所示:
...
Life is a<ref>[[dungeon|dungeon.xml]]</ref>and an<ref>[[abyss|abyss.xml]]</ref>.
...
我的所见即所得看起来像这样:
生活是地下城1和深渊2。
换行消失了,但是 ref
标签前后的 space 也消失了;这些我想保留。我可以破解它并在我的 ref
标签前后添加一个 space,但后来我得到了这个丑陋的东西:
生活是地牢1和深渊2 .
注意 abyss 和句点之间的 space。我尝试了解决方案 here and here,但这些解决方案只消除了额外的 space;他们对换行没有帮助。
我花了一整天时间尝试使用 XSL 来完成此操作,但没有成功。然后我花了 45 分钟写了一个 javascript ,它完全符合我的要求。实际的、直接的问题解决了,但我觉得奇怪的是,使用 XSL 会如此困难。看起来很简单。有没有一种方法可以使用 XSL 执行此操作,或者我是否需要在应用样式表之前预处理 XML?
您可以在没有 normalize-space
功能的情况下使用模板匹配来摆脱换行符,这里有一个例子:
<xsl:template match="yourText">
<xsl:call-template name="replace">
<xsl:with-param name="string" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="string"/>
<xsl:choose>
<xsl:when test="contains($string, ' ')">
<xsl:value-of select="substring-before($string, ' ')"/>
<xsl:call-template name="replace">
<xsl:with-param name="string" select="substring-after($string, ' ')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
这将删除您文本中出现的所有 newline
。
Edit : 然后你可以在结果上调用 normalize-space
函数来去掉多余的空格。
鉴于您使用的是 XSLT 2.0 版,您可以使用带有 replace
函数的正则表达式来获取 normalize-space()
行为的 "squash runs of whitespace down to a single space" 部分,而无需同时获取 "and trim leading and trailing whitespace"部分。
<xsl:template match="text()">
<xsl:value-of select="replace(., '\s+', ' ')"/>
</xsl:template>
这会将白色 space 的前导 and/or 尾随 运行 压缩为单个 space(与任何 运行 内部白色[一样=27=]) 但不会完全删除它们。
顺便说一句,您不需要对 ref
标签使用 disable-output-escaping
,因为它们在模板中得到了适当的平衡。刚刚
<xsl:template match="xref">
<ref>
<xsl:text>[[</xsl:text>
<xsl:value-of select="."/><!-- or <apply-templates/> -->
<xsl:text>|</xsl:text>
<xsl:value-of select="@href"/>
<xsl:text>]]</xsl:text>
</ref>
</xsl:template>
会很好。
我认为这很简单。这是我的意见。我无法控制它的布局。
<?xml version="1.0" encoding="UTF-8"?>
<topic>
<title>The Torments of Hell</title>
<body>
<p>Life is a <xref href="dungeon.xml">dungeon
</xref> and
an <xref href="abyss.xml">abyss</xref>.
</p>
</body>
</topic>
我试图获得的输出:
...
Life is a<ref>[[dungeon|dungeon.xml]]</ref> and an <ref>[[abyss|abyss.xml]]</ref>.
...
所以所见即所得(另一个工具的输出,我无法控制,它将 ref
标签转换为带引用的脚注)看起来像这样:
生活是地牢1也是深渊2.
这是我开始使用的 xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="topic">
<xsl:text>
=</xsl:text>
<xsl:value-of select="title"/>
<xsl:text>=</xsl:text>
<xsl:apply-templates select="body/p"/>
</xsl:template>
<xsl:template match="p">
<xsl:text>

</xsl:text>
<xsl:apply-templates select="node()"/>
</xsl:template>
<xsl:template match="xref">
<xsl:text disable-output-escaping="yes"><ref></xsl:text>
<xsl:text>[[</xsl:text>
<xsl:value-of select="."/>
<xsl:text>|</xsl:text>
<xsl:value-of select="@href"/>
<xsl:text>]]</xsl:text>
<xsl:text disable-output-escaping="yes"></ref></xsl:text>
</xsl:template>
</xsl:stylesheet>
这是我得到的输出:
...
Life is a <ref>[[dungeon|dungeon.xml]]</ref> and
an <ref>[[abyss|abyss.xml]]</ref>.
...
没问题,我将使用 normalize-space
去掉换行符:
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
现在我的输出如下所示:
...
Life is a<ref>[[dungeon|dungeon.xml]]</ref>and an<ref>[[abyss|abyss.xml]]</ref>.
...
我的所见即所得看起来像这样:
生活是地下城1和深渊2。
换行消失了,但是 ref
标签前后的 space 也消失了;这些我想保留。我可以破解它并在我的 ref
标签前后添加一个 space,但后来我得到了这个丑陋的东西:
生活是地牢1和深渊2 .
注意 abyss 和句点之间的 space。我尝试了解决方案 here and here,但这些解决方案只消除了额外的 space;他们对换行没有帮助。
我花了一整天时间尝试使用 XSL 来完成此操作,但没有成功。然后我花了 45 分钟写了一个 javascript ,它完全符合我的要求。实际的、直接的问题解决了,但我觉得奇怪的是,使用 XSL 会如此困难。看起来很简单。有没有一种方法可以使用 XSL 执行此操作,或者我是否需要在应用样式表之前预处理 XML?
您可以在没有 normalize-space
功能的情况下使用模板匹配来摆脱换行符,这里有一个例子:
<xsl:template match="yourText">
<xsl:call-template name="replace">
<xsl:with-param name="string" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="string"/>
<xsl:choose>
<xsl:when test="contains($string, ' ')">
<xsl:value-of select="substring-before($string, ' ')"/>
<xsl:call-template name="replace">
<xsl:with-param name="string" select="substring-after($string, ' ')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
这将删除您文本中出现的所有 newline
。
Edit : 然后你可以在结果上调用 normalize-space
函数来去掉多余的空格。
鉴于您使用的是 XSLT 2.0 版,您可以使用带有 replace
函数的正则表达式来获取 normalize-space()
行为的 "squash runs of whitespace down to a single space" 部分,而无需同时获取 "and trim leading and trailing whitespace"部分。
<xsl:template match="text()">
<xsl:value-of select="replace(., '\s+', ' ')"/>
</xsl:template>
这会将白色 space 的前导 and/or 尾随 运行 压缩为单个 space(与任何 运行 内部白色[一样=27=]) 但不会完全删除它们。
顺便说一句,您不需要对 ref
标签使用 disable-output-escaping
,因为它们在模板中得到了适当的平衡。刚刚
<xsl:template match="xref">
<ref>
<xsl:text>[[</xsl:text>
<xsl:value-of select="."/><!-- or <apply-templates/> -->
<xsl:text>|</xsl:text>
<xsl:value-of select="@href"/>
<xsl:text>]]</xsl:text>
</ref>
</xsl:template>
会很好。