【问题标题】:How to display raw HTML code in PRE or something like it but without escaping it如何在 PRE 或类似内容中显示原始 HTML 代码但不转义
【发布时间】:2013-05-22 22:21:59
【问题描述】:

我想显示原始 HTML。我们都知道必须像这样逃避每个“”:

     <PRE> this is a test  &ltDIV&gt </PRE>

但是,我不想这样做。我想要一种保持 HTML 代码原样的方法(因为它更易于阅读,(在编辑器中)我可能想复制它并自己再次使用它作为实际的 HTML 代码,并且不想必须再次更改或使用相同代码的两个版本,一个已转义,一个未转义。

是否有任何其他比 PRE 更“原始”的环境可能允许这样做?因此,人们不必在每次想要显示一些原始 HTML 代码(可能是在 HTML5 中)时都继续编辑 HTML 并更改所有内容?

类似&lt;REALLY_REALLY_VERBATIM&gt; ...... &lt;/&lt;REALLY_REALLY_VERBATIM&gt;

JavaScript 解决方案在 Firefox 21 上不起作用,这里是截图:

第一个解决方案在火狐上还是不行,这里是截图:

【问题讨论】:

  • 只有我一个人认为我们需要如此 hacky 才能执行像显示代码这样的常见任务是不可思议的吗?我真的认为这个问题的解决方案应该比其他新的、即将推出但不那么有用的 HTML 标记更早得到解决。

标签: html pre


【解决方案1】:

基本上原始问题可以分为两部分:

  • 主要目标/挑战:嵌入(/传输)原始格式的代码-sn-p (任何类型的代码)在网页的标记中(用于简单的复制/粘贴/编辑,因为没有 编码/转义)
  • 在 浏览器

简短的(但)模棱两可的答案是:你不能......但你可以(非常接近)。
(我知道,这是 3 个相互矛盾的答案,所以请继续阅读......)

(polyglot)(x)(ht)ml 标记语言依赖于(几乎)包装开始/开始和结束/结束标签/字符(序列)之间的所有内容。
因此,要将 任何 种原始代码/sn-p 嵌入到您的标记语言中,总是必须转义/编码类似于字符(-sequence)的每个实例(在该 sn-p 内) ) 这将关闭标记中的包装“容器”元素。 (在这篇文章中,我将其称为rule no 1。)
想想"some "data" here"&lt;i&gt;..close italics with '&lt;/i&gt;'-tag&lt;/i&gt;,很明显应该转义/编码(某些内容)&lt;/i"(或将容器的引号字符从" 更改为')。

因此,由于第 1 条规则,您不能“只是”在标记中嵌入“任何”未知的原始代码-sn-p。
因为,如果必须在原始 sn-p 中转义/编码 甚至一个 字符,那么该 sn-p 将不再是任何人都可以复制/粘贴/的原始“纯原始代码”在文档的标记中编辑无需进一步考虑。由于实体,它会导致格式错误/非法标记和Mojibake(主要)。
另外,应该 sn-p 包含这样的字符,你仍然需要一些 javascript 来“翻译”那个字符(序列)从(和到)它被转义/编码表示在“网页”中显示 sn-p 正确(用于复制/粘贴/编辑)。

