Apakah ada cara untuk menghindari token end CDATA dalam xml?

129

Saya bertanya-tanya apakah ada cara untuk menghindari token end CDATA (]]> ) dalam bagian CDATA dalam dokumen xml. Atau, lebih umum, jika ada beberapa urutan melarikan diri untuk digunakan dalam CDATA (tetapi jika ada, saya kira itu mungkin hanya masuk akal untuk melarikan diri mulai atau mengakhiri token, toh).

Pada dasarnya, dapatkah Anda memiliki token awal atau akhir yang tertanam dalam CDATA dan memberi tahu parser untuk tidak menafsirkannya tetapi memperlakukannya hanya sebagai urutan karakter lain.

Mungkin, Anda harus memperbaiki struktur xml atau kode Anda jika Anda berusaha melakukannya, tetapi meskipun saya telah bekerja dengan xml setiap hari selama sekitar 3 tahun terakhir dan saya tidak pernah mengalami masalah ini, Saya bertanya-tanya apakah itu mungkin. Hanya karena penasaran.

Edit:

Selain menggunakan pengodean html ...

Juan Pablo Califano
sumber
4
Pertama, saya menerima jawaban sebagai benar tetapi perhatikan: Tidak ada yang menghalangi seseorang dari penyandian >seperti >dalam CData untuk memastikan tertanam ]]>tidak akan diuraikan sebagai CDEnd. Ini hanya berarti itu tidak terduga dan itu &harus PERTAMA dikodekan &juga sehingga data dapat diterjemahkan dengan benar. Pengguna dokumen juga harus tahu untuk memecahkan kode CData ini. Ini tidak pernah terdengar sejak bagian dari tujuan CData adalah untuk mengandung konten yang dipahami oleh konsumen tertentu. CData semacam itu tidak bisa diharapkan ditafsirkan dengan benar oleh konsumen generik mana pun.
nix
1
@nix, CDATA hanya menyediakan cara eksplisit untuk mendeklarasikan konten simpul teks sehingga token dalam bahasa (selain]]>) tidak dapat diuraikan. Itu secara khusus tidak memperluas referensi entitas seperti & gt; karena alasan ini, maka dalam blok CDATA, itu berarti keempat karakter, bukan '>'. Untuk meletakkannya dalam perspektif: dalam spec xml, semua konten teks disebut "cdata", bukan hanya urutan ini ("data karakter"). Juga ini bukan tentang agen konsumsi tertentu. (Hal seperti itu memang ada meskipun - instruksi pemrosesan (<? Instruksi target?>)
Titik koma
(Saya harus menambahkan, bahkan jika hal semacam ini berjalan bertentangan dengan maksud asli dari simpul, semuanya adil dalam pertempuran panjang & menyiksa dengan XML. Saya hanya merasa mungkin berguna bagi pembaca untuk mengetahui hal itu <! [CDATA [ ]]> sebenarnya tidak dirancang untuk tujuan itu.)
Semicolon
1
@Semicolon CDATAdirancang untuk memungkinkan apa saja : mereka digunakan untuk keluar dari blok teks yang mengandung karakter yang jika tidak akan dikenali sebagai markup Itu CDATAjuga berarti karena itu juga markup. Tapi, sebenarnya, Anda tidak perlu pengkodean ganda yang saya maksudkan. ]]&gt;adalah cara yang dapat diterima untuk pengkodean CDEnddalam CDATA.
nix
Benar, Anda tidak perlu pengkodean ganda - tetapi Anda masih membutuhkan agen untuk memiliki pengetahuan khusus, karena pengurai tidak akan menguraikan & gt; sebagai>. Tapi itu maksudmu, menurutku? Anda bisa menggantinya sesuai keinginan Anda, setelah parsing?
Titik koma

Jawaban:

141

Jelas, pertanyaan ini murni bersifat akademis. Untungnya, ia memiliki jawaban yang sangat pasti.

