Xml'de bir CDATA bitiş belirtecinden çıkmanın bir yolu var mı?


130

]]>Bir xml belgesindeki bir CDATA bölümünde bir CDATA end token ( ) ' dan kaçmanın bir yolu olup olmadığını merak ediyordum . Veya, daha genel olarak, bir CDATA içinde kullanmak için bir kaçış dizisi varsa (ancak varsa, başlangıç ​​veya bitiş belirteçlerinden kurtulmanın muhtemelen mantıklı olacağını tahmin ediyorum).

Temel olarak, bir CDATA içine gömülü bir başlangıç ​​veya bitiş simgeniz olabilir ve ayrıştırıcıya onu yorumlamamasını, sadece başka bir karakter dizisi olarak işlemesini söyleyebilir misiniz?

Muhtemelen, kendinizi bunu yapmaya çalışırken bulursanız, xml yapınızı veya kodunuzu yeniden düzenlemelisiniz, ancak son 3 yıldır günlük olarak xml ile çalışmama ve bu sorunu hiç yaşamamış olmama rağmen, Mümkün olup olmadığını merak ediyordum. Sadece meraktan.

Düzenle:

Html kodlamasını kullanmak dışında ...


4
İlk olarak, yanıtı doğru olarak kabul ediyorum ama şunu not ediyorum: Gömülü CDEnd olarak ayrıştırılmayacağından emin olmak için hiçbir şey birinin CData içinde >olduğu gibi kodlamasını engellemez . Basitçe, beklenmedik olduğu ve verilerin düzgün bir şekilde kodunun çözülebilmesi için İLK olarak kodlanması gerektiği anlamına gelir . Belgenin kullanıcıları da bu CD verilerinin kodunu çözmeyi bilmelidir. CData'nın amacının bir parçası, belirli bir tüketicinin nasıl kullanılacağını anladığı içeriği barındırmak olduğu için duyulmamış bir şey değil. Böyle bir CData'nın herhangi bir genel tüketici tarafından doğru bir şekilde yorumlanması beklenemez. >]]>&&
nix

1
@nix, CDATA metin düğümü içeriğini bildirmek için açık bir yol sağlar, öyle ki içindeki dil simgeleri (]]> dışında) ayrıştırılmaz. Özellikle & gt; bu nedenle, bir CDATA bloğunda, bu sadece dört karakter anlamına gelir, '>' değil. Perspektife koymak gerekirse: xml spesifikasyonunda, tüm metin içeriği "cdata" olarak adlandırılır, sadece bu diziler ("karakter verileri") değil. Ayrıca, belirli tüketici maddelerle ilgili değil. (Yine de böyle bir şey var - işleme talimatları (<? Hedef talimatı?>).
Noktalı virgül

(Bu tür bir şey düğümün orijinal amacına aykırı olsa bile, XML ile uzun ve zorlu savaşta her şeyin adil olduğunu eklemeliyim. Okuyucuların şunu bilmesinin yararlı olabileceğini düşünüyorum <! [CDATA [ ]]> aslında bu amaç için tasarlanmamıştır.)
Noktalı virgül

1
@Semicolon CDATAizin verecek şekilde tasarlanmıştır şey : imlenim olarak tanınmaması gereken karakterleri içeren metin bloklarını için kullanılır ima CDATAo kâr payı da olduğundan çok. Ama aslında, ima ettiğim çift kodlamaya ihtiyacınız yok. ]]&gt;a CDEndiçinde kodlamanın kabul edilebilir bir yoludur CDATA.
nix

Doğru, çift kodlamaya ihtiyacınız olmaz - ancak yine de aracının özel bilgiye sahip olması gerekir, çünkü ayrıştırıcı & gt; olarak>. Demek istediğin bu, sanırım? Ayrıştırdıktan sonra onları uygun gördüğünüz gibi değiştirebileceğinizi mi?
Noktalı virgül

Yanıtlar:


141

Açıktır ki, bu soru tamamen akademiktir. Neyse ki çok kesin bir cevabı var.

Bir CDATA bitiş dizisinden çıkamazsınız. XML spesifikasyonunun üretim kuralı 20 oldukça açıktır:

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

DÜZENLEME: Bu ürün kuralı tam anlamıyla "Bir CData bölümü istediğiniz her şeyi içerebilir ANCAK ']]>'. İstisna yok." Anlamına gelir.

