xmlでCDATA終了トークンをエスケープする方法はありますか?


129

]]>xmlドキュメントのCDATAセクション内でCDATAエンドトークン()をエスケープする方法があるかどうか疑問に思っていました。または、より一般的には、CDATA内で使用するエスケープシーケンスが存在する場合(ただし、存在する場合は、とにかく、開始トークンまたは終了トークンをエスケープすることだけが意味があると思います)。

基本的に、CDATAに開始トークンまたは終了トークンを埋め込んで、パーサーに解釈せずに、別の文字シーケンスとして扱うように指示できますか。

おそらく、XML構造またはコードをリファクタリングする必要がある場合は、おそらくリファクタリングする必要がありますが、私は過去3年間ほど毎日XMLを使用しており、この問題を経験したことはありませんが、可能かと思っていました。単なる好奇心から。

編集:

HTMLエンコーディング以外の方法...


4
エンコードから何も排除誰か:まず、私は正しいが、ノートなどの答えを受け入れる>よう>に埋め込ま確保するためのCData内]]>CDEndとして解析されることはありません。それは単にそれが予期しないものであることを意味し、データを適切にデコードできるように&最初にエンコードする必要&があります。ドキュメントのユーザーは、このCDataもデコードすることを知っている必要があります。CDataの目的の一部は、特定のコンシューマーが処理方法を理解するコンテンツを含めることであるため、これは前例のないことではありません。このようなCDataは、一般的なコンシューマーによって適切に解釈されることは期待できません。
nix

1
@ nix、CDATAはテキストノードのコンテンツを宣言する明示的な方法を提供するだけで、(]]>以外の)言語トークンが解析されないようにします。特に&gt;のようなエンティティ参照を展開しません。このため、CDATAブロックでは、 '>'ではなく、これらの4文字を意味します。見方を変えると、XML仕様では、これらのシーケンス(「文字データ」)だけでなく、すべてのテキストコンテンツが「cdata」と呼ばれます。また、特定の消費剤についてではありません。(ただし、そのようなものは存在します-処理命令(<?target instruction?>)
セミコロン

(この種のことがノードの本来の意図に反して実行されたとしても、XMLとの長くて苦痛な戦いにおいてはすべて公平です。読者が<![CDATA [ ]]>はその目的のために実際に設計されたものではありません。)
セミコロン'11年

1
@SemicolonをCDATA許可するように設計されたものを彼らは、そうでない場合はマークアップとして認識される文字を含むテキストのブロックをエスケープするために使用されている意味CDATA、それはマークアップもあるので、あまりを。しかし、実際には、私が暗示する二重エンコーディングは必要ありません。]]&gt;は、CDEnd内でをエンコードするための許容可能な手段ですCDATA
nix 2015年

確かに、二重エンコードは必要ありませんが、パーサーは解析しないため、エージェントには特別な知識が必要です&gt; >として。それがあなたの言っていることだと思いますか?解析後に、必要に応じてそれらを置き換えることができるということですか?
セミコロン

回答:


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セクションが存在する場合があります。これにより、]]>トークンを分割し、トークンの2つの部分を隣接するCDATAセクションに配置できるようになります。

例:

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

次のように書く必要があります

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

1
確かに。まあ、私は学問的なタイプではありませんが、質問で述べたように、私はこれについて興味があります。正直に言うと、ルールについて使用されている構文がほとんど理解できないため、これについては簡単に説明します。ご回答有難うございます。
ファンパブロカリファノ

39
これは学術的な問題ではありません。CDATAに関するディスカッションを含むブログ投稿のRSSフィードについて考えてみます。
usr

4
「面白く、実用的ではない」という意味で「学術的」という意味でした。一般に、CDATAは役に立ちません。これは単なるXMLテキストをシリアル化する方法であり、意味的には文字エンティティを使用して特殊文字をエスケープすることと同等です&lt; &gt; および&quot;。Charactersエンティティは、最もシンプルで最も堅牢で最も一般的なソリューションであるため、CDATAセクションの代わりにそれを使用します。(文字列からXMLを構築する代わりに)適切なXMLライブラリを使用すれば、それについて考える必要すらありません。
ddaa 2012年

5
圧縮されたJavascriptを次のような<script>タグにエンコードしようとしているので、私はこれに噛まれました<script>/*<![CDATA[*/javascript goes here/*]]>*/</script>。私は複数のCDATAセクションに分割するアイデアが好きです...
NickZoic

3
これを現実の世界で体験しました。ウィキペディアのダンプを読んで別のxmlファイルを書き込んでいるときに、National Transportation Safety Boardのページでこれに遭遇しました。情報ボックスの予算には1億米ドル超(2013年)が含まれています。含まれ[[United States dollar|US$]]&gt;100 million (2013)ているソースxml は[[United States dollar|US$]]>100 million (2013)、リーダーとライターによって翻訳され、CDATAを使用してテキストをエスケープすることを選択して失敗しました。
ポールジャクソン