Anda tidak dapat menghindari urutan akhir CDATA. Aturan produksi 20 dari spesifikasi XML cukup jelas:

[20]    CData      ::=      (Char* - (Char* ']]>' Char*))

EDIT: Aturan produk ini secara harfiah berarti "Bagian CData dapat berisi apa pun yang Anda inginkan TETAPI urutan ']]>'. Tidak terkecuali.".

EDIT2: Bagian yang sama juga berbunyi:

Di dalam bagian CDATA, hanya string CDEnd yang dikenali sebagai markup, sehingga kurung sudut kiri dan ampersand dapat terjadi dalam bentuk literalnya; mereka tidak perlu (dan tidak bisa) melarikan diri menggunakan " &lt;" dan " &amp;". Bagian CDATA tidak bisa bersarang.

Dengan kata lain, itu tidak mungkin untuk menggunakan referensi entitas, markup, atau bentuk sintaks yang ditafsirkan lainnya. Satu-satunya teks yang diuraikan di dalam bagian CDATA adalah ]]>, dan itu mengakhiri bagian.

Karenanya, tidak mungkin untuk melarikan diri ]]>dalam bagian CDATA.

EDIT3: Bagian yang sama juga berbunyi:

2.7 Bagian CDATA

[Definisi: Bagian CDATA dapat terjadi di mana saja data karakter dapat terjadi; mereka digunakan untuk keluar dari blok teks yang berisi karakter yang seharusnya dikenali sebagai markup. Bagian CDATA dimulai dengan string "<! [CDATA [" dan diakhiri dengan string "]]>":]

Kemudian mungkin ada bagian CDATA di mana saja data karakter dapat terjadi, termasuk beberapa bagian CDATA yang berdekatan di tempat bagian CDATA tunggal. Itu memungkinkan untuk memisahkan ]]>token dan meletakkan kedua bagian itu di bagian CDATA yang berdekatan.

ex:

<![CDATA[Certain tokens like ]]> can be difficult and <invalid>]]> 

harus ditulis sebagai

<![CDATA[Certain tokens like ]]]]><![CDATA[> can be difficult and <valid>]]> 
ddaa
sumber
1
Memang. Yah, saya bukan tipe akademis tetapi seperti yang saya katakan dalam pertanyaan, saya hanya ingin tahu tentang ini. Sejujurnya, saya hanya akan mengambil kata-kata Anda tentang ini, karena saya hampir tidak bisa masuk akal dari sintaks yang digunakan untuk aturan. Terima kasih atas jawaban anda.
Juan Pablo Califano
39
Ini bukan pertanyaan akademis. Pikirkan tentang umpan RSS dari posting blog yang berisi diskusi tentang CDATA.
usr
4
Maksud saya "akademis" dalam arti: "menarik untuk dibahas, tetapi tanpa penggunaan praktis". Secara umum, CDATA tidak berguna, itu hanya cara untuk membuat serialisasi teks XML, dan ini setara dengan melarikan diri karakter khusus menggunakan entitas karakter & lt; & gt; dan & quot ;. Entitas karakter adalah solusi paling sederhana, paling kuat, dan paling umum, jadi gunakan itu daripada bagian CDATA. Jika Anda menggunakan perpustakaan XML yang tepat (alih-alih membangun XML dari string), Anda bahkan tidak perlu memikirkannya.
ddaa
5
Saya baru saja digigit oleh ini karena saya mencoba untuk menyandikan beberapa Javascript terkompresi menjadi tag <script> seperti: <script>/*<![CDATA[*/javascript goes here/*]]>*/</script>dan javascript saya hanya mencakup urutan itu! Saya suka gagasan untuk memecah menjadi beberapa bagian CDATA ...
NickZoic
3
Saya mengalami ini di dunia nyata. Saat membaca dump wikipedia dan menulis file xml lain saya menemukan ini di halaman untuk Dewan Keselamatan Transportasi Nasional . Isinya US $> 100 juta (2013) untuk anggaran dalam infobox. Sumber xml berisi [[United States dollar|US$]]&gt;100 million (2013)yang diterjemahkan [[United States dollar|US$]]>100 million (2013)oleh pembaca dan penulis memilih untuk menggunakan CDATA untuk menghindari teks dan gagal.
Paul Jackson
169

