มีวิธีที่จะหลบหนีโทเค็นสิ้นสุด CDATA ใน xml หรือไม่?


129

ฉันสงสัยว่ามีวิธีใดบ้างที่จะหลบหนีโทเค็นสิ้นสุด CDATA ( ]]>) ภายในส่วน CDATA ในเอกสาร xml หรือโดยทั่วไปถ้ามีบาง escape sequences สำหรับใช้ภายใน CDATA (แต่ถ้ามีอยู่ฉันคิดว่ามันคงสมเหตุสมผลที่จะหลีกเลี่ยงโทเค็นเริ่มต้นหรือสิ้นสุดโทเค็น)

โดยพื้นฐานแล้วคุณสามารถมีโทเค็นเริ่มต้นหรือจุดสิ้นสุดที่ฝังอยู่ใน CDATA และบอกให้โปรแกรมแยกวิเคราะห์ไม่ตีความ แต่เพื่อใช้เป็นลำดับอักขระอื่นได้หรือไม่

อาจเป็นไปได้ว่าคุณควรปรับโครงสร้าง xml หรือรหัสของคุณใหม่หากคุณพบว่าตัวเองพยายามทำเช่นนั้น แต่แม้ว่าฉันจะทำงานกับ xml ทุกวันในช่วง 3 ปีที่ผ่านมาและฉันก็ไม่เคยมีปัญหานี้ ฉันสงสัยว่ามันเป็นไปได้ เพิ่งออกมาจากความอยากรู้

แก้ไข:

นอกเหนือจากการใช้การเข้ารหัส html ...


4
ครั้งแรกผมยอมรับคำตอบว่าถูกต้อง แต่หมายเหตุ: ไม่มีอะไรติ๊ใครบางคนจากการเข้ารหัส>เป็น>ภายใน CDATA เพื่อให้แน่ใจว่าการฝังตัว]]>จะไม่สามารถแยกวิเคราะห์เป็น CDEnd มันหมายถึงว่ามันไม่คาดคิดและ&ต้องเข้ารหัสเป็นครั้งแรกเช่น&กันเพื่อให้สามารถถอดรหัสข้อมูลได้อย่างถูกต้อง ผู้ใช้เอกสารต้องรู้ว่าต้องถอดรหัส CData นี้ด้วย มันไม่เคยได้ยินมาก่อนเนื่องจากเป็นส่วนหนึ่งของวัตถุประสงค์ของ CData คือมีเนื้อหาที่ผู้บริโภคเฉพาะเข้าใจวิธีการจัดการ CData เช่นนี้ไม่สามารถคาดการณ์ได้ว่าจะถูกตีความอย่างถูกต้องโดยผู้บริโภคทั่วไป
ระวัง

1
@nix, CDATA ให้วิธีการที่ชัดเจนในการประกาศเนื้อหาโหนดข้อความเช่นภาษาโทเค็นภายใน (นอกเหนือจาก]]>) ไม่ได้รับการแยกวิเคราะห์ โดยเฉพาะจะไม่ขยายการอ้างอิงเอนทิตีเช่น & gt; ด้วยเหตุนี้ในบล็อก CDATA นั่นหมายถึงตัวละครทั้งสี่ไม่ใช่ไม่ใช่ '>' หากต้องการวางไว้ในมุมมอง: ในข้อมูลจำเพาะ xml เนื้อหาข้อความทั้งหมดจะถูกเรียกว่า "cdata" ไม่ใช่แค่ลำดับเหล่านี้ ("ข้อมูลตัวอักษร") นอกจากนี้ยังไม่เกี่ยวกับตัวแทนการบริโภคที่เฉพาะเจาะจง (สิ่งนี้มีอยู่จริง - คำสั่งในการประมวลผล (<? เป้าหมายคำสั่ง?>)
เซมิโคลอน

(ฉันควรจะเพิ่มแม้ว่าสิ่งเหล่านี้จะทำงานตรงกันข้ามกับจุดประสงค์ดั้งเดิมของโหนดทุกอย่างยุติธรรมในการต่อสู้ที่ยาวนานและทรมานกับ XML ฉันแค่รู้สึกว่ามันมีประโยชน์สำหรับผู้อ่านที่จะรู้ว่า <! [CDATA [ ]]> ไม่ได้ออกแบบมาเพื่อจุดประสงค์นั้นจริง ๆ )
เซมิโคลอน

1
@Semicolon CDATAถูกออกแบบมาเพื่อให้ทุกสิ่ง : พวกมันถูกใช้เพื่อหลบหนีบล็อกข้อความที่มีตัวอักษรซึ่งจะถูกจดจำว่าเป็นมาร์กอัปซึ่งมีความหมายCDATAเช่นกันเนื่องจากเป็นมาร์กอัป แต่ในความเป็นจริงคุณไม่จำเป็นต้องใช้การเข้ารหัสซ้ำซ้อน ]]&gt;เป็นวิธีที่ยอมรับได้ของการเข้ารหัสภายในCDEnd CDATA
ห้าม

