如何使用已删除的源元素打印XSLT结果文档?

时间:2010-02-09 09:33:38

标签: php xml xslt

我有一个源XHTML文档,其中包含多个名称空间中的元素,我正在将其转换为HTML文档(显然没有名称空间)。在我的XSL模板中,我只匹配XHTML命名空间中的元素,以从结果树中删除非HTML兼容的元素。然而,在输出中,当这些元素消失时,我用来缩进它们的空格仍然是 - 即不相关的CR / LF和标签行。

例如,如果这是我的输入:

<div id="container">
    <svg:svg>
        <svg:foreignObject>
            <img />
        </svg:foreignObject>
    </svg:svg>
</div>

应用转换后,这将是输出:

<div id="container">


            <img />


</div>

虽然所需的输出是这样的:

<div id="container">
    <img />
</div>

使用TransforMiiX(在Firefox本地附加样式表)和libxslt(用PHP附加样式表服务器端)都会发生这种情况,所以我知道这可能是某些XSL参数没有设置的结果,但我试过玩了使用<xsl:output indent="yes|no" />xml:space="default|preserve"<xsl:strip-space elements="foo bar|*" />,一切都无济于事。

这将在服务器端实现,所以如果在原始XSL中无法做到这一点,但有一种方法可以在PHP中实现,我会接受它。

我知道这不是命名空间问题,因为如果删除任何元素,我会得到相同的结果。

2 个答案:

答案 0 :(得分:2)

您看到的空白区域来自源文档。 XSLT默认规则说应该复制文本节点,如果它们是空的则无关紧要。要覆盖默认规则,请包括:

<xsl:template match="text()" />

或者:点击任意<xsl:apply-templates />(或<xsl:apply-templates select="node()" />)并明确指定要将模板应用于哪些子项。如果您的转换部分依赖于标识模板,则可能需要此方法(在这种情况下,文本节点的空模板会适得其反)。

我已经按照Word的方式在您的代码段中标记了“无关紧要”的空格:

<div id="container">¶
····<svg:svg>¶
········<svg:foreignObject>¶
············<img />¶
········</svg:foreignObject>¶
····</svg:svg>¶
</div>

编辑:您也可以像这样修改您的身份模板:

<xsl:template match="node() | @*">
  <xsl:copy>
    <!-- select everything except blank text nodes -->
    <xsl:apply-templates select="
      node()[not(self::text())] | text()[normalize-space() != ''] | @*
    " />
  </xsl:copy>
</xsl:template>

这将删除任何仅空白文本节点(属性值保持不变,它们不是文本节点)。使用<xsl:output indent="yes" />来打印结果。

答案 1 :(得分:2)

您有两种方法可以实现所需的结果:要么修复原始转换以不同方式处理空白,要么按原样保持转换,并添加第二遍以美化输出。如果您的原始转换很复杂,那么我建议使用2遍方法。你不想让你的转换变得更加复杂,或者你会创建一些你无法获得所需结果的极端情况,你将不得不添加更多特殊的案例处理,并可能将错误添加到以前工作的东西等等......

您应该可以通过使用normalize-text()测试空白节点来忽略空白节点。以下是第二次传球的样子。如果你采用1遍方法,代码将与我猜的大致相同。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes" />

    <xsl:template match="text()">
        <xsl:if test="normalize-space(.) != ''">
            <xsl:value-of select="."/>
        </xsl:if>
    </xsl:template>

    <xsl:template match="node()">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>