2012-12-20 26 views
6

sto sperimentando il seguente comportamento:PHP, SimpleXML, decodifica le entità 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 

I documenti PHP dicono che NOCDATA "Merge [s] CDATA come nodi di testo". Per me questo significa che CDATA verrà trattato allo stesso modo dei nodi di testo o che il comportamento del terzo esempio sarà uguale al secondo esempio.

Non ho il controllo sull'XML (è un feed da una fonte esterna), altrimenti rimuoverò semplicemente il tag CDATA poiché non fa nulla e rovina il comportamento che voglio.

Perché l'esempio sopra riportato si comporta come fa? C'è un modo per rendere SimpleXML gestire i nodi CDATA nello stesso modo in cui gestisce i nodi di testo? Che cosa fa realmente "Unisci CDATA come nodi di testo", dal momento che non riesco a capire questa opzione?

Attualmente sto decodificando dopo aver estratto i dati, ma l'esempio precedente non ha ancora senso per me.

+0

'print' ha contesto stringa, è non è necessario eseguire il cast in questo caso. – hakre

+0

@hakre ma 'print' (più comunemente scritto 'echo') è probabile che venga usato come standard mentre il debug viene sostituito con qualcos'altro, quindi direi che è una buona abitudine fare costantemente il casting per evitare la successiva confusione. – IMSoP

risposta

9

Lo scopo di sezioni CDATA in XML è quello di incapsulare un blocco di testo "così come sono", che altrimenti richiederebbero caratteri speciali (in particolare, >, < e &) per essere sfuggito. Una sezione CDATA contenente il carattere & è la stessa di un normale nodo di testo che contiene &amp;.

Se un parser dovesse offrire a ignorare questo, e fingere tutti i nodi CDATA sono stati davvero pochi i nodi di testo, sarebbe istantaneamente rompere non appena qualcuno ha detto "P & O Cruises" - che & semplicemente non può essere lì proprio (piuttosto che come &amp; o &somethingElse;).

Il LIBXML_NOCDATA è in realtà piuttosto inutile con SimpleXML, perché (string)$foo combina ordinatamente qualsiasi sequenza di testo e nodi CDATA in una stringa PHP ordinaria. (Qualcosa che le persone spesso non notano, perché non lo fa print_r.) Questo non è necessariamente vero per i metodi di accesso più sistematici, come DOM, in cui è possibile manipolare nodi di testo e nodi CDATA come oggetti a sé stanti.

Quello che effettivamente fa è passare attraverso il documento, e ovunque incontri una sezione CDATA, prende il contenuto, lo scappa e lo rimette come un normale nodo di testo, o "lo unisce" con qualsiasi nodo di testo a entrambi i lati. Il testo rappresentato è identico, appena memorizzato nel documento in un modo diverso; si può vedere la differenza se si esporta di nuovo a XML, come in questo esempio:

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

Se il documento XML che stai analisi contiene una sezione CDATA che contiene in realtà entità, è necessario prendere quella stringa e unescape si completamente indipendente dall'XML. Un motivo comune per fare questo (altro che la pigrizia con le librerie scarsamente compresi) è quello di trattare qualcosa marcato in HTML come un qualsiasi vecchio stringa all'interno di un documento XML, in questo modo:

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

Ottima risposta, molto istruttiva –