จริงคุณไม่ต้องใช้การเข้ารหัสซ้ำ - แต่คุณยังต้องการตัวแทนที่มีความรู้พิเศษเนื่องจากโปรแกรมแยกวิเคราะห์จะไม่แยกวิเคราะห์ & gt; เป็น> นั่นคือสิ่งที่คุณหมายถึงฉันคิดว่า? ที่คุณสามารถแทนที่พวกเขาในขณะที่คุณเห็นว่าเหมาะสมหลังจากการแยก?
เซมิโคลอน

คำตอบ:


141

เห็นได้ชัดว่าคำถามนี้เป็นเรื่องทางวิชาการอย่างแท้จริง โชคดีที่มันมีคำตอบที่ชัดเจนมาก

คุณไม่สามารถหลบหนีลำดับท้าย CDATA ได้ กฎการผลิต 20 ของข้อกำหนด XML ค่อนข้างชัดเจน:

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

แก้ไข: กฎผลิตภัณฑ์นี้หมายถึงตัวอักษร "ส่วน CData อาจมีสิ่งที่คุณต้องการ แต่ลำดับ ']]>' ไม่มีข้อยกเว้น"

EDIT2: ส่วนเดียวกันยังอ่าน:

ภายในส่วนของ CDATA เฉพาะสายอักขระ CDEnd เท่านั้นที่รับรู้เป็นมาร์กอัปดังนั้นวงเล็บมุมซ้ายและเครื่องหมายแอมเปอร์แซนด์อาจเกิดขึ้นในรูปแบบตัวอักษร พวกเขาไม่ต้องการ (และไม่สามารถ) หนีโดยใช้ " &lt;" และ " &amp;" ส่วน CDATA ไม่สามารถซ้อนกันได้

กล่าวอีกนัยหนึ่งไม่สามารถใช้การอ้างอิงเอนทิตีมาร์กอัปหรือรูปแบบอื่น ๆ ของไวยากรณ์ที่ตีความ ข้อความที่แยกวิเคราะห์เฉพาะในส่วน CDATA คือ]]>และมันจะยุติส่วน

ดังนั้นจึงเป็นไปไม่ได้ที่จะหลบหนี]]>จากหมวด CDATA

EDIT3: ส่วนเดียวกันยังอ่าน:

2.7 ส่วนของ CDATA

[คำจำกัดความ: ส่วน CDATA อาจเกิดขึ้นได้ทุกที่ที่มีข้อมูลตัวอักษร พวกเขาจะใช้เพื่อหลบหนีบล็อกของข้อความที่มีตัวละครซึ่งจะจำได้ว่าเป็นมาร์กอัป ส่วน CDATA เริ่มต้นด้วยสตริง "<! [CDATA [" และลงท้ายด้วยสตริง "]]>":]

จากนั้นอาจมีส่วน CDATA ที่ใดก็ได้ที่อาจมีข้อมูลตัวอักษรรวมถึงส่วน CDATA ที่อยู่ติดกันหลายตำแหน่งแทนที่ส่วน CDATA เดียว ที่ช่วยให้สามารถแยก]]>โทเค็นและวางสองส่วนในส่วน CDATA ที่อยู่ติดกัน

อดีต:

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

ควรเขียนเป็น

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

1
จริง ฉันไม่ใช่คนประเภทวิชาการ แต่อย่างที่ฉันพูดในคำถามฉันแค่อยากรู้เกี่ยวกับสิ่งนี้ พูดตามตรงฉันจะรับฟังคำพูดของคุณเพราะฉันไม่สามารถเข้าใจได้จากไวยากรณ์ที่ใช้สำหรับกฎ ขอบคุณสำหรับคำตอบ.
Juan Pablo Califano

39
นี่ไม่ใช่คำถามเชิงวิชาการ คิดถึงฟีด RSS ของบล็อกโพสต์ที่มีการอภิปรายเกี่ยวกับ CDATA
usr