Anda harus memecah data Anda menjadi beberapa bagian untuk menyembunyikannya ]]>.

Ini semuanya:

<![CDATA[]]]]><![CDATA[>]]>

Pertama <![CDATA[]]]]> memiliki ]]. Yang kedua <![CDATA[>]]>memiliki >.

S.Lott
sumber
1
Terima kasih atas jawaban anda. Saya lebih suka mencari sesuatu yang mirip dengan backslash (dalam string dalam C, PHP, Java, dll). Menurut aturan yang dikutip oleh ddaa, sepertinya tidak ada hal seperti itu.
Juan Pablo Califano
28
Ini harus menjadi jawaban yang diterima. Melarikan diri adalah istilah yang agak ambigu, tetapi jawaban ini jelas ditujukan untuk semangat melarikan diri . Sayang sekali itu tidak sesuai dengan konsepsi sempit OP tentang melarikan diri , yang sewenang-wenang mengharuskan karakter backslash untuk terlibat karena alasan tertentu.
G-Wiz
5
Jadi dalam ringkasan, melarikan diri ]]>sebagai ]]]]><![CDATA[>. 5 kali panjangnya ... wow. Tapi kemudian, itu urutan yang tidak biasa.
Brilliand
5
Tidak hanya panjang 5x yang lucu, itu bahkan bukan urutan yang tidak biasa dalam kode, yang merupakan kasus penggunaan utama CDATA! Dengan asumsi JavaScript terkompresi yang menghilangkan spasi, Anda bisa mengakses bidang dengan nama dari array nama dengan indeks, seperti "if (bidang [bidang nama bidang [0]]> 3)" dan sekarang Anda harus mengubahnya ke "jika ( field [fieldnames [0]]]]> <! [CDATA [> 3) ", yang mengalahkan tujuan penggunaan CDATA agar lebih mudah dibaca, LOL. Saya ingin menampar siapa pun yang menggunakan sintaks CDATA secara verbal.
Triynko
1
Melarikan diri, atau lebih tepatnya, mengutip, berarti menyisipkan beberapa teks dalam konteks di mana teks mentah memiliki makna TANPA meninggalkan konteks. Ini tidak ada hubungannya dengan garis miring terbalik. Dan jawaban ini tidak keluar atau mengutip karena menghasilkan dua bagian CDATA, bukan satu.
ddaa
17

Anda tidak melarikan diri ]]>tetapi Anda melarikan diri >setelah ]]dengan memasukkan ]]><![CDATA[sebelum >, pikirkan ini seperti \dalam string C / Java / PHP / Perl tetapi hanya diperlukan sebelum >dan sesudah]] .

BTW,

Jawaban S.Lott sama dengan ini, hanya kata-kata yang berbeda.

Jason Pyeron
sumber
2
Saya lebih suka kata-kata ini. :)
Brilliand
3
Cara mengatakan ini memberi orang ide yang salah. Ini bukan pelarian. ]]]]><![CDATA[>bukan beberapa urutan ajaib untuk ]]>. ]]]]>memiliki ]]karakter sebagai data, dan ]]>mengakhiri bagian CDATA saat ini. <![CDATA[>memulai bagian CDATA baru dan memasukkannya ke >dalam. Mereka sebenarnya adalah dua elemen yang berbeda dan akan diperlakukan secara berbeda ketika bekerja dengan parser DOM. Anda harus sadar akan hal itu. Cara melakukannya mirip dengan ]]]><![CDATA[]>, kecuali menempatkan CDATA ]pertama dan ]>kedua. Perbedaannya tetap.
Aidiakapi
Perbedaannya dibesar-besarkan, karena konten CDATA diperlakukan sebagai rentang literal teks yang diloloskan. Hanya ketika bermain-main dengan DOM, itu benar-benar penting, dan pada tingkat itu Anda tetap berurusan dengan batas-batas tak kasat mata lainnya seperti teks, komentar, dan pemrosesan node instruksi.
Beejor
7