DÜZENLEME2: Aynı bölümde ayrıca:

Bir CDATA bölümünde, yalnızca CDEnd dizesi işaretleme olarak tanınır, böylece sol açılı parantezler ve ve işaretleri değişmez biçimlerinde ortaya çıkabilir; " &lt;" ve " &amp;" kullanılarak bunların kaçması gerekmez (ve kaçılamaz) . CDATA bölümleri iç içe geçemez.

Başka bir deyişle, varlık referansı, işaretleme veya başka herhangi bir yorumlanmış sözdizimi biçimi kullanmak mümkün değildir. Bir CDATA bölümündeki tek çözümlenmiş metin bölümüdür ]]>ve bölümü sonlandırır.

Bu nedenle, ]]>bir CDATA bölümünden çıkmak mümkün değildir .

DÜZENLEME3: Aynı bölümde ayrıca:

2.7 CDATA Bölümleri

[Tanım: CDATA bölümleri, karakter verilerinin oluşabileceği her yerde oluşabilir; aksi takdirde biçimlendirme olarak tanınacak karakterleri içeren metin bloklarının çıkışını yapmak için kullanılırlar. CDATA bölümleri "<! [CDATA [" dizesiyle başlar ve "]]>" dizesiyle biter:]

Daha sonra, tek bir CDATA bölümünün yerine birden çok bitişik CDATA bölümü dahil olmak üzere, karakter verilerinin oluşabileceği herhangi bir yerde bir CDATA bölümü olabilir. Bu, ]]>jetonu bölmenin ve iki parçasını bitişik CDATA bölümlerine koymanın mümkün olmasını sağlar .

örn:

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

şu şekilde yazılmalıdır

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

1
Aslında. Ben akademik bir tip değilim ama soruda da söylediğim gibi, sadece bunu merak ediyorum. Dürüst olmak gerekirse, bu konudaki sözünüzü alacağım, çünkü kural için kullanılan sözdiziminden zar zor bir anlam çıkarabiliyorum. Cevabınız için teşekkürler.
Juan Pablo Califano

39
Bu akademik bir soru değil. CDATA hakkında bir tartışma içeren bir blog gönderisinin RSS beslemesini düşünün.
usr

4
Şu anlamda "akademik" demek istedim: "Tartışması ilginç ama pratik kullanım yok". Genel olarak, CDATA kullanışlı değildir, yalnızca XML metnini serileştirmenin bir yoludur ve anlamsal olarak karakter varlıklarını kullanarak özel karakterlerden kaçmaya eşdeğerdir & lt; ve gt; ve & quot; Karakter varlıkları en basit, en sağlam ve en genel çözümdür, bu nedenle CDATA bölümleri yerine bunu kullanın. Uygun bir XML kitaplığı kullanırsanız (dizelerden XML oluşturmak yerine) bunu düşünmenize bile gerek kalmaz.
ddaa

5
Bunun tarafından az önce ısırıldım çünkü sıkıştırılmış bir Javascript'i şöyle bir <script> etiketine kodlamaya çalışıyorum: <script>/*<![CDATA[*/javascript goes here/*]]>*/</script>ve benim javascript'im sadece bu diziyi içeriyor! Birden fazla CDATA bölümüne bölme fikrini seviyorum ...
NickZoic

3
Bunu gerçek dünyada yaşadım. Wikipedia dökümünü okurken ve başka bir xml dosyası yazarken, Ulusal Ulaşım Güvenliği Kurulu sayfasında bununla karşılaştım . Bilgi kutusundaki bütçe için > 100 milyon ABD Doları (2013) içeriyordu . Okuyucu tarafından [[United States dollar|US$]]&gt;100 million (2013)çevrilen [[United States dollar|US$]]>100 million (2013)ve yazar tarafından çevrilen kaynak xml , metinden kaçmak için CDATA kullanmayı seçti ve başarısız oldu.
Paul Jackson

169

.Pdf dosyasını gizlemek için verilerinizi parçalara ayırmalısınız ]]>.

İşte her şey:

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

İlk <![CDATA[]]]]>sahiptir ]]. İkinci <![CDATA[>]]>sahiptir >.


1
Cevabınız için teşekkürler. Ters eğik çizgi eşdeğeri gibi bir şey arıyordum (C, PHP, Java, vb. Dizeler içinde). Ddaa'nın aktardığı kurala göre öyle bir şey yokmuş gibi görünüyor.
Juan Pablo Califano

