1

我已经习惯了以下变量:

<xsl:variable name="openTag">
<![CDATA[
<div>
]]>
</xsl:variable>

<xsl:variable name="closeTag">
<![CDATA[
</div>
]]>
</xsl:variable>

并通过以下方式实现:

<div class="root">
      <xsl:variable name="ownerid" select="Prp[@name='owner id']/@value" />
      <xsl:variable name="nextownerid" select="preceding-sibling::Node[1]/Prp[@name='owner id']/@value"/>

      <xsl:choose>
        <xsl:when test="$ownerid = '-1'">
          <xsl:copy-of select="$LogText"/>
        </xsl:when>
        <xsl:when test="$ownerid &lt; $nextownerid">
          <xsl:copy-of select="$openTag"/>
          <xsl:copy-of select="$LogText"/>
        </xsl:when>

        <xsl:when test="$ownerid &gt; $nextownerid">
          <xsl:copy-of select="$openTag"/>
          <xsl:copy-of select="$LogText"/>
          <xsl:copy-of select="$closeTag"/>
          <xsl:copy-of select="$closeTag"/>
        </xsl:when>

        <xsl:otherwise>
          <xsl:copy-of select="$openTag"/>
          <xsl:copy-of select="$LogText"/>
          <xsl:copy-of select="$closeTag"/>
        </xsl:otherwise>
      </xsl:choose>
    </div>

问题是div标签作为文本输出,而不是被识别为 HTML 标签。有什么解决方法吗?

4

2 回答 2

9

XSLT 是一种树转换语言:它以一棵节点树作为输入,并生成一棵节点树作为输出。它不读取包含开始和结束标记的词法 XML,也不输出包含开始和结束标记的词法 XML。输入树(通常)由称为 XML 解析器的单独处理器从词法 XML 构造,输出树(通常)由称为 XML 序列化器的单独处理器转换为词法 XML。

disable-output-escaping 是一种 hack,XSLT 处理器借此向串行器发送带外信息。因此,它会在转换器和序列化程序之间产生不希望的紧密耦合,这会阻止您的 XSLT 代码在没有序列化程序的管道中工作(例如,Firefox)。

看起来好像您的逻辑正在尝试解决“组相邻”问题:将具有相同所有者 ID 的所有相邻元素分组。在 XSLT 中有很多更好的方法可以在不使用序列化技巧的情况下解决该问题。在 XSLT 2.0 中:

<xsl:for-each-group select="*" group-adjacent="owner-id">
  <div>
    <xsl:copy-of select="current-group()"/>
  </div>
</xsl:for-each-group>

如果您受限于 XSLT 1.0,这会有点棘手,但并不难:查找“兄弟递归”的示例。

于 2012-05-02T08:01:19.640 回答
1

这就是您实际需要的 XSLT 1.0 转换。

它创建了一个结构良好的 HTML 嵌套树,没有任何disable-output-escaping技巧。

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="html" indent="yes" />

  <!-- index Nodes by their owner ID -->
  <xsl:key name="kNodeByOwnerId" match="Node" use="Prp[@name = 'owner id']/@value" />

  <xsl:template match="/">
    <html>
      <head>
        <style type="text/css"><![CDATA[
          body {
            font-size: 14px;
            font-family: verdana;
            background-color: white;
          }
          div.root {
            padding: 0px 0px 2px 0px;
          }
          div.root div {
            padding: 0px 0px 0px 0px;
            margin-left: 3em;
          }
          div.remark {
            margin-left: 2em;
          }
          img.icon {
            padding-right: 5px;
          }
          span.log {
            font-weight: bold;
          }
          span.log.fail {
            color: red;
          }
          span.log.pass {
            color: green;
          }
          span.log.info {
            color: blue;
          }
        ]]></style>
      </head>
      <body>
        <!-- output "top level" nodes, i.e. those with owner ID -1 -->
        <xsl:apply-templates select="key('kNodeByOwnerId', '-1')">
          <xsl:sort select="substring-after(@name, 'message ')" data-type="number" />
          <xsl:with-param name="containerClass" select="'root'" />
        </xsl:apply-templates>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="Node">
    <xsl:param name="containerClass" select="''" />

    <xsl:variable name="messageClass">
      <xsl:apply-templates select="Prp[@name = 'type']" />
    </xsl:variable>

    <div class="{$containerClass}">
      <img class="icon" src="./{$messageClass}.png" />

      <span class="log {$messageClass}">
        <xsl:value-of select="Prp[@name='message']/@value"/>
      </span>

      <xsl:apply-templates select="Prp[@name = 'remarks']" />

      <!-- output nodes that belong to this node (recursive!) -->
      <xsl:apply-templates select="key('kNodeByOwnerId', Prp[@name = 'id']/@value)">
        <xsl:sort select="substring-after(@name, 'message ')" data-type="number" />
      </xsl:apply-templates>
    </div>
  </xsl:template>

  <xsl:template match="Prp[@name = 'remarks']">
    <xsl:if test="normalize-space(@value) != ''">
      <div class="remark">              
        <img class="icon" src="./info.png" />
        <xsl:value-of select="@value"/>              
      </div>
    </xsl:if>
  </xsl:template>

  <xsl:template match="Prp[@name = 'type']">
    <xsl:choose>
      <xsl:when test="@value = '0'">pass</xsl:when>
      <xsl:when test="@value = '4'">info</xsl:when>
      <xsl:otherwise>fail</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

注意使用<xsl:key>. 可以在我的较早答案中找到密钥如何工作的详尽解释。

该代码非常简单明了,因此您应该可以轻松理解它的作用。不要犹豫,问是否有任何不清楚的地方。

我强烈建议将 CSS 代码放入单独的文件中。

于 2012-05-02T14:11:31.953 回答