XML에서 CDATA 엔드 토큰을 이스케이프 처리하는 방법이 있습니까?


129

]]>xml 문서의 CDATA 섹션 내에서 CDATA 종료 토큰 ( ) 을 이스케이프 처리하는 방법이 있는지 궁금합니다 . 또는 더 일반적으로 CDATA 내에서 사용하기위한 이스케이프 시퀀스가있는 경우 (존재하는 경우 어쨌든 시작 또는 종료 토큰을 이스케이프하는 것이 합리적이라고 생각합니다).

기본적으로 CDATA에 시작 또는 종료 토큰이 포함되어 파서에게 해석하지 말고 다른 문자 시퀀스로 취급하도록 지시 할 수 있습니다.

아마 당신이 그것을하려고하면 XML 구조 또는 코드를 리팩터링해야하지만, 지난 3 년 동안 매일 xml을 사용해 왔지만이 문제가 없었습니다. 가능한지 궁금했습니다. 그냥 호기심.

편집하다:

HTML 인코딩을 사용하는 것 외에는 ...


4
첫째, 나는 대답을 옳게 받아들이지 만 참고 사항 : 임베디드 가 CDEnd로 구문 분석되지 않도록 CData 내 에서 누군가 인코딩 >을 방해하는 것은 없습니다 . 그것은 단순히 예상치 못한 것을 의미 하며 데이터가 올바르게 디코딩 될 수 있도록 FIRST도 인코딩되어야합니다 . 문서 사용자는이 CData도 해독해야합니다. CData의 목적 중 일부는 특정 소비자가 처리하는 방법을 이해하는 컨텐츠를 포함하는 것이므로 들어 본 적이 없습니다. 이러한 CData는 일반 소비자가 올바르게 해석 할 것으로 기대할 수 없습니다. >]]>&&
nix

1
@nix, CDATA는 (]]> 이외의 언어 토큰이 구문 분석되지 않도록 텍스트 노드 컨텐츠를 선언하는 명시적인 방법을 제공합니다. & gt;와 같은 엔티티 참조를 구체적으로 확장하지 않습니다. 이러한 이유로 CDATA 블록에서 '>'가 아닌 4 개의 문자 만 의미합니다. xml 스펙에서 모든 텍스트 컨텐츠는 이러한 시퀀스 ( "문자 데이터")뿐만 아니라 "cdata"라고합니다. 또한 특정 소비 요원에 관한 것이 아닙니다. (하지만 처리 명령 (<? target instruction?>)이 있습니다
Semicolon

(이러한 종류의 노드가 원래 노드의 의도와 상반되는 경우에도 XML과의 길고 가혹한 싸움에서 모든 것이 공평합니다. 독자가 <! [CDATA [ ]]>는 실제로 그러한 목적으로 설계되지 않았습니다.)
Semicolon

1
@Semicolon을 CDATA할 수 있도록 설계되었다 아무것도 : 그들은 마크 업으로 인식 문자를 포함한 텍스트 블록 탈출하는 데 사용되는 의미 CDATA가 마크 업도 있기 때문에 너무합니다. 그러나 실제로, 당신은 내가 암시 한 이중 인코딩이 필요하지 않습니다. ]]&gt;부호화 수용 수단 CDEnd내에 CDATA.
nix

사실, 이중 인코딩은 필요하지 않습니다.하지만 파서는 구문 분석하지 않기 때문에 에이전트에 특별한 지식이 있어야합니다. & gt; >로. 그래도 그렇게 생각합니다. 구문 분석 후 적합하다고 생각되는대로 교체 할 수 있습니까?
Semicolon

답변:


141

분명히이 질문은 순수한 학문입니다. 다행히도 매우 명확한 답이 있습니다.

CDATA 종료 시퀀스를 이스케이프 할 수 없습니다. XML 사양 의 프로덕션 규칙 20 은 매우 분명합니다.

