Domanda

Mi chiedevo se esiste un modo per sfuggire a un token di fine CDATA (]]>) all'interno di una sezione CDATA in un documento XML. O, più in generale, se esiste una sequenza di escape da utilizzare all'interno di un CDATA (ma se esiste, immagino che probabilmente avrebbe senso sfuggire ai token di inizio o fine, comunque).

Fondamentalmente, puoi avere un token di inizio o fine incorporato in un CDATA e dire al parser di non interpretarlo ma di trattarlo come solo un'altra sequenza di caratteri.

Probabilmente, dovresti semplicemente riformattare la tua struttura xml o il tuo codice se ti ritrovi a provare a farlo, ma anche se ho lavorato con xml quotidianamente negli ultimi 3 anni circa e non ho mai avuto questo problema, mi chiedevo se fosse possibile. Solo per curiosità.

Modifica:

Oltre all'utilizzo della codifica html ...

È stato utile?

Soluzione

Chiaramente, questa domanda è puramente accademica. Fortunatamente, ha una risposta molto precisa.

Non è possibile evitare una sequenza di fine CDATA. La regola di produzione 20 della specifica XML è abbastanza chiara:

[20]    CData      ::=      (Char* - (Char* ']]>' Char*))

EDIT: questa regola del prodotto significa letteralmente " Una sezione CData può contenere tutto ciò che vuoi MA la sequenza ']] >'. Nessuna eccezione. & Quot ;.

EDIT2: la stessa sezione recita anche:

  

All'interno di una sezione CDATA, solo la stringa CDEnd viene riconosciuta come markup, in modo che le parentesi angolari sinistre e le e commerciali possano verificarsi nella loro forma letterale; non devono (e non possono) essere sfuggiti usando " < " e " & " ;. Le sezioni CDATA non possono essere nidificate.

In altre parole, non è possibile utilizzare riferimenti a entità, markup o qualsiasi altra forma di sintassi interpretata. L'unico testo analizzato all'interno di una sezione CDATA è ]]> e termina la sezione.

Quindi, non è possibile uscire da <=> all'interno di una sezione CDATA.

EDIT3: la stessa sezione recita anche:

  

2.7 Sezioni CDATA

     

[Definizione: le sezioni CDATA possono verificarsi ovunque possano verificarsi dati sui caratteri; sono usati per sfuggire a blocchi di testo contenenti caratteri che altrimenti verrebbero riconosciuti come markup. Le sezioni CDATA iniziano con la stringa & Quot; & Lt;! [CDATA [& Quot; e termina con la stringa "]] > " ;:]

Quindi potrebbe esserci una sezione CDATA ovunque possano verificarsi dati sui caratteri, incluse più sezioni CDATA adiacenti al posto di una singola sezione CDATA. Ciò consente di dividere il <=> token e metterne le due parti in sezioni CDATA adiacenti.

es:

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

deve essere scritto come

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

Altri suggerimenti

Devi dividere i tuoi dati in pezzi per nascondere ]]>.

Ecco il tutto:

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

Il primo <![CDATA[]]]]> ha il ]]. Il secondo <![CDATA[>]]> ha il >.

Non esci da ]]> ma esci da > dopo ]] inserendo ]]><![CDATA[ prima di \, pensa a questo proprio come un <=> in C / Java / PHP / Perl stringa ma necessaria solo prima di <=> e dopo <=>.

A proposito,

La risposta di S.Lott è la stessa di questa, formulata diversamente.

S. La risposta di Lott è giusta: non codifichi il tag di fine, lo spezzi in più sezioni CDATA.

Come affrontare questo problema nel mondo reale: usando un editor XML per creare un documento XML che verrà inserito in un sistema di gestione dei contenuti, prova a scrivere un articolo sulle sezioni CDATA. Il tuo trucco ordinario di incorporare esempi di codice in una sezione CDATA non riuscirà qui. Puoi immaginare come ho imparato questo.

Ma nella maggior parte dei casi non ti imbatterai in questo, ed ecco perché: se vuoi archiviare (diciamo) il testo di un documento XML come contenuto di un elemento XML, probabilmente utilizzerai un metodo DOM, ad esempio:

XmlElement elm = doc.CreateElement("foo");
elm.InnerText = "<[CDATA[[Is this a problem?]]>";

E il DOM sfugge abbastanza ragionevolmente al < e > ;, il che significa che non hai inavvertitamente incorporato una sezione CDATA nel tuo documento.

Oh, e questo è interessante:

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

Questa è probabilmente un'ideosincrasia del DOM .NET, ma ciò non fa eccezione. L'eccezione viene generata qui:

Console.Write(doc.OuterXml);

Immagino che ciò che sta accadendo sotto il cofano sia che XmlDocument sta usando un XmlWriter per produrre il suo output, e XmlWriter controlla la sua buona formazione mentre scrive.

sostituisci semplicemente ]]> con ]]]]><![CDATA[>

Ecco un altro caso in cui ]]> deve essere evitato. Supponiamo di dover salvare un documento HTML perfettamente valido all'interno di un blocco CDATA di un documento XML e che l'origine HTML abbia il proprio blocco CDATA. Ad esempio:

<htmlSource><![CDATA[ 
    ... html ...
    <script type="text/javascript">
        /* <![CDATA[ */
        -- some working javascript --
        /* ]]> */
    </script>
    ... html ...
]]></htmlSource>

il suffisso CDATA commentato deve essere modificato in:

        /* ]]]]><![CDATA[> *//

poiché un parser XML non saprà come gestire i blocchi di commenti javascript

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

Un modo più pulito in PHP:

   function safeCData($string)
   {
      return '<![CDATA[' . str_replace(']]>', ']]]]><![CDATA[>', $string) . ']]>';
   }

Non dimenticare di utilizzare uno str_replace sicuro per multibyte, se necessario (non latino1 $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;
   }

Un'altra soluzione è quella di sostituire ]]> con ]]]><![CDATA[]>.

Vedi questa struttura:

<![CDATA[
   <![CDATA[
      <div>Hello World</div>
   ]]]]><![CDATA[>
]]>

Per i tag CDATA interni è necessario chiudere con ]]]]><![CDATA[> anziché ]]>. Semplice come quello.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top