Erreur D'analyseur XML: entité non définie
j'ai cherché stackoverflow sur ce problème et j'ai trouvé quelques sujets, mais je pense qu'il n'y a pas vraiment une réponse solide pour moi sur ce sujet.
j'ai un formulaire que les utilisateurs soumettent et la valeur du champ est stockée dans un fichier XML. Le XML est défini pour être encodé avec UTF-8.
de temps en temps un utilisateur va copier/coller du texte de quelque part et c'est là que j'obtiens"l'erreur d'entité non définie".
je réalise que XML supporte seulement une sélection de quelques entités et rien au-delà qui n'est pas reconnu - d'où l'erreur de l'analyseur.
D'après ce que j'ai compris, il y a quelques options que j'ai vues:
- je peux trouver et remplacer tous les
et les échanger avec - je peux placer le code en question dans une section CDATA.
- je peux inclure ces entités dans le fichier XML.
ce que je fais avec le fichier XML, c'est que l'utilisateur peut entrer du contenu dans un formulaire, qu'il est stocké dans un fichier XML, et que le contenu est ensuite affiché en XHTML sur une page Web (avec SimpleXML).
des trois options, ou de toute autre option dont je ne suis pas au courant, Quelle est vraiment la meilleure façon de traiter avec ces entités?
Merci, Ryan
mise à JOUR
I tiens à remercier tout le monde pour le grand retour. J'ai en fait déterminé ce qui a causé mes erreurs d'entity. Toutes les suggestions m'ont fait regarder plus profondément!
quelques boîtes de texte où de vieilles boîtes de texte simples, mais mes textareas ont été améliorées avec TinyMCE. Il s'avère, en y regardant de plus près, que les Avertissements PHP référencent toujours les données des textareas améliorées de TinyMCE. Plus tard j'ai remarqué sur un PC que tous les personnages étaient sortis( parce qu'il ne pouvait pas les lire), mais sur un MAC vous pourriez voir des petites cases carrées se référant au numéro unicode de ce caractère. La raison pour laquelle il est apparu dans les carrés sur un MAC en premier lieu, est parce que j'ai utilisé utf8_encode pour encoder des données qui n'étaient pas dans UTF pour empêcher d'autres erreurs d'analyse (qui est en quelque sorte également liée à TinyMCE).
la solution à tout cela était très simple:
j'ai ajouté cette ligne entity_encoding : "utf-8"
dans mon tinyMCE.initialisation. Maintenant, tous les personnages apparaissent comme ils sont supposés de.
je suppose que la seule chose que je ne comprends pas c'est pourquoi les caractères apparaissent toujours lorsqu'ils sont placés dans des boîtes de texte, parce que rien ne les convertit en UTF, mais avec TinyMCE c'était un problème.
5 réponses
je conviens qu'il s'agit purement d'une question d'encodage. En PHP, c'est comme ça que j'ai résolu ce problème:
-
avant de passer le fragment html au constructeur
SimpleXMLElement
Je l'ai décodé en utilisanthtml_entity_decode
. -
puis encodé en utilisant
utf8_encode()
.
$headerDoc = '<temp>' . utf8_encode(html_entity_decode($headerFragment)) . '</temp>';
$xmlHeader = new SimpleXMLElement($headerDoc);
maintenant le code ci-dessus ne jette pas de entité non définie erreur.
vous pourriez HTML-parse le texte et l'avoir ré-échappé avec les entités numériques respectives seulement (comme:
→  
). Dans tous les cas-tout simplement en utilisant l'utilisateur non-épuré entrée est une mauvaise idée.
toutes les entités numériques sont autorisées en XML, seules les entités nommées connues en HTML ne fonctionnent pas (à l'exception de &
, "
, <
, >
, '
).
Most du temps, vous pouvez simplement écrire le caractère réel ( ö
→ ö
) dans le fichier XML, donc il n'est pas nécessaire d'utiliser une entité de référence. Si vous utilisez une API DOM pour manipuler votre XML (et vous devriez!) c'est votre pari le plus sûr.
enfin (c'est la solution de développeur paresseux) vous pourriez construire un fichier XML cassé (i.e. pas bien formé, avec des erreurs d'entity) et juste passer par tidy pour les corrections nécessaires. Ce peut fonctionner ou peut échouer selon juste comment cassé l'ensemble de la chose est. Dans mon expérience, bien rangé est assez intelligent, cependant, et vous permet d'obtenir beaucoup de lui.
1
. Je peux trouver et remplacer tout [
?] et les échanger avec [ 
?] ou un espace réel.
c'est une méthode robuste, mais elle exige que vous ayez une table de toutes les entités HTML (je suppose que l'entrée collée vient de HTML) et d'analyser le texte collé pour les références d'entités.
2
. Je peux placer le code en question dans une section CDATA.
en d'autres termes disable parsing pour toute la section? Ensuite, vous avez à analyser d'une autre manière. Pourrait fonctionner.
3
. Je peux inclure ces entités dans le fichier XML.
vous voulez dire inclure les définitions d'entité? Je pense que c'est un moyen facile et robuste, si vous ne vous gênez pas de faire le fichier XML un peu plus grand. Vous pourriez avoir un fichier "inclus" (en trouver un sur le web) qui est une entité externe, que vous référencez à partir du haut de votre fichier XML principal.
un inconvénient est que L'analyseur XML que vous utilisez doit être celui qui traite les entités externes (ce que tous les analyseurs ne sont pas tenus de faire). Et il doit correctement résoudre L'URL (éventuellement relative) de l'entité externe à quelque chose d'accessible. Ce n'est pas si mal, mais cela peut augmenter les contraintes sur vos outils de traitement.
4
. Vous pourriez interdire le non-XML dans le contenu collé. Entre autres choses, cela exclurait les références d'entités qui ne sont pas prédéfinies dans XML (les 5 Que Tomalak a mentionnés) ou définies dans le contenu lui-même. Toutefois, cela peut violer les exigences de l'application, si les utilisateurs ont besoin d'être en mesure de coller HTML là-dedans.
5
. Vous pouvez analyser le contenu collé en HTML dans un arbre DOM en paramétrant someDiv.innerHTML = theastedcontent;
En d'autres termes, créer une div quelque part (probablement display=none, excepté pour le débogage). Supposons que vous ayez une variable javascript myDiv
qui contient cet élément div, et une autre variable myField
qui contient l'élément qui est votre champ de texte d'entrée. Puis en javascript vous faites
myDiv.innerHTML = myField.value;
qui prend le texte sans équivalent de myField, le parse dans un arbre de DOM HTML, et le colle dans myDiv comme contenu HTML.
alors vous utiliseriez une méthode basée sur le navigateur pour sérialiser (="de-parsing") L'arbre DOM de nouveau dans XML. Voir par exemple cette question . Ensuite, vous envoyez le résultat au serveur en XML.
si vous voulez faire cette correction dans le navigateur ou sur le serveur (comme @Hannes l'a suggéré) dépendra de la taille des données, de la rapidité de la réponse doit être, comment beefy votre serveur est, et si vous vous souciez des pirates envoyant XML pas bien formé exprès.
si vous voulez convertir tous les caractères, cela peut vous aider (je l'ai écrit il y a un moment):
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);
cette question Est Un Problème général pour toute langue qui analyse XML ou JSON (donc, essentiellement, chaque langue).
les réponses ci-dessus sont pour PHP, mais une solution Perl serait aussi facile que...
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);