4
ฉันหมายถึง "นักวิชาการ" ในแง่: "น่าสนใจที่จะพูดคุย แต่ไม่มีประโยชน์" โดยทั่วไป CDATA ไม่มีประโยชน์มันเป็นเพียงวิธีหนึ่งในการทำให้ซีเรียลข้อความ XML เป็นอนุกรมและมีความหมายเทียบเท่ากับการหลีกเลี่ยงอักขระพิเศษโดยใช้อักขระหน่วยงาน & lt; & gt; และ & quot; เอนทิตีของตัวละครเป็นวิธีที่ง่ายที่สุดมีประสิทธิภาพที่สุดและเป็นวิธีแก้ปัญหาทั่วไปดังนั้นให้ใช้วิธีนั้นแทนส่วนของ CDATA ถ้าคุณใช้ไลบรารี XML ที่เหมาะสม (แทนที่จะสร้าง XML จากสายอักขระ) คุณไม่จำเป็นต้องคิด
ddaa

5
ฉันเพิ่งถูกกัดโดยคนนี้เพราะฉันพยายามเข้ารหัสจาวาสคริปต์ที่ถูกบีบอัดบางส่วนให้เป็นแท็ก <script> เช่น: <script>/*<![CDATA[*/javascript goes here/*]]>*/</script>และจาวาสคริปต์ของฉันมีเพียงลำดับนั้น! ฉันชอบความคิดที่จะแยกส่วน CDATA ออกเป็นหลายส่วน ...
NickZoic

3
ฉันพบสิ่งนี้ในโลกแห่งความจริง ขณะที่อ่านการถ่ายโอนข้อมูลวิกิพีเดียและการเขียนไฟล์ xml อื่นผมพบนี้ในหน้าสำหรับคณะกรรมการความปลอดภัยการขนส่งแห่งชาติ มีงบประมาณ $ 100 ล้าน (2013)ในกล่องข้อมูล ซอร์ส xml ที่มี[[United States dollar|US$]]&gt;100 million (2013)ซึ่งแปล[[United States dollar|US$]]>100 million (2013)โดยผู้อ่านและผู้เขียนเลือกใช้ CDATA เพื่อหลีกเลี่ยงข้อความและล้มเหลว
พอลแจ็คสัน

169

]]>คุณจะต้องทำลายข้อมูลของคุณเป็นชิ้นที่จะปกปิด

นี่คือสิ่งทั้งหมด:

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

เป็นครั้งแรกที่มี<![CDATA[]]]]> ]]ประการที่สองมี<![CDATA[>]]>>


1
ขอบคุณสำหรับคำตอบ. ฉันค่อนข้างมองหาสิ่งที่คล้าย backslash (ภายในสตริงใน C, PHP, Java, ฯลฯ ) ตามกฎที่ยกมาโดย ddaa ดูเหมือนว่าไม่มีอะไรแบบนี้
Juan Pablo Califano

28
นี่ควรเป็นคำตอบที่ยอมรับได้ หนีเป็นคำที่คลุมเครือเล็กน้อย แต่คำตอบนี้แน่นอนอยู่จิตวิญญาณของการหลบหนี น่าเสียดายที่มันไม่สอดคล้องกับแนวคิดการหลบหนีแคบ ๆ ของ OP ซึ่งโดยพลการนั้นต้องการอักขระแบ็กสแลชที่เกี่ยวข้องด้วยเหตุผลบางประการ
G-Wiz

5
ดังนั้นในการสรุปหนีเป็น]]> ]]]]><![CDATA[>ความยาว 5 เท่า ... ว้าว แต่มันเป็นเรื่องผิดปกติ
Brilliand

5
ไม่เพียง แต่จะมีความยาว 5x เฮฮา แต่ก็ไม่ใช่ลำดับที่ผิดปกติในรหัสซึ่งเป็นกรณีการใช้งานหลักของ CDATA! สมมติว่าจาวาสคริปต์ที่ถูกบีบอัดซึ่งลบช่องว่าง, คุณสามารถเข้าถึงฟิลด์ตามชื่อจากอาเรย์ของชื่อตามดัชนี, เช่น "if (field [fieldnames [0]]> 3)" และตอนนี้คุณต้องเปลี่ยนเป็น "ถ้า ( เขตข้อมูล [fieldnames [0]]]]> <! [CDATA [> 3) "ซึ่งมีจุดประสงค์ในการใช้ CDATA เพื่อให้สามารถอ่านได้ง่ายขึ้น LOL ฉันต้องการจะตบวาจาใครก็ตามที่เกิดขึ้นกับไวยากรณ์ CDATA
Triynko

1
การหลบหนีหรืออย่างถูกต้องมากขึ้นการอ้างถึงหมายถึงการแทรกข้อความบางส่วนในบริบทที่ข้อความดิบมีความหมายโดยไม่ต้องออกจากบริบท มันไม่มีส่วนเกี่ยวข้องกับแบ็กสแลช และคำตอบนี้ไม่ได้หลบหนีหรืออ้างถึงเพราะมันผลิตสองส่วน CDATA แทนที่จะเป็นหนึ่ง
ddaa

17

คุณไม่ได้หลบหนี]]>แต่คุณหนี>หลัง]]โดยการใส่]]><![CDATA[ก่อนที่จะ>คิดว่านี้เช่นเดียวกับ\ในสาย C / Java / PHP / Perl แต่เฉพาะที่จำเป็นก่อนและหลัง>]]

