9

我写这篇文章是因为我真的碰壁了,无法继续前进。在我的数据库中,我已经像这样转义了 HTML "<p>My name is Freddy and I was":.

我想将其显示为 HTML 或去除我的 XSL 模板中的 HTML 标记。两种解决方案都对我有用,我会选择更快的解决方案。

我在网上阅读了几篇文章,但找不到解决方案。我也尝试过禁用输出转义但没有成功。基本上,问题似乎是在 XSL 执行的某个地方,引擎正在将其更改<p>为:<p>.

它正在转换&&. 如果有帮助,这是我的 XSL 代码。我尝试了几种在顶部有和没有输出标签的组合。

任何帮助将不胜感激。提前致谢。

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

  <xsl:output method="html" omit-xml-declaration="yes"/>

  <xsl:template match="DocumentElement">
    <div>
      <xsl:attribute name="id">mySlides</xsl:attribute>
      <xsl:apply-templates>
        <xsl:with-param name="templatenumber" select="0"/>
      </xsl:apply-templates>
    </div>

    <div>
      <xsl:attribute name="id">myController</xsl:attribute>
      <xsl:apply-templates>
        <xsl:with-param name="templatenumber" select="1"/>
      </xsl:apply-templates>
    </div>
  </xsl:template>

  <xsl:template match="DocumentElement/QueryResults">
    <xsl:param name="templatenumber">tobereplace</xsl:param>

    <xsl:if test="$templatenumber=0">
      <div>
        <xsl:attribute name="id">myController</xsl:attribute>
        <div>
          <xsl:attribute name="class">article</xsl:attribute>
          <h2>
            <a>
              <xsl:attribute name="class">title</xsl:attribute>
              <xsl:attribute name="title"><xsl:value-of select="Title"/></xsl:attribute>
              <xsl:attribute name="href">/stories/stories-details/articletype/articleview/articleid/<xsl:value-of select="ArticleId"/>/<xsl:value-of select="SEOTitle"/>.aspx</xsl:attribute>
              <xsl:value-of select="Title"/>
            </a>
          </h2>
          <div>
            <xsl:attribute name="style">text-indent: 25px;</xsl:attribute>
            <xsl:attribute name="class">articlesummary</xsl:attribute>
            <xsl:call-template name="removeHtmlTags">
              <xsl:with-param name="html" select="Summary" />
            </xsl:call-template>
          </div>
        </div>
      </div>
    </xsl:if>
    <xsl:if test="$templatenumber=1">
      <div>
        <xsl:attribute name="id">myController</xsl:attribute>
        <span>
          <xsl:attribute name="class">jFlowControl</xsl:attribute>
          aa
        </span>
      </div>
    </xsl:if>
  </xsl:template>

  <xsl:template name="removeHtmlTags">
    <xsl:param name="html"/>
    <xsl:choose>
      <xsl:when test="contains($html, '&lt;')">
        <xsl:value-of select="substring-before($html, '&lt;')"/>
        <!-- Recurse through HTML -->
        <xsl:call-template name="removeHtmlTags">
          <xsl:with-param name="html" select="substring-after($html, '&gt;')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$html"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>
4

4 回答 4

18

基于你有这个HTML 字符串的假设,

<p>My name is Freddy &amp; I was

然后,如果您将其转义并将其存储在数据库中,它将变为:

&lt;p&gt;My name is Freddy &amp;amp; I was

因此,如果您将其作为 XML 检索(没有事先取消转义),结果将

&amp;lt;p&amp;gt;My name is Freddy &amp;amp;amp; I was

<xsl:value-of select="." disable-output-escaping="yes" />会产生:

&lt;p&gt;My name is Freddy &amp;amp; I was