这将我们带到标记语言指定的(某些)数据类型。这些数据类型本质上定义了什么是“有效字符”及其含义(每个标签、属性等):

  • PCDATA(已解析的字符数据):将扩展实体,必须 转义 &lt;&amp;amp;(和 &gt; 取决于标记语言/版本)。
    大多数标签如bodydivpre 等,还有textarea(直到 HTML5) 属于这种类型。
    因此,您不仅需要对所​​有容器的结束字符序列进行编码 在 sn-p 中,您还必须对所有 &lt;&amp;amp; (,&gt;) 字符进行编码 (至少)。
    不用说,编码/转义这么多字符不在此范围内 目标在标记中嵌入原始 sn-p 的范围。
    '..但是 textarea 似乎可以工作...',是的,要么是因为浏览器 错误引擎试图从中做出一些事情,或者因为 HTML5:

  • RCDATA(可替换字符数据):不会处理内部的标签 文本作为标记(但仍受规则 1 约束),因此不需要 编码&lt; (&gt;)。但是实体仍在扩展,因此它们和“模棱两可” & 符号 (&amp;amp;) 需要特别小心。
    当前 HTML5 spec says the textarea is now a RCDATA field 和(引用):

    raw textRCDATA 元素中的文本不得包含任何 字符串 "&lt;/" 的出现次数 (U+003C LESS-THAN SIGN, U+002F SOLIDUS) 后跟不区分大小写的与标签名称匹配的字符 后跟 U+0009 CHARACTER TABULATION(制表符)之一的元素, U+000A 换行 (LF), U+000C 换页 (FF), U+000D 回车 (CR)、U+0020 空格、U+003E 大于号 (>) 或 U+002F SOLIDUS (/)。

    因此无论如何,textarea 需要一个强大的实体翻译处理程序或 它最终在实体上 Mojibake!

  • CDATA(字符数据)不会将文本内的标签视为 标记,不会展开实体
    所以只要原始的 sn-p 代码不违反规则 1(不能 在 sn-p 中有容器关闭字符(序列),这个 需要没有其他转义/编码。

显然这归结为:我们如何最小化仍然需要在 sn-p 的原始源中编码的字符/字符序列的数量以及该字符(序列)可能出现在平均 sn-p 中的次数;这对于处理这些字符的翻译(如果它们发生)的 javascript 来说也很重要。

那么,CDATA 上下文是什么“容器”?

标签的大多数值属性是 CDATA,因此一个可以(ab)使用隐藏输入的值属性 (proof of concept jsfiddle here)。
但是(符合规则 1)这会在原始 sn-p 中使用嵌套引号("')创建一个编码/转义问题,并且需要一些 javascript 来获取/翻译并在另一个中设置 sn-p(可见) 元素(或简单地将其设置为文本区域的值)。不知何故,这给了我在 FF 中的实体问题(就像在文本区域中一样)。但这并不重要,因为必须转义/编码嵌套引号的“代价”高于(HTML5)文本区域(引号在源代码中很常见..)。

尝试(ab)使用&lt;![CDATA[&lt;tag&gt;bla &amp; bla&lt;/tag&gt;]]&gt;怎么样?
正如 Jukka 在他的扩展答案中指出的那样,这只适用于(罕见的)“真正的 xhtml”。
我想过使用一个脚本标签(在脚本标签内有或没有这样的 CDATA 包装器)和一个包装原始 sn-p 的多行注释 /* */(脚本标签可以有一个 id 和您可以按计数访问它们)。但由于这显然会在原始 sn-p 中引入*/]]&gt;&lt;/script 的转义问题,这似乎也不是一个解决方案

请将 cmets 中的其他可行“容器”发布到此答案。

顺便说一句,编码或计算- 字符的数量并在注释标签&lt;!-- --&gt; 中平衡它们对于这个目的来说是疯狂的(除了规则1)。


这给我们留下了Jukka K. Korpela's excellent answer&lt;xmp&gt; 标签似乎是最好的选择!

“被遗忘”的&lt;xmp&gt; 包含CDATA,旨在用于此目的并且确实仍然是in the current HTML 5 spec(并且至少从HTML3.2 开始就是这样);正是我们需要的!它也得到了广泛的支持,即使在 IE6 中也是如此(也就是说……直到它遭受与滚动表体相同的回归)。
注意:正如 Jukka 所指出的,这在真正的 xhtml 或 polyglot 中不起作用(将其视为pre),xmp 标记仍必须遵守规则 1。但这是“唯一”规则。

考虑以下标记:

<!-- ATTENTION: replace any occurrence of &lt;/xmp with </xmp -->
<xmp id="snippet-container">
<div>
    <div>this is an example div &amp; holds an xmp tag:<br />
        <xmp> 
<html><head>  <!-- indentation col 0!! -->
    <title>My Title</title>
</head><body>
    <p>hello world !!</p>
</body></html>
        &lt;/xmp>  <!-- note this encoded/escaped tag -->
    </div>
    This line is also part of the snippet
</div>
</xmp>

上面的代码块展示了一段原始标记,其中&lt;xmp id="snippet-container"&gt; 包含一个(几乎是原始的)代码-sn-p(包含div&gt;div&gt;xmp&gt;html-document)。
注意到这个标记中的编码结束标签了吗?为了遵守第 1 条规则,这被编码/转义)。

因此,嵌入/传输(有时几乎)原始代码已经/似乎解决了。

如何显示/渲染 sn-p(以及编码的 &amp;lt;/xmp&gt;)?

浏览器将(或应该)渲染 sn-p(snippet-container 中的内容)完全您在上面的代码块中看到的方式(浏览器之间存在一些差异,无论是否sn-p 以空行开头)。
包括格式/缩进、实体(如字符串&amp;amp;)、完整标签、cmets 和编码的结束标签&amp;lt;/xmp&gt;(就像在标记中编码一样)。根据浏览器(版本),甚至可以尝试使用属性contenteditable="true" 来编辑这个sn-p(所有这些都没有启用javascript)。做类似textarea.value=xmp.innerHTML 的事情也很容易。

