2010-05-22 4 views
4

J'utilise SimpleXML pour charger des fichiers xml (que je n'ai pas écrits/fournis et que je ne peux pas vraiment changer le format).PHP - Traitement XML non valide

Occasionnellement (par exemple, un ou deux fichiers sur 50 environ), ils n'échappent pas aux caractères spéciaux (la plupart du temps &, mais parfois aussi d'autres éléments invalides). Cela crée et pose problème parce que SimpleXML avec php échoue juste, et je ne connais pas vraiment un bon moyen de gérer l'analyse XML invalide. Ma première idée était de pré-traiter le XML comme une chaîne et de mettre TOUS les champs comme CDATA pour que cela fonctionne, mais pour une raison impie le XML que j'ai besoin de traiter met toutes ses données dans les champs d'attributs. Donc je ne peux pas utiliser l'idée CDATA. Un exemple de l'être XML:

<Author v="By Someone & Someone" /> 

Quelle est la meilleure façon de traiter cette option pour remplacer tous les caractères non valides à partir du XML avant de le charger avec SimpleXML?

+0

si c'est juste le &, ne pouvez-vous y échapper avant le chargement? – Dormilich

+0

C'est plus que juste le & qui est invalide. – Paul

Répondre

6

Ce dont vous avez besoin est quelque chose qui va utiliser les erreurs internes de libxml pour localiser les caractères invalides et les échapper en conséquence. Voici une maquette de la façon dont je l'écrirais. Jetez un oeil au résultat de libxml_get_errors() pour l'information d'erreur.

function load_invalid_xml($xml) 
{ 
    $use_internal_errors = libxml_use_internal_errors(true); 
    libxml_clear_errors(true); 

    $sxe = simplexml_load_string($xml); 

    if ($sxe) 
    { 
     return $sxe; 
    } 

    $fixed_xml = ''; 
    $last_pos = 0; 

    foreach (libxml_get_errors() as $error) 
    { 
     // $pos is the position of the faulty character, 
     // you have to compute it yourself 
     $pos = compute_position($error->line, $error->column); 
     $fixed_xml .= substr($xml, $last_pos, $pos - $last_pos) . htmlspecialchars($xml[$pos]); 
     $last_pos = $pos + 1; 
    } 
    $fixed_xml .= substr($xml, $last_pos); 

    libxml_use_internal_errors($use_internal_errors); 

    return simplexml_load_string($fixed_xml); 
} 
+2

Poster un exemple de position de l'ordinateur serait pratique! –

2

Je pense que workaroung pour créer la fonction compute_position va rendre la chaîne xml plate avant le traitement. Code Rewrite publié par Josh:

function load_invalid_xml($xml) 
{ 
    $use_internal_errors = libxml_use_internal_errors(true); 
    libxml_clear_errors(true); 

    $sxe = simplexml_load_string($xml); 

    if ($sxe) 
    { 
     return $sxe; 
    } 

    $fixed_xml = ''; 
    $last_pos = 0; 

    // make string flat 
    $xml = str_replace(array("\r\n", "\r", "\n"), "", $xml); 

    // get file encoding 
    $encoding = mb_detect_encoding($xml); 

    foreach (libxml_get_errors() as $error) 
    { 
     $pos = $error->column; 
     $invalid_char = mb_substr($xml, $pos, 1, $encoding); 
     $fixed_xml .= substr($xml, $last_pos, $pos - $last_pos) . htmlspecialchars($invalid_char); 
     $last_pos = $pos + 1; 
    } 
    $fixed_xml .= substr($xml, $last_pos); 

    libxml_use_internal_errors($use_internal_errors); 

    return simplexml_load_string($fixed_xml); 
} 

J'ai ajouté l'encodage des choses becose j'ai eu des problèmes avec simplement tableau [index] moyen d'obtenir le caractère de chaîne.

Tout cela devrait fonctionner mais, ne sais pas pourquoi, j'ai vu que $ error-> column me donne un nombre différent de ce qu'il devrait. Essayer de déboguer cela en ajoutant simplement des caractères invalides dans xml et vérifier quelle valeur il reviendrait, mais pas de chance avec ça. J'espère que quelqu'un pourrait me dire ce qui ne va pas avec cette approche.

+0

Pendant que votre méthode s'exécute, elle ne résout pas mon problème particulier qui génère cette erreur. – pthurmond