Về cơ bản câu hỏi ban đầu có thể được chia làm 2 phần:
- Mục tiêu chính/thách thức: nhúng (/ vận chuyển) một định dạng thô mã đoạn (bất kỳ loại mã) trong đánh dấu trang web (để sao chép/dán/chỉnh sửa đơn giản do không có mã vạch /thoát)
- hiển thị chính xác/hiển thị đoạn mã đó (có thể chỉnh sửa) trong trình duyệt
Ngắn (nhưng) mơ hồ Câu trả lời là: bạn không thể, ... nhưng bạn có thể (nhận được rất gần).
(Tôi biết, đó là 3 mâu thuẫn với câu trả lời, vì vậy hãy đọc tiếp ...)
(nhiều thứ tiếng) (x) (ht) ml Markup-ngôn ngữ dựa trên gói (gần như) tất cả mọi thứ giữa bắt đầu/mở và kết thúc/đóng thẻ/ký tự (chuỗi).
Vì vậy, để nhúng bất kỳ loại mã/đoạn thô nào bên trong ngôn ngữ đánh dấu của bạn, người ta sẽ luôn phải thoát/mã hóa mọi phiên bản (bên trong đoạn mã đó) giống với ký tự (hậu quả) sẽ đóng gói phần tử container trong đánh dấu. (Trong bài này tôi sẽ đề cập đến điều này như quy tắc không có 1.)
Hãy suy nghĩ về "some "data" here"
hoặc <i>..close italics with '</i>'-tag</i>
, nơi mà nó là một rõ ràng nên thoát/mã hóa (cái gì đó trong) </i
và "
(hoặc quote- thay đổi container ký tự từ "
đến '
).
Vì vậy, vì quy tắc số 1, bạn không thể 'chỉ' nhúng 'bất kỳ' đoạn mã thô không xác định bên trong đánh dấu.
Vì, nếu người dùng phải thoát/mã hóa ngay cả một ký tự bên trong đoạn mã thô, thì đoạn mã đó sẽ không còn là 'mã nguyên thuần túy' gốc mà bất kỳ ai cũng có thể sao chép/dán/chỉnh sửa trong đánh dấu tài liệu mà không cần suy nghĩ thêm. Nó sẽ dẫn đến đánh dấu bất hợp pháp/bất hợp pháp và Mojibake (chủ yếu) vì các thực thể.
Ngoài ra, nên rằng đoạn mã chứa các ký tự như vậy, bạn muốn vẫn cần một số javascript để 'dịch' rằng ký tự (sequence) từ (và) nó thoát/mã hóa đại diện để hiển thị các đoạn mã đúng trong 'trang web' (để sao chép/dán/chỉnh sửa).
Điều đó đưa chúng ta đến (một số) các kiểu dữ liệu mà ngôn ngữ đánh dấu chỉ định. Những kiểu dữ liệu cơ bản xác định những gì được coi là nhân vật có giá trị và ý nghĩa của chúng (mỗi thẻ, tài sản, vv):
PCDATA
(phân tích phân Character DATA): sẽ mở rộng thực thể và một người phải thoát <
, &
(và >
tùy thuộc vào ngôn ngữ/phiên bản đánh dấu).
Hầu hết các thẻ như body
, div
, pre
, v.v ... nhưng cũng textarea
(cho đến khi HTML5) thuộc loại này.
Vì vậy, không chỉ bạn cần mã hóa tất cả các ký tự đóng của dãy chứa bên trong đoạn mã, bạn cũng phải mã hóa tất cả các ký tự <
, &
(, >
) (tối thiểu).
Không cần phải nói, mã hóa/thoát nhiều ký tự này nằm ngoài phạm vi mục tiêu của việc nhúng đoạn trích thô vào đánh dấu.
'..nhưng một textarea dường như làm việc ...', vâng, hoặc vì các trình duyệt lỗi động cơ cố gắng để làm một cái gì đó ra khỏi nó, hoặc bởi vì HTML5:
RCDATA
(có thể thay thế nhân vật DỮ LIỆU) : sẽ không xử lý các thẻ bên trong văn bản dưới dạng đánh dấu (nhưng vẫn được điều chỉnh theo quy tắc 1), vì vậy, không cần phải mã hóa <
(>
). Các thực thể NHƯNG vẫn được mở rộng, vì vậy chúng và 'mơ hồ ký hiệu' (&
) cần được chăm sóc đặc biệt.
Các hiệnHTML5 spec says the textarea is now a RCDATA
field và (quote):
Các văn bản trong raw text
và RCDATA
yếu tố phải không chứa bất kỳ lần xuất hiện của chuỗi "</"
(U + 003C ít hơn SIGN, U + 002F gạch chéo ở cuối) theo sau là các ký tự phân biệt chữ hoa với tên thẻ là thành phần được theo sau bởi một trong U + 0009 TÍNH NĂNG (tab), U + 000A DÒNG DÒNG (LF), U + 000C MẪU THỨC ĂN (FF), U + TRẢ LẠI TRẢ LÃI 000D (CR), U + 0020 SPACE, U + 003E G ĐĂNG NHẬP ĐĂNG KÝ (>), hoặc U + 002F SOLIDUS (/).
Như vậy không có vấn đề gì, textarea cần một handler dịch thực thể khổng lồ hoặc nó sẽ cuối cùng Mojibake trên thực thể!
CDATA
(Character Data) sẽ không đối xử với thẻ bên trong văn bản như đánh dấu và sẽ không mở rộng các đối tượng.
Vì vậy, miễn là đoạn mã thô không vi phạm quy tắc 1 (không thể có ký tự đóng thùng chứa (chuỗi) bên trong đoạn mã), yêu cầu không khác thoát/mã hóa.
Rõ ràng này nắm để: làm thế nào chúng ta có thể giảm thiểu số ký tự/ký tự chuỗi rằng vẫn cần phải được mã hóa trong nguồn nguyên liệu của đoạn và số lần mà ký tự (sequence) có thể xuất hiện trong một đoạn mã trung bình; cái gì đó cũng quan trọng đối với javascript xử lý bản dịch của các ký tự này (nếu chúng xảy ra).
Vậy 'vùng chứa' có ngữ cảnh CDATA
này là gì?
Hầu hết các thuộc tính giá trị của thẻ là CDATA, vì vậy một có thể (ab) sử dụng thuộc tính giá trị của đầu vào bị ẩn (proof of concept jsfiddle here).
Tuy nhiên (tuân thủ quy tắc 1) điều này tạo ra sự cố mã hóa/thoát với dấu ngoặc kép ("
và '
) trong đoạn thô và một số javascript cần có/dịch và đặt đoạn mã trong phần tử (hiển thị) khác (hoặc chỉ cần cài đặt) nó như là giá trị của vùng văn bản). Bằng cách nào đó điều này đã cho tôi vấn đề với các thực thể trong FF (giống như trong một textarea). Nhưng nó không thực sự quan trọng, vì 'giá' của việc phải thoát/mã hóa các trích dẫn lồng nhau cao hơn một textarea (HTML5) (dấu ngoặc kép khá phổ biến trong mã nguồn ..).
Điều gì về việc cố gắng sử dụng (ab) <![CDATA[<tag>bla & bla</tag>]]>
?
Như Jukka chỉ ra trong câu trả lời mở rộng của mình, điều này sẽ chỉ làm việc trong (hiếm) 'xhtml thực'.
Tôi đã nghĩ đến việc sử dụng thẻ tập lệnh (có hoặc không có trình bao bọc CDATA bên trong thẻ-script) cùng với nhận xét nhiều dòng /* */
kết thúc tốt đoạn mã thô (thẻ tập lệnh có thể có id
và bạn có thể truy cập chúng bằng cách đếm). Nhưng vì điều này rõ ràng là giới thiệu một vấn đề thoát với */
, ]]>
và </script
trong đoạn mã thô, , điều này dường như không phải là giải pháp hoặc là.
Vui lòng đăng các 'thùng chứa' khả thi khác trong các nhận xét cho câu trả lời này.
Nhân tiện, mã hóa hoặc đếm số lượng -
ký tự và cân bằng chúng trong thẻ nhận xét <!-- -->
chỉ là điên cho mục đích này (ngoài quy tắc 1).
Điều này khiến chúng tôi với Jukka K. Korpela's excellent answer: thẻ <xmp>
dường như lựa chọn tốt nhất!
'Đã quên' <xmp>
giữ CDATA
, dành cho mục đích này VÀ thực sự vẫn là in the current HTML 5 spec (và ít nhất là từ HTML3.2); chính xác những gì chúng ta cần! Nó cũng được hỗ trợ rộng rãi, ngay cả trong IE6 (đó là .. cho đến khi nó bị suy thoái tương tự như bảng di chuyển cơ thể).
Lưu ý: như Jukka chỉ ra, điều này sẽ không hoạt động đúng xhtml hoặc polyglot (sẽ coi nó là pre
) và thẻ xmp
vẫn phải tuân thủ quy tắc số 1. Nhưng đó là quy tắc 'duy nhất'.
Hãy xem xét các đánh dấu sau:
<!-- ATTENTION: replace any occurrence of </xmp with </xmp -->
<xmp id="snippet-container">
<div>
<div>this is an example div & holds an xmp tag:<br />
<xmp>
<html><head> <!-- indentation col 0!! -->
<title>My Title</title>
</head><body>
<p>hello world !!</p>
</body></html>
</xmp> <!-- note this encoded/escaped tag -->
</div>
This line is also part of the snippet
</div>
</xmp>
Các codeblok trên minh họa một mảnh liệu đánh dấu nơi <xmp id="snippet-container">
chứa (gần như thô) Mã-đoạn (chứa div>div>xmp>html-document
).
Thông báo thẻ đóng được mã hóa trong đánh dấu này? Để tuân thủ quy tắc số 1, điều này đã được mã hóa/thoát).
Vì vậy, việc nhúng/vận chuyển mã (đôi khi gần như) đã được giải quyết.
Điều gì về hiển thị/hiển thị đoạn mã (và được mã hóa </xmp>
)?
Trình duyệt sẽ (hoặc cần) làm cho đoạn mã (các nội dung bên trong snippet-container
) chính xác theo cách bạn nhìn thấy nó trong codeblock trên (với một số sự khác biệt giữa các trình duyệt hay không đoạn bắt đầu với một dòng trống) .
Đó bao gồm định dạng/thụt đầu dòng, các thực thể (như chuỗi &
), đầy đủ thẻ, bình luận VÀ thẻ đóng mã hóa </xmp>
(giống như nó đã được mã hóa trong đánh dấu). Và tùy thuộc vào trình duyệt (phiên bản) người ta thậm chí có thể thử sử dụng thuộc tính contenteditable="true"
để chỉnh sửa đoạn mã này (tất cả những gì không bật javascript). Làm một việc như textarea.value=xmp.innerHTML
cũng dễ dàng.
Vì vậy, bạn có thể ... nếu đoạn mã không chứa chuỗi ký tự đóng thùng chứa.
Tuy nhiên, nên một đoạn thô chứa đóng nhân vật-tự </xmp
(vì nó là một ví dụ về bản thân XMP hoặc nó có chứa một số regex, vv), bạn phải chấp nhận rằng bạn có để mã hóa/thoát mà trong đoạn mã thô VÀ cần trình xử lý javascript để dịch mã hóa đó để hiển thị/hiển thị mã hóa </xmp>
như </xmp>
bên trong một textarea
(để chỉnh sửa/đăng) hoặc (ví dụ) pre
chỉ để hiển thị chính xác mã của đoạn mã (hoặc vì vậy có vẻ).
Rất thô sơ jsfiddle example of this here. Lưu ý rằng việc nhận/nhúng/hiển thị/truy xuất-văn bản làm việc hoàn hảo ngay cả trong IE6. Nhưng thiết lập innerHTML
của đã tiết lộ một số hành vi 'thông minh' thú vị trên phần của IE. Có một lưu ý rộng rãi hơn và cách giải quyết khác về điều đó trong fiddle.
Nhưng bây giờ đến kicker quan trọng (một lý do tại sao bạn chỉ nhận được rất gần): Cũng như một ví dụ quá đơn giản, hãy tưởng tượng này thỏ lỗ:
Dành số- liệu snippet:
<!-- remember to translate between </xmp> and </xmp> -->
<xmp>
<p>a paragraph</p>
</xmp>
Vâng, để tuân thủ quy tắc 1, chúng tôi chỉ cần mã hóa các chuỗi </xmp[> \n\r\t\f\/]
này, đúng không?
Vì vậy mà cho chúng ta đánh dấu sau (chỉ sử dụng một mã hóa có thể):
<xmp id="container">
<!-- remember to translate between </xmp> and </xmp> -->
<xmp>
<p>a paragraph</p>
</xmp>
</xmp>
Hmm .. ngươi sẽ tôi nhận được quả cầu pha lê của tôi hay lật một đồng xu? Không, hãy để máy tính nhìn vào đồng hồ hệ thống của nó và nói rằng một số có nguồn gốc là 'ngẫu nhiên'. Vâng, đó là nên làm điều đó ..
Sử dụng một regex như: xmp.innerHTML.replace(/<(?=\/xmp[> \n\r\t\f\/])/gi, '<');
, sẽ dịch 'trở lại' như thế này:
<!-- remember to translate between </xmp> and </xmp> -->
<xmp>
<p>a paragraph</p>
</xmp>
Hmm .. dường như phát ngẫu nhiên này bị phá vỡ ... Houston. .?
Nếu bạn đã bỏ lỡ trò đùa/vấn đề, hãy đọc lại bắt đầu từ 'đoạn mã thô dự định'.
Chờ, tôi biết, chúng tôi (cũng cần phải mã hóa .... thành ....
Ok, quay lại 'dự định đoạn mã thô' và đọc lại.
Bằng cách nào đó tất cả điều này bắt đầu có mùi như the famous hilarious-but-true rexgex-answer on SO, đọc tốt cho những người thông thạo mojibake.
Có thể ai đó biết thuật toán thông minh hoặc giải pháp để khắc phục sự cố này, nhưng tôi giả định rằng mã thô được nhúng sẽ càng ngày càng mơ hồ đến mức bạn nên thoát/mã hóa đúng cách <
, &
của mình (và >
), giống như phần còn lại của thế giới.
Kết luận: (sử dụng xmp
tag)
- nó có thể được thực hiện với đoạn được biết đến mà không chứa bế mạc ký tự chuỗi của container,
- chúng tôi có thể nhận được rất gần với mục tiêu ban đầu với các đoạn trích đã biết chỉ sử dụng 'thoát'/mã hóa 'cấp cơ bản' để chúng tôi không rơi vào rabbithole,
- nhưng cuối cùng là có vẻ như không thể thực hiện điều này một cách đáng tin cậy trong 'môi trường sản xuất' mọi người có thể/nên sao chép/dán/chỉnh sửa các đoạn trích thô 'không xác định' trong khi không biết/hiểu các hàm ý/quy tắc/rabbithole (tùy thuộc vào việc bạn thực hiện xử lý/dịch cho quy tắc 1 và lỗ thỏ).
Hy vọng điều này sẽ hữu ích!
PS: Trong khi tôi đánh giá cao nếu bạn thấy giải thích này hữu ích, tôi nghĩ câu trả lời của Jukka phải là câu trả lời được chấp nhận (không nên lựa chọn/trả lời tốt hơn), vì anh ấy là người nhớ thẻ xmp (mà tôi đã quên mất trong những năm qua và bị 'phân tâm' bởi các phần tử PCDATA thường được ủng hộ như pre
, textarea
, v.v.). Câu trả lời này bắt nguồn từ việc giải thích lý do tại sao bạn không thể làm điều đó (với bất kỳ đoạn trích không xác định nào) và giải thích một số cạm bẫy rõ ràng mà một số câu trả lời khác (bị xóa) bị bỏ qua khi tư vấn cho văn bản nhúng/truyền tải. Tôi đã mở rộng lời giải thích hiện tại của mình để hỗ trợ và giải thích thêm về câu trả lời của Jukka (vì tất cả thực thể đó và CDATA đều khó hơn các trang mã).
Tôi là người duy nhất nghĩ rằng nó đáng kinh ngạc mà chúng ta cần để được như vậy hacky chỉ để thực hiện một nhiệm vụ phổ biến như hiện mã? Tôi thực sự nghĩ rằng một giải pháp cho vấn đề này nên được giải quyết sớm hơn các thẻ HTML mới, sắp tới nhưng không hữu ích. – Nobita