2012-12-20 9 views
6

内のエンティティをデコードする私は、次の行動を経験している:PHP、SimpleXMLのは、CDATA

$xml_string1 = "<person><name><![CDATA[ Someone&#039;s Name ]]></name></person>"; 
$xml_string2 = "<person><name> Someone&#039;s Name </name></person>"; 

$person = new SimpleXMLElement($xml_string1); 
print (string) $person->name; # Someone&#039;s Name 

$person = new SimpleXMLElement($xml_string2); 
print (string) $person->name; # Someone's Name 

$person = new SimpleXMLElement($xml_string1, LIBXML_NOCDATA); 
print (string) $person->name; # Someone&#039;s Name 

PHPのドキュメントはNOCDATAは、 "テキストノードとして[s]はCDATAをマージする" と言います。私にとってこれは、CDATAがテキストノードと同じように扱われること、あるいは3番目の例の動作が2番目の例と同じになることを意味します。

XML(これは外部ソースからのフィード)を制御できません。そうでなければ、何もしないのでCDATAタグを削除して、必要な動作を破棄します。

上記の例は、なぜ動作しますか? SimpleXMLをテキストノードを扱うのと同じ方法でCDATAノードを扱えるようにする方法はありますか?私はそのオプションを理解していないように見えるので、「CDATAをテキストノードとしてマージする」とは実際に何をしていますか?

私は現在データを取り出した後にデコードしていますが、上記の例はまだわかりません。

+0

'print'には文字列コンテキストがありますその場合は文字列にキャストする必要はありません。 – hakre

+0

@hakreしかし、 'print'(もっと一般的に' echo'と書かれています)は、デバッグが何か他のものに置き換えられている間にスタンドとして使用される可能性が高いので、一貫して文字列キャストを行うのは良い習慣です後の混乱を避ける。 – IMSoP

答えて

9

XMLのCDATAセクションの目的は、特別な文字(特に>,<、および&)をエスケープする必要があると思われるテキストブロックを "そのまま"カプセル化することです。 &という文字を含むCDATAセクションは、&amp;を含む通常のテキストノードと同じです。

パーサはこれを無視して提供し、すべてのCDATAノードをふりをした場合には、実際には単なるテキストノードだった、それは即座に、すぐに誰かが「P & Oクルーズ」に述べたように破る - &は単純には存在しないことを(&amp;、または&somethingElse;としてではなく)

(string)$fooは、通常のPHP文字列にテキストとCDATAノードのシーケンスをきれいに組み合わせるため、実際にはSimpleXMLではかなり役に立ちません。 print_rには気付かないことがよくあります。これは、テキストノードやCDATAノードを独自のオブジェクトとして操作できる、DOMなどのより体系的なアクセスメソッドには必ずしも当てはまりません。

CDATAセクションに出会うたびに、そのコンテンツを取得し、エスケープして、通常のテキストノードとして戻したり、テキストノードと「マージ」します。いずれかの側。表現されるテキストは同じで、異なる方法でドキュメントに格納されます。あなたが戻ってXMLにエクスポートする場合は、この例のように、違いを見ることができます:

$xml_string = "<person><name>Welcome aboard this <![CDATA[P&O Cruises]]> voyage!</name></person>"; 

$person = new SimpleXMLElement($xml_string); 
echo 'CDATA retained: ', $person->asXML(); 
// CDATA retained: <?xml version="1.0"?> 
// <person><name>Welcome aboard this <![CDATA[P&O Cruises]]> voyage!</name></person> 

$person = new SimpleXMLElement($xml_string, LIBXML_NOCDATA); 
echo 'CDATA merged: ', $person->asXML(); 
// CDATA merged: <?xml version="1.0"?> 
// <person><name>Welcome aboard this P&amp;O Cruises voyage!</name></person> 

あなたが解析しているXML文書が、実際のエンティティが含まれているCDATAセクションが含まれている場合は、その文字列を取り、それをアンエスケープする必要がありますXMLから完全に独立しています。これを行う一般的な理由の1つは、HTMLでマークアップされたものを、XMLドキュメントの中の古い文字列として扱うことです。

<Comment> 
<SubmittedBy>IMSoP</SubmittedBy> 
<Text><![CDATA[I'm <em>really</em> bad at keeping my answers brief <tt>;)</tt>]]></Text> 
</Comment> 
+1

偉大な答え、非常に有益な –