Question

Je me demandais s'il existe un moyen d'échapper à un jeton de fin CDATA (]]>) dans une section CDATA d'un document xml. Ou, plus généralement, s'il existe une séquence d'échappement à utiliser dans un CDATA (mais si elle existe, je suppose qu'il serait probablement logique de sortir uniquement des balises de début ou de fin).

En gros, pouvez-vous incorporer un jeton de début ou de fin dans un CDATA et dire à l'analyseur syntaxique de ne pas l'interpréter, mais de le traiter simplement comme une autre séquence de caractères.

Probablement, vous devriez simplement refactoriser votre structure xml ou votre code si vous essayez de le faire, mais même si je travaille avec xml quotidiennement depuis environ 3 ans et que je n'ai jamais eu ce problème, je me demandais si c'était possible. Juste par curiosité.

Modifier:

Autre que l'utilisation du codage HTML ...

Était-ce utile?

La solution

Clairement, cette question est purement académique. Heureusement, la réponse est très claire.

Vous ne pouvez pas échapper à une séquence de fin CDATA. La spécification de la règle de production 20 est très claire:

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

EDIT: cette règle de produit signifie littéralement & "; Une section CData peut contenir tout ce que vous voulez MAIS la séquence ']] >'. Aucune exception. & ";

EDIT2: la même section se lit également:

  

Dans une section CDATA, seule la chaîne CDEnd est reconnue en tant que balise, de sorte que les crochets angulaires et les esperluettes à gauche peuvent apparaître sous leur forme littérale. ils ne doivent pas (et ne peuvent pas) être échappés avec " < " et " & " ;. Les sections CDATA ne peuvent pas imbriquer.

En d'autres termes, il n'est pas possible d'utiliser une référence d'entité, un balisage ou toute autre forme de syntaxe interprétée. Le seul texte analysé dans une section CDATA est ]]> et met fin à la section.

Il est donc impossible d'échapper à <=> une section CDATA.

EDIT3: La même section se lit également:

  

2.7 Sections CDATA

     

[Définition: les sections CDATA peuvent apparaître n'importe où des données de caractères peuvent apparaître; ils sont utilisés pour échapper à des blocs de texte contenant des caractères qui seraient autrement reconnus comme du balisage. Les sections CDATA commencent par la chaîne & Quot; & Lt;! [CDATA [& Quot; et se terminer par la chaîne "]] > " ;:]

Ensuite, il peut y avoir une section CDATA partout où des données de caractère peuvent apparaître, y compris plusieurs sections CDATA adjacentes à la place d’une seule section CDATA. Cela permet de scinder le <=> jeton et de placer ses deux parties dans des sections CDATA adjacentes.

ex:

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

devrait être écrit comme

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

Autres conseils

Vous devez fractionner vos données pour dissimuler le ]]>.

Voici le tout:

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

Le premier <![CDATA[]]]]> a le ]]. Le second <![CDATA[>]]> a le >.

Vous n'échappez pas à ]]> mais vous échappez à > après ]] en insérant ]]><![CDATA[ avant le \, pensez à cela comme un <=> en C / Java / PHP / Perl chaîne mais nécessaire uniquement avant un <=> et après un <=>.

BTW,

La réponse de S.Lott est la même que celle-ci, mais libellée différemment.

S. La réponse de Lott est juste: vous ne codez pas la balise de fin, vous la découpez dans plusieurs sections CDATA.

Comment gérer ce problème dans le monde réel: en utilisant un éditeur XML pour créer un document XML qui sera introduit dans un système de gestion de contenu, essayez de rédiger un article sur les sections CDATA. Votre astuce ordinaire consistant à incorporer des exemples de code dans une section CDATA vous fera échouer ici. Vous pouvez imaginer comment j'ai appris cela.

Mais dans la plupart des cas, vous ne rencontrerez pas cela et voici pourquoi: si vous voulez stocker (par exemple) le texte d'un document XML en tant que contenu d'un élément XML, vous utiliserez probablement une méthode DOM, par exemple:

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

Et le DOM échappe assez raisonnablement à la < et le > ;, ce qui signifie que vous n'avez pas incorporé par inadvertance une section CDATA dans votre document.

Oh, et c'est intéressant:

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

Ceci est probablement une idéosyncrasie du DOM .NET, mais cela ne jette pas une exception. L'exception est levée ici:

Console.Write(doc.OuterXml);

Je suppose que ce qui se passe sous le capot est que XmlDocument utilise un fichier XmlWriter pour produire sa sortie et que XmlWriter vérifie le bon format lors de l'écriture.

remplacez simplement ]]> par ]]]]><![CDATA[>

Voici un autre cas dans lequel ]]> doit être évité. Supposons que nous ayons besoin de sauvegarder un document HTML parfaitement valide dans un bloc CDATA d'un document XML et que la source HTML ait son propre bloc CDATA. Par exemple:

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

le suffixe CDATA commenté doit être remplacé par:

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

puisqu'un analyseur XML ne saura pas comment gérer les blocs de commentaires javascript

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

Une manière plus propre en PHP:

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

N'oubliez pas d'utiliser un str_replace multibyte-safe si nécessaire (non latin1 $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;
   }

Une autre solution consiste à remplacer ]]> par ]]]><![CDATA[]>.

Voir cette structure:

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

Pour les balises CDATA internes, vous devez fermer avec ]]]]><![CDATA[> au lieu de ]]>. Aussi simple que cela.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top