BTW,

คำตอบของ S.Lott นั้นเหมือนกับคำนี้


2
ฉันชอบถ้อยคำนี้ :)
Brilliand

3
วิธีการบอกว่ามันทำให้คนคิดผิด นี่ไม่ใช่การหลบหนี ไม่ได้เป็นบางขลังสำหรับลำดับ]]]]><![CDATA[> มีอักขระเป็นข้อมูลและสิ้นสุดส่วน CDATA ปัจจุบัน เริ่มส่วน CDATA ใหม่และวางไว้ในนั้น จริงๆแล้วมันเป็นองค์ประกอบที่แตกต่างกันสององค์ประกอบและจะได้รับการปฏิบัติต่างกันเมื่อทำงานกับตัวแยกวิเคราะห์ DOM คุณควรระวังสิ่งนั้น วิธีการทำเช่นนี้คล้ายกับยกเว้นจะใส่ในCDATA ที่หนึ่งและที่สอง ความแตกต่างยังคงอยู่ ]]>]]]]>]]]]><![CDATA[>>]]]><![CDATA[]>]]>
Aidiakapi

ความแตกต่างนั้นเกินความจริงเนื่องจากเนื้อหา CDATA จะถือว่าเป็นข้อความที่มีการยกเว้น เฉพาะเมื่อเล่นกับ DOM เท่านั้นมันสำคัญจริงๆและในระดับนั้นคุณต้องเผชิญกับขอบเขตที่มองไม่เห็นอื่น ๆ เช่นข้อความความคิดเห็นและการประมวลผลโหนดคำสั่ง
Beejor

7

คำตอบของ S. Lott นั้นถูกต้อง: คุณไม่ได้เข้ารหัสแท็กปิดท้าย แต่คุณแบ่งมันออกเป็นหลายส่วนของ CDATA

วิธีแก้ไขปัญหานี้ในโลกแห่งความเป็นจริง: การใช้โปรแกรมแก้ไข XML เพื่อสร้างเอกสาร XML ที่จะถูกป้อนเข้าสู่ระบบการจัดการเนื้อหาลองเขียนบทความเกี่ยวกับส่วนของ CDATA กลอุบายทั่วไปของคุณในการฝังตัวอย่างโค้ดในส่วน CDATA จะทำให้คุณล้มเหลวที่นี่ คุณสามารถจินตนาการได้ว่าฉันเรียนรู้สิ่งนี้อย่างไร

แต่ภายใต้สถานการณ์ส่วนใหญ่คุณจะไม่พบสิ่งนี้และนี่คือสาเหตุ: ถ้าคุณต้องการจัดเก็บ (พูด) ข้อความของเอกสาร XML เป็นเนื้อหาขององค์ประกอบ XML คุณอาจใช้วิธี DOM เช่น:

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

และ DOM ค่อนข้างจะหลบหนีส่วน <และ> ซึ่งหมายความว่าคุณไม่ได้ฝังส่วน CDATA ในเอกสารของคุณโดยไม่ตั้งใจ

โอ้และนี่น่าสนใจ:

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

นี่อาจเป็น ideosyncrasy ของ. NET DOM แต่ไม่ได้มีข้อยกเว้น ข้อยกเว้นได้รับที่นี่:

Console.Write(doc.OuterXml);

ฉันเดาว่าสิ่งที่เกิดขึ้นภายใต้ประทุนคือ XmlDocument ใช้ XmlWriter สร้างเอาต์พุตของมันและ XmlWriter ตรวจสอบว่ามีรูปแบบที่ดีตามที่เขียนหรือไม่


ฉันมีตัวอย่าง "โลกแห่งความจริง" เกือบ ฉันมักจะโหลด Xml จาก Flash ที่มีมาร์กอัป HTML ภายในส่วน CDATA ฉันคิดว่ามีวิธีที่จะหนีมันอาจจะมีประโยชน์ แต่อย่างไรก็ตามในกรณีนั้นเนื้อหา CDATA มักจะเป็น XHTML ที่ถูกต้องและดังนั้น CDATA "outer" จึงสามารถหลีกเลี่ยงได้ทั้งหมด
Juan Pablo Califano

