2012-12-20 12 views
6

Ich erlebe das folgende Verhalten:PHP, SimpleXML, Dekodieren Entitäten in 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 

Die php docs sagen, dass NOCDATA "Merge [s] CDATA als Textknoten". Für mich bedeutet das, dass CDATA dann genauso wie Textknoten behandelt wird - oder dass das Verhalten des 3. Beispiels jetzt das gleiche wie im 2. Beispiel ist.

Ich habe keine Kontrolle über das XML (es ist ein Feed von einer externen Quelle), sonst würde ich nur das CDATA-Tag entfernen, da es nichts tut und das Verhalten zerstört, das ich will.

Warum verhält sich das obige Beispiel so? Gibt es eine Möglichkeit, SimpleXML die CDATA-Knoten auf die gleiche Weise behandeln zu lassen, wie es Textknoten behandelt? Was macht "CDATA als Textknoten zusammenführen" eigentlich, da ich diese Option nicht verstehe?

Ich entziffere gerade, nachdem ich die Daten herausgezogen habe, aber das obige Beispiel ergibt immer noch keinen Sinn für mich.

+0

'print' String-Kontext hat, Sie muss in diesem Fall nicht in eine Zeichenfolge umgewandelt werden. – hakre

+0

@hakre aber "print" (häufiger geschrieben "echo") wird wahrscheinlich als Ersatz verwendet, während Debugging dann durch etwas anderes ersetzt wird, also würde ich sagen, dass es eine gute Angewohnheit ist, das String-Casting konsequent durchzuführen vermeiden Sie spätere Verwirrung. – IMSoP

Antwort

9

Der Zweck der CDATA-Abschnitte in XML besteht darin, einen Textblock "wie er ist" einzukapseln, der andernfalls Sonderzeichen (insbesondere >, < und &) erfordert. Ein CDATA-Abschnitt, der das Zeichen & enthält, entspricht einem normalen Textknoten, der &amp; enthält.

Wenn ein Parser war zu bieten, dies zu ignorieren und so tun, als alle CDATA Knoten waren wirklich nur Textknoten, würde es sofort so schnell brechen, wie jemand „P & O Cruises“ erwähnt - dass & einfach nicht dort auf seine eine eigene (anstatt als &amp; oder &somethingElse;).

Die LIBXML_NOCDATA ist tatsächlich ziemlich nutzlos mit SimpleXML, weil (string)$foo jede Sequenz von Text und CDATA-Knoten in einer normalen PHP-Zeichenfolge sauber kombiniert. (Etwas, was die Leute häufig nicht bemerken, weil print_r dies nicht tut.) Das trifft nicht notwendigerweise auf systematischere Zugriffsmethoden wie DOM zu, wo Sie Textknoten und CDATA-Knoten als eigenständige Objekte bearbeiten können.

Was es effektiv tut, ist durch das Dokument zu gehen, und wo immer es einen CDATA-Abschnitt findet, nimmt es den Inhalt, entkommt und stellt ihn als normalen Textknoten wieder her oder "fusioniert" ihn mit beliebigen Textknoten jeder Seite. Der dargestellte Text ist identisch, nur im Dokument auf andere Weise gespeichert; Sie können den Unterschied sehen, wenn Sie zurück in XML exportieren, wie in diesem Beispiel:

$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> 

Wenn das XML-Dokument, das Sie Parsen einen CDATA-Abschnitt enthält, welche Unternehmen tatsächlich enthält, können Sie diese Zeichenfolge und unescape es nehmen müssen völlig unabhängig vom XML. Ein häufiger Grund dieses (außer Faulheit mit schlecht verstanden Bibliotheken) zu tun ist, etwas zu behandeln, in HTML als irgendeinen String in einem XML-Dokument, wie dies markiert:

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

Große Antwort, sehr informativ –