【问题标题】:XSL apply template when node is missing缺少节点时 XSL 应用模板
【发布时间】:2014-03-18 21:49:36
【问题描述】:

当我要格式化的节点丢失时,我无法应用模板。我不认为这种解释具有很强的描述性,因此我提供了一个模拟示例来准确说明我的意思。我有以下形式的 XML:

<mains>
    <main>
        <detail1>stuff11</detail1>
        <detail2>stuff12</detail2>
    </main>
    <main>
        <detail1>stuff22</detail1>
    </main>
    <main>
        <detail2>stuff32</detail2>
        <detail3>stuff33</detail3>
    </main>
</mains>

目前,我使用的 XSL 执行以下操作

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/mains">
<table>
    <xsl:apply-templates select="main"/>
</table>
</xsl:template>

<xsl:template match="main">
    <xsl:apply-templates select="detail1"/>
    <xsl:apply-templates select="detail2"/>
    <xsl:apply-templates select="detail3"/>
</xsl:template>

<xsl:template match="detail1">
    <tr>
        <td>
            <xsl:value-of select="."/>
        </td>
    </tr>
</xsl:template>
<xsl:template match="detail2">
    <tr>
        <td>
            <xsl:value-of select="."/>
        </td>
    </tr>
</xsl:template>
<xsl:template match="detail3">
    <tr>
        <td>
            <xsl:value-of select="."/>
        </td>
    </tr>
</xsl:template>

</xsl:stylesheet>

当我应用 XSL 时,我得到以下信息

<?xml version="1.0" encoding="UTF-8"?>
<table>
    <tr><td>stuff11</td></tr>
    <tr><td>stuff12</td></tr>
    <tr><td>stuff21</td></tr>
    <tr><td>stuff32</td></tr>
    <tr><td>stuff33</td></tr>
</table>

这不是我想要的那张桌子。我想要下表

<?xml version="1.0" encoding="UTF-8"?>
<table>
    <tr><td>stuff11</td></tr>
    <tr><td>stuff12</td></tr>
    <tr><td></td></tr>
    <tr><td>stuff21</td></tr>
    <tr><td></td></tr>
    <tr><td></td></tr>
    <tr><td></td></tr>
    <tr><td>stuff32</td></tr>
    <tr><td>stuff33</td></tr>
</table>

为了争论,假设我不能将 &lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt; 标记移到各种详细信息模板之外,它们必须保留在那里。

我知道我可以在每个模板调用上执行 &lt;xsl:if&gt; 并检查 value-of 以确保它存在或不存在,但这感觉很笨拙。是否有设置使apply-templates 即使在节点丢失时也适用?

【问题讨论】:

  • 你确定这是你想要的结果吗?还是您的意思是每个主要的一行,每行有 3 个单元格?
  • 是的,我确定。这是一个例子,它不是我想要的行和列,我正在应用的模板有更多。我只想在缺少的节点上应用模板。或者可以让我获得那种效果而又不会太笨重的东西。 (最佳做法是理想的)
  • "我只想在缺少的节点上应用模板。" 正如您发现的那样,这不会产生任何结果 - 所以您需要重新考虑这个语句:“为了争论,假设我不能将 标签移到各种详细信息模板之外,它们必须留在那里。”。顺便说一句,根据我的经验,一个人为的例子并不能带来好的答案。
  • 相信你明白我想要的效果。我正在应用的模板很复杂,与我面临的问题没有任何关系。根据我的经验,一个简单的问题可以找到一个好的答案,假设答案不是“那么你为什么要首先这样做?”
  • 你的例子的问题在于它导致了既定的思维模式(“哦,他想要一张桌子,我知道如何制作一张桌子”)。无论如何,您的要求中的 something 必须给予,因为不可能同时满足两者,恕我直言。

标签: xml xslt xml-parsing


【解决方案1】:

谈论“不存在的节点”是一厢情愿的想法。没有这样的节点,因此您无法选择它,因此您无法处理它。你需要一个 xsl:choose。

【讨论】:

  • 这是一个简短的回应,但我投了赞成票,因为你实际上解决了我的部分问题。我认为可能有一个设置可以打开此功能。
【解决方案2】:

抱歉,将模板应用于空集确实会产生空结果。

您可以通过向上重构 HTML 包装器来获得您想要的东西——在调用模板中生成 &lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt; 包装器,并让“详细”模板只生成数据内容。

或者,也许只有一个 &lt;xsl:apply-templates select="detail1|detail2|detail3"&gt;,但对其应用 &lt;xsl:sort&gt; 以按所需顺序(1,然后 2,然后 3)生成结果。

【讨论】:

  • 感谢您的响应,但需要将内容保留在模板中,因此无法将其移出。 :-/
【解决方案3】:

想出了一个解决方法。

<xsl:apply-templates select=".">
    <xsl:with-param name="value" select="detail1" />
</xsl:apply-templates>

这将使模板始终被调用,并且我可以在模板中使用xsl:choose 处理丢失的节点,而不是在每个模板调用周围包装xsl:choose

话虽如此,我不确定什么是“最佳实践”,所以如果有人有更好的解决方案,我仍然有兴趣听听。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多