special especiales escape escapar characters caracteres amp xml escaping cdata

especiales - xml encode



¿Hay alguna forma de evitar un token final CDATA en xml? (10)

Me preguntaba si hay alguna forma de escapar de un token final CDATA ( ]]> ) dentro de una sección CDATA en un documento xml. O, de manera más general, si hay alguna secuencia de escape para usar dentro de un CDATA (pero si existe, supongo que probablemente tenga sentido escapar de los tokens de inicio y finalización, de todos modos).

Básicamente, puede tener un token de inicio o final incrustado en un CDATA y decirle al analizador que no lo interprete, sino que lo trate como una secuencia de caracteres más.

Probablemente, solo deberías refactorizar tu estructura xml o tu código si intentas hacerlo, pero aunque he estado trabajando con xml diariamente durante los últimos 3 años y nunca he tenido este problema, Me preguntaba si fue posible. Solo por curiosidad.

Editar:

Aparte de usar la codificación html ...


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 se debe cambiar a:

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

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


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

No puede escapar de una secuencia final CDATA. La regla de producción 20 de la specification XML es bastante clara:

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

EDITAR: Esta regla de producto significa literalmente "Una sección de CData puede contener lo que quieras PERO la secuencia '']]>'' No hay excepción.".

EDIT2: La specification también dice:

Dentro de una sección CDATA, solo la cadena CDEnd se reconoce como marcado, de modo que los corchetes angulares y los símbolos entre comillas pueden aparecer en su forma literal; no necesitan (ni pueden) escaparse usando " &lt; " y " &amp; ". Las secciones CDATA no pueden anidar.

En otras palabras, no es posible utilizar la referencia de entidad, el marcado o cualquier otra forma de sintaxis interpretada. El único texto analizado 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: La specification también dice:

2.7 Secciones CDATA

[Definición: las secciones de CDATA pueden ocurrir en cualquier lugar donde puedan ocurrir datos de caracteres; se usan para escapar de bloques de texto que contienen caracteres que, de lo contrario, se reconocerían como marcas. Las secciones CDATA comienzan con la cadena "<! [CDATA [" y finalizan con la cadena "]]>":]

Entonces puede haber una sección CDATA en cualquier lugar donde puedan ocurrir datos de caracteres, incluyendo múltiples secciones CDATA adyacentes en el lugar de una sola sección CDATA. Eso permite que sea posible dividir el token ]]> y colocar las dos partes del mismo en secciones adyacentes de CDATA.

ex:

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

debe escribirse como

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


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


La respuesta de S. 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 alimentará en un sistema de administración de contenido, intente escribir un artículo sobre las secciones CDATA. Su truco habitual de incrustar muestras 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 aquí está el porqué: si quiere almacenar (decir) el texto de un documento XML como el contenido de un elemento XML, probablemente use 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 el>, 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 del .NET DOM, pero eso no arroja una excepción. La excepción se arroja aquí:

Console.Write(doc.OuterXml);

Supongo que lo que sucede bajo el capó es que el XmlDocument está usando un XmlWriter para producir su salida, y el XmlWriter comprueba la buena forma mientras escribe.


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


Tienes que dividir tus datos en partes para ocultar el ]]> .

Aquí está todo:

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

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


Una manera más limpia en PHP:

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

No se olvide de usar un str_replace multibyte-safe 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; }


Usted no escapa del ]]> pero escapa del > después de ]] insertando ]]><![CDATA[ antes de > , piense en esto como una cadena / in C / Java / PHP / Perl pero solo necesitada antes a > y después de ]] .

Por cierto,

La respuesta de S.Lott es la misma, simplemente redactada de otra manera.


Vea esta estructura:

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

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


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