所以你可以... 如果 sn-p 不包含关闭字符序列的容器。

然而应该一个原始的 sn-p 包含结束字符序列&lt;/xmp(因为它是 xmp 本身的一个示例或者它包含一些正则表达式等( /posting)或(例如)pre 只是为了正确呈现 sn-p 的代码(或者看起来如此)。

一个非常初级的jsfiddle example of this here。请注意,即使在 IE6 中,getting/embedding/displaying/retrieving-to-textarea 也能完美运行。但是设置xmpinnerHTML 揭示了IE 的一些有趣的“智能”行为。小提琴中有更广泛的注释和解决方法。

但现在是重要的踢球者你只能靠得很近的另一个原因): 就像一个过于简单的例子,想象一下这个兔子洞

预期的原始代码-sn-p:

<!-- remember to translate between </xmp> and &lt;/xmp> -->
<xmp>
<p>a paragraph</p>
</xmp>

好吧,为了遵守规则 1,我们“只”需要对那些 &lt;/xmp[&gt; \n\r\t\f\/] 序列进行编码,对吧?

这给了我们以下标记(仅使用一种可能的编码):

<xmp id="container">
<!-- remember to translate between &lt;/xmp> and &lt;/xmp> -->
<xmp>
<p>a paragraph</p>
&lt;/xmp>
</xmp>

嗯.. 我应该拿水晶球还是掷硬币?不,让计算机查看它的系统时钟并声明派生数字是“随机的”。是的,应该这样做..

使用正则表达式 likexmp.innerHTML.replace(/&amp;lt;(?=\/xmp[&gt; \n\r\t\f\/])/gi, '&lt;');,会将“返回”翻译为:

<!-- remember to translate between </xmp> and </xmp> -->
<xmp>
<p>a paragraph</p>
</xmp>

嗯..这个随机生成器似乎坏了...休斯顿..?
如果您错过了笑话/问题,请从“预期的原始代码-sn-p”开始再次阅读。

等等,我知道,我们(也)需要将 .... 编码为 ....
好的,倒回“预期的原始代码-sn-p”并再次阅读。
不知何故,这一切开始闻起来像the famous hilarious-but-true rexgex-answer on SO,对于精通 mojibake 的人来说,这是一本好书。

也许有人知道一个聪明的算法或解决方案来解决这个问题,但我认为嵌入式原始代码会变得越来越模糊,以至于你最好只对你的&lt;进行正确转义/编码, &amp;amp;(和&gt;),就像世界其他地方一样。

结论:(使用xmp标签)

  • 可以使用不包含容器结束字符序列的已知 sn-ps 来完成,
  • 我们可以通过仅使用“基本第一级”转义/编码的已知 sn-ps 非常接近原始目标,因此我们不会陷入困境,
  • 最终似乎无法在“生产环境”中可靠地做到这一点,人们可以/应该在不知道的情况下复制/粘贴/编辑“任何未知”的原始 sn-ps /理解含义/规则/兔子洞(取决于您对规则 1 和兔子洞的处理/翻译实施)。

希望这会有所帮助!

