7

次の動作が発生しています。

$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は「CDATAをテキストノードとしてマージする」とのことです。私にとってこれは、CDATAがテキストノードと同じように扱われること、または3番目の例の動作が2番目の例と同じになることを意味します。

XML(外部ソースからのフィード)を制御できません。そうでない場合は、CDATAタグが何も実行されず、必要な動作が台無しになるため、CDATAタグを削除するだけです。

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

現在、データを取り出してからデコードしていますが、上記の例はまだ意味がありません。

4

1 に答える 1

13

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

パーサーがこれを無視することを提案し、すべてのCDATAノードが実際には単なるテキストノードであると偽った場合、誰かが「P&Oクルーズ」と言うとすぐに壊れ&ます&amp;。または&somethingElse;)。

テキストとCDATAノードの任意のシーケンスを通常のPHP文字列にきちんと結合するため、これLIBXML_NOCDATAは実際にはSimpleXMLではまったく役に立ちません。(string)$foo(気付かないため、人々が気付か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>
于 2012-12-20T23:02:16.313 に答える