Pregunta

Me preguntaba si hay alguna manera de escapar de una CDATA final token (]]>) dentro de una sección CDATA en un documento xml.O, más en general, si hay alguna secuencia de escape para el uso dentro de una CDATA (pero si es que existe, supongo que probablemente sólo tienen sentido para escapar de comenzar o terminar los tokens, de todos modos).

Básicamente, se puede tener un inicio o fin de token incrustado en una CDATA y decirle al analizador de no interpretar, sino a tratar como una secuencia de caracteres.

Probablemente, usted sólo debe refactorizar su estructura xml o el código si usted se encuentra tratando de hacer eso, pero aunque he estado trabajando con xml en una base diaria durante los últimos 3 años o así y nunca he tenido este problema, me preguntaba si era posible.Sólo por curiosidad.

Editar:

Otros que el uso de la codificación html...

¿Fue útil?

Solución

Claramente, esta pregunta es puramente académica.Afortunadamente, tiene una respuesta definitiva.

Usted no puede escapar de una CDATA final de la secuencia.La producción de la regla 20 de los XML especificación es bastante claro:

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

EDITAR:Este producto esta regla significa literalmente "Una sección CData puede contener cualquier cosa que desee, PERO la secuencia ']]>'.No es la excepción.".

EDIT2:El misma sección también lee:

Dentro de una sección CDATA, sólo el CDEnd cadena es reconocida como marcado, de modo que el ángulo izquierdo paréntesis y signos pueden ocurrir en su forma literal;ellos no tienen (y no puede) ser escapado de usar "<"y "&".Las secciones CDATA pueden anidar.

En otras palabras, no es posible utilizar la entidad de referencia, de marcas o de cualquier otra forma de interpretar la sintaxis.La única analiza el texto dentro de una sección CDATA es ]]>, y termina la sección.

Por lo tanto, no es posible escapar ]]> dentro de una sección CDATA.

EDIT3:El misma sección también lee:

2.7 Secciones CDATA

[Definición:Las secciones CDATA puede ocurrir en cualquier parte de los datos de carácter puede ocurrir;se utilizan para escapar de los bloques de texto que contiene caracteres que de otra manera sería reconocido como el marcado.Las secciones CDATA comienzan con la cadena "<![CDATA[" and end with the string "]]>":]

A continuación, puede haber una sección CDATA cualquier parte de los datos de carácter pueden ocurrir, incluyendo múltiples adyacentes secciones CDATA directamente de una sola sección CDATA.Que le permite ser posible dividir el ]]> token y poner las dos partes adyacentes de las secciones CDATA.

ex:

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

debe ser escrito como

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

Otros consejos

Debe dividir sus datos en pedazos para ocultar el ]]>.

Aquí está todo:

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

El primer <![CDATA[]]]]> tiene el ]]. El segundo <![CDATA[>]]> tiene el >.

No escapar de la ]]> pero escapar de la > después de ]] mediante la inserción de ]]><![CDATA[ antes de la >, piense en esto como un \ en C/Java/PHP/Perl cadena, pero sólo se necesita antes de una > y después de un ]].

BTW,

S. Lott la respuesta es la misma que esta, solo redactado de manera diferente.

S. La respuesta de Lott es correcta: no codifica la etiqueta final, la divide en varias secciones CDATA.

Cómo resolver este problema en el mundo real: utilizando un editor XML para crear un documento XML que se incorporará a un sistema de gestión de contenido, intente escribir un artículo sobre las secciones CDATA. Su truco habitual de incrustar ejemplos de código en una sección CDATA le fallará aquí. Puedes imaginar cómo aprendí esto.

Pero en la mayoría de las circunstancias, no encontrará esto, y esta es la razón: si desea almacenar (por ejemplo) el texto de un documento XML como el contenido de un elemento XML, probablemente usará un método DOM, por ejemplo:

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

Y el DOM escapa razonablemente del < y > ;, lo que significa que no ha incrustado inadvertidamente una sección CDATA en su documento.

Ah, y esto es interesante:

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

Esta es probablemente una ideosincrasia de .NET DOM, pero eso no arroja una excepción. La excepción se lanza aquí:

Console.Write(doc.OuterXml);

Supongo que lo que sucede debajo del capó es que el XmlDocument está utilizando un XmlWriter para producir su salida, y el XmlWriter comprueba si está bien formado mientras escribe.

simplemente reemplace ]]> con ]]]]><![CDATA[>

Aquí hay otro caso en el que ]]> necesita ser escapado. Supongamos que necesitamos guardar un documento HTML perfectamente válido dentro de un bloque CDATA de un documento XML y la fuente HTML tiene su propio bloque CDATA. Por ejemplo:

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

el sufijo CDATA comentado debe cambiarse a:

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

dado que un analizador XML no sabrá cómo manejar los bloques de comentarios de JavaScript

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

Una forma más limpia en PHP:

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

No olvide utilizar un str_replace seguro para múltiples bytes si es necesario (no 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;
   }

Otra solución es reemplazar ]]> por ]]]><![CDATA[]>.

Ver esta estructura:

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

Para las etiquetas CDATA internas, debe cerrar con ]]]]><![CDATA[> en lugar de ]]>. Tan simple como eso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top