PS: 如果你觉得这个解释有用,我会很感激,但我有点认为 Jukka 的答案应该是公认的答案(不应该出现更好的选择/答案),因为他是记得 xmp 标签的人(我忘了多年来,被pretextarea 等普遍提倡的 PCDATA 元素“分心”。
这个答案起源于解释为什么你不能这样做(使用任何未知的原始 sn-p)并解释一些其他(现已删除)答案在建议文本区域进行嵌入/传输时被忽略的明显缺陷。我已经扩展了我现有的解释,以支持和进一步解释 Jukka 的答案(因为所有实体和 *CDATA 的东西几乎比代码页更难)。

【讨论】:

  • 您所写的内容非常真实且符合规范,但归根结底,OP 是在寻求一种解决方案,该解决方案允许他从元素中复制文本并再次使用它。我在 Chrome、Firefox 和 IE 上测试过,把你提到的所有特殊字符都放到 textarea 内的 HTML 源代码中,它不想破坏。当我将值从 textarea 中复制出来时,它始终与 HTML 源代码中的原始值完全相同。
  • 我将原始问题解释为:“如何在有效 html 源中的元素内包含格式化的原始代码-sn-p”(您的答案也以:&lt;textarea readonly&gt; &lt;REALLY_REALLY_VERBATIM&gt; ...... &lt;/&lt;REALLY_REALLY_VERBATIM&gt; &lt;/textarea&gt; 开头)。即使没有这种限制(因此(正确的)原始源如何进入元素并不重要),如果只是为了防止&lt;/textarea[ &gt;/](当你想到这一点时这是相当明显的),仍然需要一个转义例程例子。
  • PS:我正在调查&lt;![CDATA[&lt;tag&gt;bla &amp; bla&lt;/tag&gt;]]&gt;,但目前我不确定跨标记语言(html、xhtml、xml、多语言等)和服务方法的确切规则.
  • 真正的莎士比亚演讲!电影什么时候上映?
【解决方案2】:

您可以使用xmp 元素,请参阅What was the <XMP> tag used for?。它从一开始就在 HTML 中,并且被所有浏览器支持。规范对它不屑一顾,但 HTML5 CR 仍然对其进行了描述,并要求浏览器支持它(虽然它也告诉作者不要使用它,但它并不能真正阻止你)。

xmp 中的所有内容都被视为这样,在那里没有识别出任何标记(标签或字符引用),出于显而易见的原因,元素本身的结束标签 &lt;/xmp&gt; 除外。

否则xmp 会呈现为pre

当使用“真正的 XHTML”时,即 XHTML 服务于 XML 媒体类型(这种情况很少见),特殊的解析规则不适用,所以 xmp 被视为 pre。但在“真正的 XHTML”中,您可以使用 CDATA 部分,这意味着类似的解析规则。它没有特殊格式,因此您可能希望将其包装在 pre 元素中:

<pre><![CDATA[
This is a demo, tags like <p> will
appear literally.
]]></pre>

我不明白你如何结合 xmp 和 CDATA 部分来实现所谓的多语言标记

【讨论】:

  • +1 太棒了!你知道这个&lt;xmp&gt; 是否也支持多语言等?另外,有没有可以使用&lt;![CDATA[&lt;tag&gt;bla &amp; bla&lt;/tag&gt;]]&gt; 的(x)(ht)ml 版本?
  • xmp 是一个过时的标签。
  • @jlguenego,肯定有这样的声明你知道你需要[citation needed]
  • @JukkaK.Korpela,&lt;xmp&gt; 代表什么?
【解决方案3】:

如果您启用了 jQuery,您可以使用 escapeXml 函数,而不必担心转义箭头或特殊字符。

<pre>
  ${fn:escapeXml('
    <!-- all your code --> 
  ')};
</pre>

【讨论】:

    【解决方案4】:
    echo '<pre>' . htmlspecialchars("<div><b>raw HTML</b></div>") . '</pre>';
    

    我想这就是你要找的东西?

    换句话说,在 PHP 中使用 htmlspecialchars()

    【讨论】:

      【解决方案5】:

      @GitaarLAB 和@Jukka 详细说明&lt;xmp&gt; 标签已经过时,但仍然是最好的。当我这样使用它时

      <xmp>
      <div>Lorem ipsum</div>
      <p>Hello</p>
      </xmp>
      

      然后在代码中插入第一个 EOL,它是looks awful

      可以通过删除 EOL 来解决

      <xmp><div>Lorem ipsum</div>
      <p>Hello</p>
      </xmp>
      

      但它在源代码中看起来很糟糕。我曾经用包装&lt;div&gt;解决它,但最近我想出了一个很好的CSS3规则,我希望它也可以帮助某人:

      xmp { margin: 5px 0; padding: 0 5px 5px 5px; background: #CCC; }
      xmp:before { content: ""; display: block; height: 1em; margin: 0 -5px -2em -5px; }
      

      这个looks better

      【讨论】:

        【解决方案6】:

        便宜又愉快的回答:

        <textarea>Some raw content</textarea>
        

        文本区域将逐字处理制表符、多个空格、换行符、换行。 它可以很好地复制和粘贴其有效的 HTML。它还允许用户调整代码框的大小。 你不需要任何 CSS、JS、转义、编码。

        您也可以更改外观和行为。 这是等宽字体,已禁用编辑,字体较小,无边框:

        <textarea
            style="width:100%; font-family: Monospace; font-size:10px; border:0;"
            rows="30" disabled
        >Some raw content</textarea>
        

        这个解决方案可能在语义上不正确。因此,如果您需要,最好选择更复杂的答案。

        【讨论】:

          【解决方案7】:

          xmp 是要走的路,即:

          <xmp>
            # your code...
          </xmp>
          

          【讨论】:

            【解决方案8】:

            &lt;code&gt; 标签是个好方法,因为&lt;xmp&gt;&lt;pre&gt; 标签不支持换行

            echo '<code>' . htmlspecialchars("<div><b>hello world</b></div>") . '</code>';
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-01-20
              • 1970-01-01
              • 1970-01-01
              • 2018-12-26
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多