Jawaban S. Lott benar: Anda tidak menyandikan tag akhir, Anda memecahnya di beberapa bagian CDATA.

Cara mengatasi masalah ini di dunia nyata: menggunakan editor XML untuk membuat dokumen XML yang akan dimasukkan ke dalam sistem manajemen konten, cobalah menulis artikel tentang bagian CDATA. Trik biasa Anda menanamkan sampel kode di bagian CDATA akan mengecewakan Anda di sini. Anda bisa bayangkan bagaimana saya belajar ini.

Namun dalam sebagian besar keadaan, Anda tidak akan menemukan ini, dan inilah sebabnya: jika Anda ingin menyimpan (katakanlah) teks dokumen XML sebagai konten elemen XML, Anda mungkin akan menggunakan metode DOM, misalnya:

XmlElement elm = doc.CreateElement("foo");
elm.InnerText = "<[CDATA[[Is this a problem?]]>";

Dan DOM cukup lolos dari <dan>, yang berarti bahwa Anda belum secara tidak sengaja memasukkan bagian CDATA dalam dokumen Anda.

Oh, dan ini menarik:

XmlDocument doc = new XmlDocument();

XmlElement elm = doc.CreateElement("doc");
doc.AppendChild(elm);

string data = "<![[CDATA[This is an embedded CDATA section]]>";
XmlCDataSection cdata = doc.CreateCDataSection(data);
elm.AppendChild(cdata);

Ini mungkin ideosinkrasi dari. NET DOM, tapi itu tidak membuang pengecualian. Pengecualian akan dibuang di sini:

Console.Write(doc.OuterXml);

Saya kira apa yang terjadi di bawah tenda adalah bahwa XmlDocument menggunakan XmlWriter menghasilkan outputnya, dan XmlWriter memeriksa bentuk yang baik ketika ia menulis.

Robert Rossney
sumber
Yah, saya punya contoh yang hampir "dunia nyata". Saya biasanya memuat Xml dari Flash yang berisi marka html di dalam bagian CDATA. Memiliki cara untuk menghindarinya bisa bermanfaat, kurasa. Tetapi bagaimanapun, dalam hal itu, konten CDATA biasanya XHTML yang valid, dan sehingga CDATA "luar" dapat dihindari sama sekali.
Juan Pablo Califano
2
CDATA hampir selalu bisa dihindari sama sekali. Saya menemukan bahwa orang yang berjuang dengan CDATA sangat sering tidak mengerti apa yang sebenarnya mereka coba lakukan dan / atau bagaimana teknologi yang mereka gunakan benar-benar berfungsi.
Robert Rossney
Oh, saya juga harus menambahkan bahwa satu-satunya alasan CMS yang saya singgung dalam jawaban saya menggunakan CDATA adalah karena saya menulisnya, dan saya tidak mengerti apa yang sebenarnya saya coba lakukan dan / atau bagaimana teknologi itu bekerja. Saya tidak perlu menggunakan CDATA.
Robert Rossney
Jika Anda menggunakan .net, komentar sebelumnya tentang CDATA yang dapat dihindari adalah tepat - cukup tulis konten sebagai string dan kerangka kerja akan melakukan semua pelolosan (dan penghapusan saat dibaca) untuk Anda dari dunia nyata .... ... xmlStream.WriteStartElement ("UnprocessedHtml"); xmlStream.WriteString (UnprocessedHtml); xmlStream.WriteEndElement ();
Mark Mullin
6