[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
이것은 학문적 인 질문이 아닙니다. CDATA에 대한 토론이 포함 된 블로그 게시물의 RSS 피드에 대해 생각해보십시오.
usr

4
나는 "학업 적"이라는 의미에서 "논의하기는하지만 실제로는 사용하지 않는다"는 의미였다. 일반적으로 CDATA는 유용하지 않으며 XML 텍스트를 직렬화하는 방법 일 뿐이며 문자 엔터티 & lt; & gt; 및 & quot ;. 문자 엔티티는 가장 단순하고 가장 강력하고 일반적인 솔루션이므로 CDATA 섹션 대신 사용하십시오. 문자열로 XML을 작성하는 대신 적절한 XML 라이브러리를 사용하면 그것에 대해 생각할 필요조차 없습니다.
ddaa

5
압축 된 자바 스크립트를 <script> 태그로 인코딩하려고하기 때문에 이것에 물 렸습니다. <script>/*<![CDATA[*/javascript goes here/*]]>*/</script>내 자바 스크립트에는 그 시퀀스가 ​​포함되어 있습니다! 나는 여러 CDATA 섹션으로 나누는 아이디어를 좋아한다 ...
NickZoic

3
나는 실제 세계에서 이것을 경험했다. Wikipedia 덤프를 읽고 다른 xml 파일을 작성하는 동안 National Transportation Safety Board 페이지에서이 문제가 발생했습니다 . 그것은 포함 된 US $> 만 (2013) 100 인포 박스에서 예산. 독자 [[United States dollar|US$]]&gt;100 million (2013)가 번역 한 소스 xml이 포함 되어 [[United States dollar|US$]]>100 million (2013)있으며, 작가는 CDATA를 사용하여 텍스트를 이스케이프 처리하지 못했습니다.
Paul Jackson

169

은닉하려면 데이터를 여러 조각으로 나눠야합니다 ]]>.

모든 것이 여기 있습니다 :

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

첫 번째 <![CDATA[]]]]>]]입니다. 두 번째 <![CDATA[>]]>>입니다.


1
답변 주셔서 감사합니다. 오히려 백 슬래시와 같은 것을 찾고있었습니다 (C, PHP, Java 등의 문자열 내). ddaa가 인용 한 규칙에 따르면 그런 것이없는 것 같습니다.
Juan Pablo Califano

28
이것이 정답입니다. 탈출 은 약간 모호한 용어이지만이 답변은 탈출 의 정신을 분명히 다루고 있습니다. 안타깝게도 OP의 좁은 이스케이프 개념에 맞지 않기 때문에 어떤 이유로 든 백 슬래시 문자가 임의로 필요합니다.
G-Wiz

5
그래서 요약, 탈출 ]]>]]]]><![CDATA[>. 길이의 5 배 ... 와우. 그러나 드문 경우입니다.
Brilliand

5
5 배의 길이는 재미있을뿐만 아니라 CDATA의 주요 사용 사례 인 코드에서 드문 시퀀스가 ​​아닙니다! 공백을 제거하는 압축 된 JavaScript를 가정하면 "if (fields [fieldnames [0]]> 3)"과 같이 색인으로 이름 배열에서 이름으로 필드에 액세스 할 수 있으며 이제 "if ( fields [fieldnames [0]]]]> <! [CDATA [> 3) ". CDATA를 사용하여 읽기 쉽도록 LOL을 사용하지 않습니다. CDATA 구문을 만든 사람을 구두로 때리고 싶습니다.
Triynko

1
이스케이프 처리 또는보다 정확하게 인용하는 것은 원시 텍스트가 컨텍스트를 떠나지 않고 의미를 갖는 컨텍스트에 일부 텍스트를 삽입하는 것을 의미합니다. 백 슬래시와는 아무런 관련이 없습니다. 그리고이 답변은 하나가 아닌 두 개의 CDATA 섹션을 생성하므로 이스케이프하거나 인용하지 않습니다.
ddaa

17

당신은 이스케이프하지 않지만 , 앞에 삽입 ]]>하여 >after 를 피하십시오. 이것은 C / Java / PHP / Perl 문자열과 같지만 a 전후에만 필요 합니다 .]]]]><![CDATA[>\>]]

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