28
Kabul edilen cevap bu olmalıdır. Kaçmak biraz belirsiz bir terimdir, ancak bu cevap kesinlikle kaçış ruhuna hitap eder . Ne yazık ki, OP'nin dar kaçış anlayışına uymaması, keyfi olarak ters eğik çizgi karakterinin herhangi bir nedenle dahil edilmesini gerektiriyor.
G-Wiz

5
Yani özetle, kaçış ]]>olarak ]]]]><![CDATA[>. Uzunluğun 5 katı ... vay. Ama sonra, bu alışılmadık bir sekans.
Brilliand

5
Sadece 5x uzunluk komik değil, aynı zamanda CDATA'nın ana kullanım durumu olan kodda alışılmadık bir sıra bile değil! Boşlukları kaldıran sıkıştırılmış JavaScript varsayarsak, "if (alanlar [alan adları [0]]> 3)" gibi dizine göre bir ad dizisinden bir alana ada göre erişiyor olabilirsiniz ve şimdi bunu "if ( alanlar [alan adları [0]]]]> <! [CDATA [> 3) ", CDATA'yı daha okunabilir hale getirmek için kullanma amacını geçersiz kılar, LOL. CDATA sözdizimi ile gelen kişiyi sözlü olarak tokatlamak istiyorum.
Triynko

1
Kaçmak veya daha doğrusu, alıntı yapmak, bağlamı terk etmeden ham metnin anlamının olduğu bir bağlama bir metin eklemek anlamına gelir. Ters eğik çizgilerle ilgisi yoktur. Ve bu cevap, bir yerine iki CDATA bölümü ürettiği için kaçış veya alıntı yapmamaktadır.
ddaa

17

Kaçış yapmazsınız ]]>ama >sonradan ]], 'den ]]><![CDATA[önce ekleyerek kaçarsınız >, bunu tıpkı bir \C / Java / PHP / Perl dizgesinde olduğu gibi, ancak sadece a'dan önce >ve sonra gerekli olduğunu düşünün ]].

BTW,

S.Lott'un cevabı bununla aynı, sadece farklı bir şekilde ifade edildi.


2
Bu ifadeyi tercih ederim. :)
Brilliand