cukup ganti ]]>dengan]]]]><![CDATA[>

Thomas Grainger
sumber
3

Inilah kasus lain yang ]]>harus diloloskan. Misalkan kita perlu menyimpan dokumen HTML yang benar-benar valid di dalam blok CDATA dari dokumen XML dan sumber HTML kebetulan memiliki blok CDATA itu sendiri. Sebagai contoh:

<htmlSource><![CDATA[ 
    ... html ...
    <script type="text/javascript">
        /* <![CDATA[ */
        -- some working javascript --
        /* ]]> */
    </script>
    ... html ...
]]></htmlSource>

sufiks CDATA yang dikomentari perlu diubah menjadi:

        /* ]]]]><![CDATA[> *//

karena parser XML tidak akan tahu cara menangani blok komentar javascript

Shawn Becker
sumber
Ini bukan kasus khusus. Cukup ganti ]]>dengan yang ]]]]><![CDATA[>masih berlaku di sini. Fakta bahwa itu JavaScript, atau komentar tidak penting.
Thomas Grainger
1

Dalam PHP: '<![CDATA['.implode(explode(']]>', $string), ']]]]><![CDATA[>').']]>'

pengguna2194495
sumber
1

Cara yang lebih bersih di PHP:

   function safeCData($string)
   {
      return '<![CDATA[' . str_replace(']]>', ']]]]><![CDATA[>', $string) . ']]>';
   }

Jangan lupa untuk menggunakan str_replace multibyte-safe jika diperlukan (non latin1 $string):

   function mb_str_replace($search, $replace, $subject, &$count = 0)
   {
      if (!is_array($subject))
      {
         $searches = is_array($search) ? array_values($search) : array ($search);
         $replacements = is_array($replace) ? array_values($replace) : array ($replace);
         $replacements = array_pad($replacements, count($searches), '');
         foreach ($searches as $key => $search)
         {
            $parts = mb_split(preg_quote($search), $subject);
            $count += count($parts) - 1;
            $subject = implode($replacements[$key], $parts);
         }
      }
      else
      {
         foreach ($subject as $key => $value)
         {
            $subject[$key] = mb_str_replace($search, $replace, $value, $count);
         }
      }
      return $subject;
   }
Alain Tiemblo
sumber
Bisakah Anda menjelaskan downvote Anda? Mengatakan bahwa saya melakukan kesalahan tidak berguna seperti menjelaskan di mana itu.
Alain Tiemblo
Tidak perlu melakukan penggantian multibyte yang aman jika Anda menggunakan UTF-8. Saya tidak
mengundurkan diri
-1

Saya tidak berpikir bahwa menginterupsi CDATA adalah cara yang baik untuk pergi. Inilah alternatif saya ...

Gunakan ]untuk urutan pelarian diikuti oleh nilai hex karakter Anda. Seperti di &#xhhhh;=>]<unicode value>;

Dengan cara ini jika Anda mencoba untuk merekam ]]>encode Anda fn akan menghasilkan ]005D;]005D;]003E;yang ok di CDATA.

Ini lebih baik daripada melarikan diri dengan nama entitas, karena itu tidak diterjemahkan setiap kali di aplikasi Anda dan Anda mungkin memiliki prioritas yang berbeda untuk melarikan diri entitas dengan ampersand vs melarikan diri beberapa karakter / urutan lainnya. Akibatnya, Anda memiliki kontrol lebih besar atas konten CDATA.

honzar
sumber
-2

Lihat struktur ini:

<![CDATA[
   <![CDATA[
      <div>Hello World</div>
   ]]]]><![CDATA[>
]]>

Untuk tag CDATA bagian dalam yang harus Anda tutup ]]]]><![CDATA[>bukan ]]>. Sederhana seperti itu.

Chad Kuehn
sumber