이것은 아마도 .NET DOM의 이데올로기 일지 모르지만 예외는 발생하지 않습니다. 여기서 예외가 발생합니다.

Console.Write(doc.OuterXml);

나는 후드 아래에서 일어나는 일이 XmlDocument가 XmlWriter를 사용하여 출력을 생성하고 XmlWriter가 글을 쓸 때 올바른 형식을 검사한다는 것입니다.


글쎄요, 저는 거의 "실제"예를 가지고있었습니다. 일반적으로 CDATA 섹션 내에 html 마크 업이 포함 된 Xml을 Flash에서로드합니다. 탈출 할 수있는 방법이 있으면 유용 할 수 있다고 생각합니다. 그러나 어쨌든 CDATA 내용은 일반적으로 유효한 XHTML이므로 "외부"CDATA를 완전히 피할 수 있습니다.
Juan Pablo Califano

2
CDATA는 거의 항상 피할 수 있습니다. CDATA로 어려움을 겪고있는 사람들은 자신이 실제로 무엇을하는지 그리고 / 또는 그들이 사용하는 기술이 실제로 어떻게 작동하는지 이해하지 못하는 경우가 많습니다.
Robert Rossney

또한 필자가 CDATA를 사용한 CMS에서 CDATA를 사용한 유일한 이유는 내가 작성한 것이기 때문에 실제로 수행하려는 작업 및 / 또는 기술의 작동 방식을 이해하지 못했음을 덧붙여 야합니다. CDATA를 사용할 필요가 없었습니다.
Robert Rossney

.net을 사용하는 경우 피할 수없는 CDATA에 대한 앞의 의견은 바로 자리에 있습니다. 콘텐츠를 문자열로 작성하면 프레임 워크가 실제 세계에서 모든 이스케이프 (및 이스케이프 해제)를 수행합니다 .... ... xmlStream.WriteStartElement ( "UnprocessedHtml"); xmlStream.WriteString (UnprocessedHtml); xmlStream.WriteEndElement ();
Mark Mullin


3

]]>탈출해야 할 또 다른 경우 가 있습니다. XML 문서의 CDATA 블록 안에 완벽하게 유효한 HTML 문서를 저장해야하고 HTML 소스에 자체 CDATA 블록이 있다고 가정합니다. 예를 들면 다음과 같습니다.

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

주석 처리 된 CDATA 접미 부를 다음과 같이 변경해야합니다.

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

XML 파서는 자바 스크립트 주석 블록을 처리하는 방법을 알지 못하기 때문에


이것은 특별한 경우가 아닙니다. 간단하게 교체 ]]>와 함께 ]]]]><![CDATA[>아직 여기에 적용됩니다. JavaScript이거나 주석이 달린 사실은 중요하지 않습니다.
Thomas Grainger 2016 년


1

PHP에서 더 깔끔한 방법 :

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

필요한 경우 멀티 바이트 안전 str_replace를 사용하는 것을 잊지 마십시오 (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을 사용하는 경우 멀티 바이트 안전 교체를 수행 할 필요가 없습니다. 나는 비록 downvote하지 않았다 :)
frodeborli

-1

CDATA를 중단하는 것이 좋은 방법이라고 생각하지 않습니다. 여기 내 대안이 있습니다 ...

사용 ]이스케이프 시퀀스는 문자의 16 진수 값 하였다. &#xhhhh;=> 에서와 같이]<unicode value>;

이렇게하면 ]]>인코딩 fn 을 기록하려고하면 ]005D;]005D;]003E;CDATA에서 괜찮습니다.

엔티티 이름으로 이스케이프하는 것이 낫습니다. 앱에서 매번 디코딩되지 않으며 앰퍼샌드로 엔티티를 이스케이프 처리하는 것과 다른 문자 / 시퀀스를 이스케이프 처리하는 것과는 다른 우선 순위가있을 수 있기 때문입니다. 결과적으로 CDATA의 내용을보다 강력하게 제어 할 수 있습니다.


-2

이 구조를보십시오 :

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

내부 CDATA 태그의 경우로 ]]]]><![CDATA[>대신 닫아야합니다 ]]>. 그렇게 간단합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.