2010-09-27 20 views
24

He buscado Stackoverflow en este problema y encontré algunos temas, pero siento que no hay una respuesta sólida para mí en esto.Error del analizador XML: entidad no definida

Tengo un formulario que los usuarios envían y el valor del campo se almacena en un archivo XML. El XML está configurado para ser codificado con UTF-8.

De vez en cuando, un usuario copiará/pegará texto de alguna parte y es cuando aparece el "error de entidad no definida".

Me doy cuenta de que XML solo admite unas pocas entidades selectas y no se reconoce nada más allá de eso, de ahí el error del analizador.

Por lo que sé, hay algunas opciones que he visto:

  1. puedo buscar y reemplazar todas   e intercambiarlos con   o un espacio real.
  2. Puedo colocar el código en cuestión dentro de una sección CDATA.
  3. Puedo incluir estas entidades dentro del archivo XML.

Lo que estoy haciendo con el archivo XML es que el usuario puede ingresar el contenido en un formulario, se almacena en un archivo XML y ese contenido se muestra como XHTML en una página web (analizado con SimpleXML)

De las tres opciones, o cualquier otra opción que desconozco, ¿cuál es la mejor manera de tratar con estas entidades?

Gracias, Ryan

ACTUALIZACIÓN

Quiero agradecer a todos por la gran respuesta. De hecho, determiné qué causaba los errores de mi entidad. ¡Todas las sugerencias me hicieron analizarlo más profundamente!

Algunos cuadros de texto tienen cuadros de texto antiguos, pero mis áreas de texto se han mejorado con TinyMCE. Resulta que, mientras se mira más de cerca, las advertencias de PHP siempre hacían referencia a los datos de TinyMCE y mejoraban las áreas de texto. Más tarde noté en una PC que todos los personajes se habían eliminado (porque no podía leerlos), pero en un MAC se veían pequeños recuadros que hacen referencia al número Unicode de ese personaje. La razón por la que apareció en cuadrados en un MAC en primer lugar, es porque utilicé utf8_encode para codificar datos que no estaban en UTF para evitar otros errores de análisis (que de alguna manera también están relacionados con TinyMCE).

La solución a todo esto era bastante simple:

que añade esta línea entity_encoding : "utf-8" en mi tinyMCE.init. Ahora, todos los personajes aparecen de la manera en que se supone que deben hacerlo.

Supongo que lo único que no entiendo es por qué los caracteres aún aparecen cuando se colocan en cuadros de texto, porque nada los convierte a UTF, pero con TinyMCE fue un problema.

+0

Algunas partes importantes de su pregunta son invisibles porque se han analizados como marcado. Rodea esos bits con comillas inversas (''). – LarsH

+0

@LarsH: Hm, no veo nada en la fuente de la pregunta que pueda necesitar esto. – Tomalak

+0

@Tomalak: "1. Puedo buscar y reemplazar todos * ?? * y cambiarlos por * ?? * o un espacio real". Seguro me parece que falta algo allí. – LarsH

Respuesta

13

Puede analizar en HTML el texto y hacer que vuelva a escaparse con las entidades numéricas respectivas solamente (como:   ). En cualquier caso, simplemente utilizando entrada de usuario no desinfectada es una mala idea.

