XSL normalize-space()在嵌入式标签周围过于贪婪

时间:2015-01-18 15:11:38

标签: xml xslt

我认为这很简单。这是我的意见。我对其布局没有任何控制权。

<?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>.
...

所以WYSIWYG(不同工具的输出,我无法控制,并将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>&#xa;=</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>&#xa;&#xa;</xsl:text>
        <xsl:apply-templates select="node()"/>
    </xsl:template>
    <xsl:template match="xref">
        <xsl:text disable-output-escaping="yes">&lt;ref&gt;</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">&lt;/ref&gt;</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>.
...

我的WYSIWYG看起来像这样:

生命是adungeon 1 和anabyss 2

换行消失了,但ref标签之前和之后的空格也是如此;这些我想保留。我可以破解它并在我的ref标签之前和之后添加一个空格,但后来我觉得这个丑陋:

生命是地牢 1 和深渊 2

注意 abyss 和句点之间的空格。我尝试了解决方案herehere,但这些只消除了额外的空格;他们对换行没有帮助。

我花了一整天的时间尝试用XSL做这件事,没有运气。然后我花了45分钟写了一个完全符合我想要的javascript。实际的,直接的问题解决了,但对我来说,使用XSL这将是如此困难似乎很奇怪。看起来很简单。有没有办法用XSL做到这一点,还是我需要在应用样式表之前预处理XML?

2 个答案:

答案 0 :(得分:1)

鉴于您使用的是XSLT 2.0版,您可以使用带有replace函数的正则表达式来获取normalize-space()行为的“空格直到单个空格”,而不会获得“并修剪前导和尾随空白”部分。

<xsl:template match="text()">
    <xsl:value-of select="replace(., '\s+', ' ')"/>
</xsl:template>

这会将空格的前导和/或尾随运行压缩到单个空格(与任何内部空格的运行一样),但不会完全删除它们。

另外,您不需要对disable-output-escaping标记使用ref,因为它们在模板内部得到了适当的平衡。刚

<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>

会正常工作。

答案 1 :(得分:0)

你可以在没有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, '&#10;')">
            <xsl:value-of select="substring-before($string, '&#10;')"/>
            <xsl:call-template name="replace">
                <xsl:with-param name="string" select="substring-after($string, '&#10;')"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$string"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

这将删除文字中newline的所有出现。

编辑:然后您可以调用结果上的normalize-space函数来删除多余的空格。