3
Bu şekilde söyleme, insanlara yanlış fikir veriyor. Bu kaçış değil . ]]]]><![CDATA[>sihirli bir sekans değil ]]>. veri olarak karakterlere ]]]]>sahiptir ]]ve ]]>geçerli CDATA bölümünü bitirir. <![CDATA[>yeni bir CDATA bölümü başlatır ve içine koyar >. Aslında bunlar iki farklı unsurdur ve bir DOM ayrıştırıcısı ile çalışırken farklı şekilde ele alınacaktır. Bunun farkında olmalısın. Bunu yapmanın bu yolu , birinci ve ikinci CDATA'ya ]]]><![CDATA[]>koyması dışında benzerdir . Fark kalır. ]]>
Aidiakapi

CDATA içeriği, çıkış karakterli metnin değişmez bir alanı olarak değerlendirildiğinden, fark abartılıyor. Yalnızca DOM ile uğraşırken bu gerçekten önemlidir ve bu düzeyde yine de metin, yorum ve işleme talimat düğümleri gibi diğer görünmez sınırlarla uğraşırsınız.
Beejor

7

S. Lott'un cevabı doğrudur: bitiş etiketini kodlamazsınız, onu birden çok CDATA bölümüne bölersiniz.

Gerçek dünyada bu problemle nasıl karşılaşılır: İçerik yönetim sistemine beslenecek bir XML belgesi oluşturmak için bir XML düzenleyici kullanarak, CDATA bölümleri hakkında bir makale yazmaya çalışın. Bir CDATA bölümüne kod örneklerini gömmekle ilgili olağan hileniz sizi burada yüzüstü bırakacaktır. Bunu nasıl öğrendiğimi tahmin edebilirsiniz.

Ancak çoğu durumda, bununla karşılaşmazsınız ve nedeni şudur: Bir XML belgesinin metnini bir XML öğesinin içeriği olarak saklamak (örneğin) istiyorsanız, muhtemelen bir DOM yöntemi kullanacaksınız, örneğin:

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

Ve DOM oldukça makul bir şekilde <ve> kaçar, bu da belgenize yanlışlıkla bir CDATA bölümü eklemediğiniz anlamına gelir.

Oh, ve bu ilginç:

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);

Bu muhtemelen .NET DOM'un bir ideosenkrasisidir, ancak bu bir istisna oluşturmaz. Buraya istisna atılır:

Console.Write(doc.OuterXml);

Kaputun altında olan şeyin, XmlDocument'in çıktısını üreten bir XmlWriter kullanması ve XmlWriter'ın yazarken iyi biçimlendirmeyi kontrol etmesi olduğunu tahmin ediyorum.


Neredeyse "gerçek dünya" örneğim vardı. Xml'yi genellikle CDATA bölümleri içinde html biçimlendirmesi içeren Flash'tan yüklerim. Bundan kaçmanın bir yolu olması faydalı olabilir sanırım. Ama yine de, bu durumda, CDATA içeriği genellikle geçerli XHTML'dir ve bu nedenle "dış" CDATA'dan tamamen kaçınılabilir.
Juan Pablo Califano

2
CDATA neredeyse her zaman tamamen önlenebilir. CDATA ile çok sık mücadele eden insanların gerçekte ne yapmaya çalıştıklarını ve / veya kullandıkları teknolojinin gerçekten nasıl çalıştığını anlamadıklarını görüyorum.
Robert Rossney

Oh, ayrıca şunu da eklemeliyim ki cevabımda bahsettiğim CMS'nin CDATA kullanmasının tek sebebi onu yazmış olmamdı ve gerçekten ne yapmaya çalıştığımı ve / veya teknolojinin nasıl çalıştığını anlamadım. CDATA kullanmama gerek yoktu.
Robert Rossney

.Net kullanıyorsanız, CDATA'nın önlenebilir olduğuna dair önceki yorum yerinde - sadece içeriği bir dizge olarak yazın ve çerçeve sizin için gerçek dünyadan tüm kaçışları (ve okumayı kaldırmayı) yapacaktır ... ... xmlStream.WriteStartElement ("İşlenmemişHtml"); xmlStream.WriteString (UnprocessedHtml); xmlStream.WriteEndElement ();
Mark Mullin


3

İşte kaçılması gereken başka bir vaka ]]>. Bir XML belgesinin CDATA bloğunun içine tamamen geçerli bir HTML belgesini kaydetmemiz gerektiğini ve HTML kaynağının kendi CDATA bloğuna sahip olduğunu varsayalım. Örneğin:

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

yorum yapılan CDATA son ekinin şu şekilde değiştirilmesi gerekiyor:

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

XML ayrıştırıcı javascript yorum bloklarını nasıl kullanacağını bilemeyeceği için


Bu özel bir durum değil. Sadece burada hala geçerlidir ]]>ile değiştirin ]]]]><![CDATA[>. JavaScript olması veya yorumlanmış olması önemli değildir.
Thomas Grainger

1

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


1

PHP'de daha temiz bir yol:

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

Gerekirse çok baytlı güvenli bir str_replace kullanmayı unutmayın (latin1 olmayan $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;
   }

Olumsuz oyunuzu açıklayabilir misiniz? Bir hata yaptığımı söylemek, nerede olduğunu açıklamak kadar yararlı değil.
Alain Tiemblo

UTF-8 kullanıyorsanız çok baytlı güvenli değiştirme yapmaya gerek yoktur. Yine de olumsuz oy vermedim :)
frodeborli

-1

CDATA'yı kesintiye uğratmanın iyi bir yol olduğunu düşünmüyorum. İşte benim alternatifim ...

]Kaçış dizisi ve ardından karakterinizin onaltılık değeri için kullanın . Gibi içinde &#xhhhh;> =]<unicode value>;

Bu şekilde ]]>, kodlamanızı kaydetmeye çalışırsanız fn, CDATA'da uygun ]005D;]005D;]003E;olanı üretecektir .

Varlık adına göre kaçmaktan daha iyidir, çünkü bunlar uygulamanızda her seferinde çözülmez ve varlıkları ve işareti ile kaçmak için diğer karakterlerden / dizilerden kaçmak için farklı öncelikleriniz olabilir. Sonuç olarak, CDATA içeriği üzerinde daha fazla kontrole sahip olursunuz.


-2

Şu yapıyı görün:

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

İç CDATA etiket (ler) i için ]]]]><![CDATA[>bunun yerine ile kapatmalısınız ]]>. Bu kadar basit.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.