Todas las entidades numéricas están permitidos en XML, solamente los nombrados se hace en HTML no funcionan (con la excepción de &, ", <, >, ').

La mayor parte del tiempo, sin embargo, se puede escribir el carácter real (öö) al archivo XML lo que no hay necesidad de utilizar una referencia de entidad en absoluto. Si está utilizando una DOM API para manipular su XML (¡y debería hacerlo!) Esta es su apuesta más segura.

Finalmente (esta es la solución de desarrollador perezosa) podría construir un archivo XML roto (es decir, no bien formado, con errores de entidad) y solo pass it through tidy para las reparaciones necesarias. Esto puede funcionar o puede fallar dependiendo de solo cómo está roto. En mi experiencia, tidy es bastante inteligente, sin embargo, y te permite salir con la tuya.

+0

"Se podría analizar en HTML el texto y hacer que vuelva a escaparse con las entidades numéricas respectivas", ¿significa eso que siempre se pueden almacenar entidades numéricas sobre entidades de texto HTML? -Ryan – NightHawk

+0

@Ryan: Sí, las entidades numéricas están permitidas en (y reconocidas por) tanto XML como HTML. – Tomalak

+0

@Tomalak Eso significa que tendría que conocer todas las entidades por nombre y su entidad numérica de antemano, ¿verdad? ¿Eso va a ser extremadamente intenso en el procesamiento si los agrego todos allí? -Ryan – NightHawk

1

Si desea convertir todos los caracteres, esto puede ayudar a que (lo escribí hace un tiempo):

http://www.lautr.com/convert-all-applicable-characters-to-numeric-entities-for-use-in-xml

function _convertAlphaEntitysToNumericEntitys($entity) { 
    return '&#'.ord(html_entity_decode($entity[0])).';'; 
} 

$content = preg_replace_callback(
    '/&([\w\d]+);/i', 
    '_convertAlphaEntitysToNumericEntitys', 
    $content); 

function _convertAsciOver127toNumericEntitys($entity) { 
    if(($asciCode = ord($entity[0])) > 127) 
    return '&#'.$asciCode.';'; 
    else 
    return $entity[0]; 
} 

$content = preg_replace_callback(
    '/[^\w\d ]/i', 
    '_convertAsciOver127toNumericEntitys', $content); 
+0

, si aplica "$ content = preg_replace_callback ('/ & ([\ w \ d] +);/i', '_ convertAlphaEntitysToNumericEntitys', $ content);" toda la entidad HTML (  y otras cosas) se cambiaría a entidades numéricas. Después de eso, aplique "$ content = preg_replace_callback ('/ [^ \ w \ d]/i', '_ convertAsciOver127toNumericEntitys'), $ content);" y cada caracter por encima de 127 (que no es manejado por htmlspecialchars) se convierte en una entidad numérica, si lo entiendo mal, ¿puedes dar un fragmento de ejemplo de Entrada? – Hannes

+0

lo siento, entendí mal lo que hizo su código. Borrando mi comentario anterior – LarsH

4

1 . I can find and replace all [   ?] and swap them out with [   ?] or an actual space.

Este es un método robusto, pero que requiere tener una tabla de todas las entidades HTML (supongo que la entrada pegada proviene de HTML) y analizar el texto pegado para referencias de entidad.

2 . I can place the code in question within a CDATA section.

En otras palabras, deshabilitar el análisis para toda la sección? Entonces tendrías que analizarlo de otra manera. Podría funcionar.

3 . I can include these entities within the XML file.

¿Quiere decir incluir las definiciones de entidad? Creo que esta es una manera fácil y sólida, si no te importa hacer que el archivo XML sea un poco más grande. Podría tener un archivo "incluido" (encuentre uno en la web) que es una entidad externa, a la que hace referencia desde la parte superior de su archivo XML principal.

Un inconveniente es que el analizador XML que utiliza debe ser uno que procese entidades externas (que no todos los analizadores deben hacer). Y debe resolver correctamente la URL (posiblemente relativa) de la entidad externa a algo accesible. Esto no es tan malo, pero puede aumentar las limitaciones en sus herramientas de procesamiento.

4. Puede prohibir que no XML en el contenido pegado. Entre otras cosas, esto no permitiría referencias de entidades que no estén predefinidas en XML (las 5 mencionadas por Tomalak) o definidas en el contenido mismo. Sin embargo, esto puede violar los requisitos de la aplicación, si los usuarios deben poder pegar HTML allí.

5. Puede analizar el contenido pegado como HTML en un árbol DOM al establecer someDiv.innerHTML = thePastContent; En otras palabras, crea un div en alguna parte (probablemente display = none, excepto para la depuración). Supongamos que tiene una variable de JavaScript myDiv que contiene este elemento div y otra variable myField que contiene el elemento que es su campo de entrada de texto. A continuación, en javascript que hace

myDiv.innerHTML = myField.value; 

que toma el texto no analizada desde myField, lo analiza en un árbol DOM HTML y lo pega en myDiv como contenido HTML.

Luego utilizaría algún método basado en navegador para serializar (= "de-analizar") el árbol DOM de nuevo en XML. Ver por ejemplo this question. Luego envía el resultado al servidor como XML.

Si desea hacer esta corrección en el navegador o en el servidor (como @Hannes sugirió) dependerá del tamaño de los datos, cuán rápida debe ser la respuesta, qué tan robusto es su servidor y si usted se preocupan por los hackers que envían XML no bien formado a propósito.

+0

@Tomalak: ¿por qué ö se convertiría en & ouml ;? Cuando el texto se pone en innerhtml, ¿no se analizará en el dom como un solo carácter diéresis? – LarsH

+0

1. Probablemente sería demasiada sobrecarga, ¿verdad? 2. Pensándolo bien, esto parece contraproducente, así que voy a eliminar esa opción. 3. Además de que el archivo es más grande, ¿hay otras desventajas? Si no, diría que ese es el camino a seguir. 4. Sí, eso violaría los requisitos. 5. No entiendo esta solución. ¿Pueden proporcionar más detalles? -Ryan – NightHawk

+0

@Ryan, voy a editar mi respuesta para agregar detalles en 3 y 5. – LarsH

19

Acepto que se trata de un problema puramente de codificación. En PHP, así es como he resuelto este problema:

  1. Antes de pasar html fragmento de SimpleXMLElement constructor que decodificó usando html_entity_decode.

  2. Luego lo codificó utilizando utf8_encode().

$headerDoc = '<temp>' . utf8_encode(html_entity_decode($headerFragment)) . '</temp>'; 
$xmlHeader = new SimpleXMLElement($headerDoc); 

Ahora el código anterior no lanzan cualquier error entidad indefinida.

+7

Es posible que pueda escapar sin usar 'utf8_encode' si le da' 'UTF-8" 'a [' html_entity_decode'] (http://php.net/manual/en/function.html-entity-decode. php) como el tercer parámetro, por ejemplo 'html_entity_decode ($ headerFragment, null," UTF-8 ")' –

0

Esta pregunta es un problema general para cualquier lenguaje que analice XML o JSON (por lo tanto, básicamente, en todos los idiomas).

Las respuestas anteriores son para PHP, Perl, sino una solución sería tan fácil como ...

my $excluderegex = 
    '^\n\x20-\x20' . # Don't Encode Spaces 
     '\x30-\x39' . # Don't Encode Numbers 
     '\x41-\x5a' . # Don't Encode Capitalized Letters 
     '\x61-\x7a' ; # Don't Encode Lowercase Letters 

    # in case anything is already encoded 
$value = HTML::Entities::decode_entities($value); 

    # encode properly to numeric 
$value = HTML::Entities::encode_numeric($value, $excluderegex); 
Cuestiones relacionadas