您将获得与数据库中完全相同的内容,但当然您会在输出中看到 HTML 标记。因此,您需要一种机制来执行以下字符串替换:

  • "&amp;lt;"with "&lt;"(有效地更改&lt;<未转义的输出)
  • "&amp;gt;"with "&gt;"(有效地更改&gt;>未转义的输出)
  • "&amp;quot;"with "&quot;"(有效地更改&quot;"未转义的输出)
  • "&amp;amp;"with "&amp;"(有效地更改&amp;&未转义的输出)

从您的 XSL 我推断出以下测试输入 XML:

<DocumentElement>
  <QueryResults>
    <Title>Article 1</Title>
    <ArticleId>1</ArticleId>
    <SEOTitle>Article_1</SEOTitle>
    <Summary>&amp;lt;p&amp;gt;Article 1 summary &amp;amp;amp; description.&amp;lt;/p&amp;gt;</Summary>
  </QueryResults>
  <QueryResults>
    <Title>Article 2</Title>
    <ArticleId>2</ArticleId>
    <SEOTitle>Article_2</SEOTitle>
    <Summary>&amp;lt;p&amp;gt;Article 2 summary &amp;amp;amp; description.&amp;lt;/p&amp;gt;</Summary>
  </QueryResults>
</DocumentElement>

我已经更改了您提供的样式表并实现了这样的替换机制。如果您对其应用以下 XSLT 1.0 模板:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:my="my:namespace"
  exclude-result-prefixes="my"
>

  <xsl:output method="html" omit-xml-declaration="yes"/>

  <my:unescape>
    <my:char literal="&lt;" escaped="&amp;lt;" />
    <my:char literal="&gt;" escaped="&amp;gt;" />
    <my:char literal="&quot;" escaped="&amp;quot;" />
    <my:char literal="&amp;" escaped="&amp;amp;" />
  </my:unescape>

  <xsl:template match="DocumentElement">
    <div id="mySlides">
      <xsl:apply-templates mode="slides" />
    </div>
    <div id="myController">
      <xsl:apply-templates mode="controller" />
    </div>
  </xsl:template>

  <xsl:template match="DocumentElement/QueryResults" mode="slides">
    <div class="article">
      <h2>
        <a class="title" title="{Title}" href="{concat('/stories/stories-details/articletype/articleview/articleid/', ArticleId, '/', SEOTitle, '.aspx')}">
          <xsl:value-of select="Title"/>
        </a>
      </h2>
      <div class="articlesummary" style="text-indent: 25px;">
        <xsl:apply-templates select="document('')/*/my:unescape/my:char[1]">
          <xsl:with-param name="html" select="Summary" />
        </xsl:apply-templates>
      </div>
    </div>
  </xsl:template>

  <xsl:template match="DocumentElement/QueryResults" mode="controller">
    <span class="jFlowControl">
      <xsl:text>aa </xsl:text>
      <xsl:value-of select="Title" />
    </span>
  </xsl:template>

  <xsl:template match="my:char">
    <xsl:param name="html" />
    <xsl:variable name="intermediate">
      <xsl:choose>
        <xsl:when test="following-sibling::my:char">
          <xsl:apply-templates select="following-sibling::my:char[1]">
            <xsl:with-param name="html" select="$html" />
          </xsl:apply-templates>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$html" disable-output-escaping="yes" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:call-template name="unescape">
      <xsl:with-param name="html" select="$intermediate" />
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="unescape">
    <xsl:param name="html" />
    <xsl:choose>
      <xsl:when test="contains($html, @escaped)">
        <xsl:value-of select="substring-before($html, @escaped)" disable-output-escaping="yes"/>
        <xsl:value-of select="@literal" disable-output-escaping="yes" />
        <xsl:call-template name="unescape">
          <xsl:with-param name="html" select="substring-after($html, @escaped)"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$html" disable-output-escaping="yes"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

然后生成此输出 HTML:

<div id="mySlides">
  <div class="article">
    <h2>
      <a class="title" title="Article 1" href="/stories/stories-details/articletype/articleview/articleid/1/Article_1.aspx">Article 1</a>
    </h2>
    <div class="articlesummary" style="text-indent: 25px;">
      <p>Article 1 summary &amp; description.</p>
    </div>
  </div>
  <div class="article">
    <h2>
      <a class="title" title="Article 2" href="/stories/stories-details/articletype/articleview/articleid/2/Article_2.aspx">Article 2</a>
    </h2>
    <div class="articlesummary" style="text-indent: 25px;">
      <p>Article 2 summary &amp; description.</p>
    </div>
  </div>
</div>
<div id="myController">
  <span class="jFlowControl">aa Article 1</span>
  <span class="jFlowControl">aa Article 2</span>
</div>

笔记

  • 使用临时命名空间和嵌入元素 ( <my:unescape>) 创建要替换的字符列表
  • 使用递归来模拟输入中所有受影响字符的迭代替换
  • 使用unescape模板中的隐式上下文来传输当前要替换哪个字符的信息

另外注意:

  • 使用模板模式为相同的输入获得不同的输出(这取代了你的templatenumber参数)
  • 大多数时候不需要<xsl:attribute>元素。它们可以安全地替换为内联符号 ( attributename="{attributevalue}")
  • 使用concat()函数创建 URL

一般来说,将转义的 HTML 存储在数据库中是一个坏主意(更一般地说:将 HTML 存储在数据库中是一个坏主意。)。你让自己遇到各种各样的问题,这就是其中之一。如果您无法更改此设置,我希望该解决方案对您有所帮助。

我不能保证它在所有情况下都做正确的事情,并且它可能会打开安全漏洞(想想 XSS),但处理这个问题不是问题的一部分。无论如何,请考虑自己受到警告。

我现在需要休息。;-)

于 2009-03-15T14:22:55.060 回答
6

您不应该在数据库中存储转义的 HTML。如果您的数据库包含实际的“<”字符,那么“disable-output-escaping”命令将执行您想要的操作。

如果您无法更改数据,那么您必须在执行转换之前取消转义数据。

于 2009-03-14T16:38:20.953 回答
2

将此行添加到您的样式表

<xsl:output method="html" indent="yes" version="4.0"/>
于 2012-01-17T15:56:55.590 回答
1

将 HTML 存储在数据库中是个坏主意

什么?那你应该怎么保存呢?在 XML 文档中,所以无论如何您都必须使用 XSLT?作为 Web 开发人员,我们一直使用 SQL 数据库来存储用户定义的 HTML 数据。只要根据您的目的对其进行了适当的消毒,该方法就没有任何问题。

于 2010-02-01T00:37:08.577 回答