2
CDATA สามารถหลีกเลี่ยงได้เกือบทั้งหมดพร้อมกัน ฉันพบว่าคนที่ต่อสู้กับ CDATA บ่อยมากไม่เข้าใจว่าพวกเขากำลังพยายามทำอะไรจริงๆและ / หรือวิธีที่เทคโนโลยีใช้งานได้จริง
Robert Rossney

โอ้ฉันควรเพิ่มด้วยเหตุผลเดียวที่ CMS ที่ฉันพูดถึงในคำตอบที่ฉันใช้คือ CDATA คือฉันเขียนมันและฉันไม่เข้าใจสิ่งที่ฉันพยายามทำจริงๆและ / หรือวิธีการทำงานของเทคโนโลยี ฉันไม่จำเป็นต้องใช้ CDATA
Robert Rossney

หากคุณใช้. net ความคิดเห็นก่อนหน้าเกี่ยวกับ CDATA ที่สามารถหลีกเลี่ยงได้นั้นเป็นเพียงแค่เขียนเนื้อหาเป็นสตริงและเฟรมเวิร์กจะทำการหลบหนีทั้งหมด (และหลีกเลี่ยงการอ่าน) สำหรับคุณจากโลกแห่งความจริง .... ... xmlStream.WriteStartElement ("UnprocessedHtml"); xmlStream.WriteString (UnprocessedHtml); xmlStream.WriteEndElement ();
Mark Mullin


3

นี่เป็นอีกกรณีที่]]>จำเป็นต้องหลบหนี สมมติว่าเราจำเป็นต้องบันทึกเอกสาร HTML ที่ถูกต้องสมบูรณ์ภายในบล็อก CDATA ของเอกสาร XML และแหล่งที่มา HTML เกิดขึ้นเพื่อให้มีบล็อก CDATA ของตัวเอง ตัวอย่างเช่น:

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

ความต้องการต่อท้าย CDATA ที่ถูกคอมเม้นต์จะต้องเปลี่ยนเป็น:

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

เนื่องจากตัวแยกวิเคราะห์ XML จะไม่ทราบวิธีจัดการกับบล็อกความคิดเห็นจาวาสคริปต์


นี่ไม่ใช่กรณีพิเศษ เพียงแทนที่]]>ด้วย]]]]><![CDATA[>ยังใช้ที่นี่ ความจริงที่ว่ามันเป็น JavaScript หรือแสดงความคิดเห็นไม่สำคัญ
โทมัสเกรนเจอร์


1

วิธีทำความสะอาดใน PHP:

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

อย่าลืมใช้ str_replace multibyte-safe หากจำเป็น (ไม่ใช่ 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;
   }

คุณช่วยอธิบาย downvote ของคุณได้ไหม? การบอกว่าฉันทำผิดพลาดไม่ได้มีประโยชน์เหมือนการอธิบายว่ามันอยู่ที่ไหน
Alain Tiemblo

ไม่จำเป็นต้องทำการเปลี่ยนที่ปลอดภัยหลายไบต์หากคุณใช้ UTF-8 ฉันไม่ได้ลงคะแนนเลย :)
frodeborli

-1

ฉันไม่คิดว่าการขัดจังหวะ CDATA เป็นวิธีที่ดีที่จะไป นี่คือทางเลือกของฉัน ...

ใช้]สำหรับ escape sequence ตามด้วยค่า hex ของตัวละครของคุณ เหมือนใน&#xhhhh; =>]<unicode value>;

วิธีนี้ถ้าคุณพยายามที่จะบันทึก]]>fn เข้ารหัสของคุณจะผลิต]005D;]005D;]003E;ซึ่งเป็น ok ใน CDATA

จะดีกว่าการหลบหนีตามชื่อเอนทิตีเพราะสิ่งเหล่านั้นไม่ได้รับการถอดรหัสทุกครั้งในแอปของคุณและคุณอาจมีลำดับความสำคัญแตกต่างกันสำหรับการหลบหลีกเอนทิตีด้วยเครื่องหมายแอมเปอร์แซนด์ ดังนั้นคุณสามารถควบคุมเนื้อหาของ CDATA ได้มากขึ้น


-2

ดูโครงสร้างนี้:

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

สำหรับแท็ก CDATA ภายใน (s) คุณต้องใกล้ชิดกับแทน]]]]><![CDATA[> ]]>เรียบง่ายเหมือนที่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.