169

を隠すには、データを断片に分割する必要があり]]>ます。

ここにすべてがあります:

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

最初の<![CDATA[]]]]>]]です。2つ目<![CDATA[>]]>>です。


1
ご回答有難うございます。相当する円記号(C、PHP、Javaなどの文字列内)のようなものを探していました。ddaaが引用したルールによると、そのようなことはないようです。
ファンパブロカリファノ

28
これは受け入れられる答えになるはずです。エスケープは少しあいまいな用語ですが、この答えは間違いなくエスケープの精神に対処します。これは、OPのエスケープという狭い概念に適合しません。何らかの理由でバックスラッシュ文字を任意に含める必要があります。
G-Wiz

5
したがって、要約すると、]]>としてエスケープし]]]]><![CDATA[>ます。長さの5倍...すごい。しかし、それは珍しいシーケンスです。
ブリリアント、

5
5倍の長さは陽気なだけでなく、CDATAの主な使用例であるコード内の珍しいシーケンスでさえありません!スペースを削除する圧縮されたJavaScriptを想定すると、 "if(fields [fieldnames [0]]> 3)"のように、インデックスによって名前の配列から名前でフィールドにアクセスすることができ、これを "if( fields [fieldnames [0]]]]> <![CDATA [> 3) "。これは、CDATAを使用して読みやすくするという目的に反します。CDATA構文を思いついた人は誰でも口頭で叩きたいです。
Triynko 2013

1
エスケープ、またはより正確には引用とは、コンテキストから離れることなく生のテキストが意味を持つコンテキストにテキストを挿入することを意味します。バックスラッシュとは関係ありません。また、この回答は1つではなく2つのCDATAセクションを生成するため、エスケープまたは引用ではありません。
ddaa 2013年

17

あなたは脱出していない]]>が、あなたは脱出>した後に]]挿入することによって、]]><![CDATA[前に>、同じようにこの考える\C / Javaの/ PHP / Perlの文字列の中だけ前に必要>とした後]]

ところで、

S.Lottの答えはこれと同じですが、言い方が違うだけです。


2
私はこの言い回しを好む。:)
ブリリアント

3
この言い方は人々に間違った考えを与えます。これはエスケープされていません]]]]><![CDATA[>の魔法のようなシーケンスではありません]]>]]]]>持っている]]データなどの文字を、そして]]>現在のCDATAセクションを終了します。<![CDATA[>新しいCDATAセクションを開始し、>そこに配置します。これらは実際には2つの異なる要素であり、DOMパーサーを使用する場合は異なる扱いになります。あなたはそれを知っておくべきです。この方法は、最初と2番目のCDATA ]]]><![CDATA[]>に配置]することを除いて、に似てい]>ます。違いは残ります。
アイディアカピ2013

CDATAコンテンツはエスケープされたテキストのリテラルスパンとして扱われるため、違いは誇張されています。DOMをいじるときだけ、それが本当に重要であり、そのレベルでは、とにかく、テキスト、コメント、処理命令ノードのような他の見えない境界を扱っています。
Beejor、2016年

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マークアップを含むFlashからXmlをロードします。それを回避する方法があると便利だと思います。しかしとにかく、その場合、CDATAコンテンツは通常有効なXHTMLであるため、「外部」CDATAは完全に回避できます。
ファンパブロカリファノ

2
CDATAはほぼ完全に回避できます。CDATAに非常に頻繁に取り組む人々は、彼らが実際に何をしようとしているのか、および/または彼らが使用しているテクノロジーが実際にどのように機能するのかを理解していないことがわかりました。
ロバートロスニー2008年

ああ、私はまた、私の回答で言及したCMSがCDATAを使用した唯一の理由は、私がそれを書いたことであり、私が実際に何をしようとしているか、テクノロジーがどのように機能しているかを理解していなかったことです。CDATAを使用する必要はありませんでした。
ロバートロスニー2008年

.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パーサーはjavascriptコメントブロックの処理方法を認識しないため


これは特別なケースではありません。単に置き換えて]]>]]]]><![CDATA[>ここでも適用されます。それがJavaScriptである、またはコメントされているという事実は重要ではありません。
Thomas Grainger

1

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


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

あなたの反対票を説明できますか?私が間違いを犯したと言っても、それがどこにあるのかを説明するほど役に立ちません。
Alain Tiemblo 2014

UTF-8を使用している場合は、マルチバイトの安全な置換を行う必要はありません。私は反対投票しませんでした:)
frodeborli

-1

CDATAを中断することは良い方法ではないと思います。これが私の代替案です...

使用]エスケープシーケンスについては、あなたのキャラクターの進値が続きます。のように&#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.