Bonjour
J'ai un petit problème de codage de données dont je n'arrive pas à me dépêtrer:
- mes données sont toutes dans des fichiers XML, du genre
<event startDate="2014-03-10" endDate="2014-03-13">
<location>
<name>.......</name>
<address>.......</address>
..........................
</location>
</event>
- mon code en php génère le html pour afficher cet "événement".
Or il ce trouve que l'endroit où se tient cet événement (une exposition artistique) s'appelle "Art&Culture".

J'ai donc mis dans le fichier <name>Art&amp;Culture</name>

Ça marche comme escompté, le résultat dans ma feuille html devient "Art&Culture". Seulement le validateur me dit que ce & est illégal est devrait être remplacé par &amp;

Parfaitement d'accord, mais il ne faut pas pour autant que d'autres caractères codés sous la forme &abcd; ou &#1234; soient affectés.
Pour l'instant j'ignore l'alerte du validateur, mais j'aimerais bien trouver une solution, soit en codant différemment le fichier de données, soit en trouvant un moyen de transcoder les chaînes de caractères comprenant des & sans risque de confusion.

Merci de vos propositions.
Modifié par PapyJP (01 Feb 2014 - 10:55)
Bonjour,

je n'arrive pas bien à comprendre le problème.
Si il y a &amp; dans les données , cela devrait laisser &amp; dans le code source html et afficher seulement & sur le rendu de la page html par le navigateur. Du coup le validateur devrait lire &amp; dans le code source et ne pas poser de problème.

Est ce possible d'avoir un lien vers la page html, ainsi que le code qui fait la transformation du xml vers le html.

Bonne journée
Merci Mathieu
Je vous ferai une réponse plus détaillée en rentrant chez moi ce soir.
Bonsoir

J'ai fait un petit programme de test http://tests.bonieux.com/html/amp-test.php
Les données sont dans http://tests.bonieux.com/html/expos.xml

Ce qu'on constate: la page générée est ce que j'escomptais (sachant que je n'ai pas mis de CSS pour avoir une présentation correcte).
MAIS: si on regarde le code généré (Ctrl-U) on voit dans le texte des caractères "&" qui devraient théoriquement être écrits "&amp;".
Les navigateurs laissent passer, mais les validateurs ne sont pas satisfaits.

Pour l’instant je laisse courir, mais je cherche une solution qui me permettrait de détecter les "vrais" "&" pour les coder "&amp;" et les distinguer des "&quot;" ou autres "&#339; nécessaire au codage de certains caractères ( "&#339; = codage de &oelig;)

Pour cela il faudrait savoir faire un preg_replace sur le texte, mais je ne suis pas arrivé à faire une expression régulière convenable.

J'espère avoir été plus clair que dans le premier message de ce fil.
Modérateur
PapyJP a écrit :
Pour l’instant je laisse courir, mais je cherche une solution qui me permettrait de détecter les &quot;vrais&quot; &quot;&amp;&quot; pour les coder &quot;&amp;amp;&quot; et les distinguer des &quot;&amp;quot;&quot; ou autres &quot;&amp;#339; nécessaire au codage de certains caractères ( &quot;&amp;#339; = codage de &amp;oelig;).


Bonsoir. Une expression régulière pour chasser tous les & du texte sant toucher aux entités me paraît délicat.
Par élimination:
– &#… c'est facile à éviter.
– &foo; c'est plus délicat, il faudrait soit un dico, soit chasser les formes & suivi de 2 à 8 caractères [a-zA-Z] et d'un point-virgule. En sachant que ça pourrait occasionnellement faire des faux positifs (probablement très rare).

Par contre, en travaillant en UTF-8, les seules entités nécessaires sont &amp;, et occasionellement &lt; &gt; le reste étant purement superflu. Ainsi il devient facile d'éviter ces 3 cas (ainsi que peut-être 2 ou trois autres que l'on jugerait pratique). Mais &quot; et &#339;, je ne vois pas vraiment l'intérêt.
kustolovic a écrit :
Par contre, en travaillant en UTF-8, les seules entités nécessaires sont &amp;amp;, et occasionnellement &amp;lt; &amp;gt; le reste étant purement superflu.

Est-ce que je comprends bien que vous proposez en fait d'écrire les fichiers .php en UTF-8?

Je ne croyais pas cela possible, ce qui m'avait conduit, sans que j'en aie vraiment conscience, à utiliser des codes &foo; ou &#xxx; pour mettre en page le contenu de mes fichiers xml.
Je vais configurer mon éditeur de texte pour mettre les fichiers php en UTF-8 et voir ce qui en résulte.

Merci de cette proposition: c'est le genre de choses "évidentes" auxquelles on ne pense pas!

Edit 10:40: cela semble effectivement fonctionner très bien!
Modifié par PapyJP (06 Feb 2014 - 10:42)
Modérateur
Oui c'est plutôt le standard actuellement. Sauf si on reprend un vieux projet que l'on ne souhaite pas tout transcoder, on travaille plutôt de base en utf-8, Smiley cligne
kustolovic a écrit :
Oui c'est plutôt le standard actuellement. Sauf si on reprend un vieux projet que l'on ne souhaite pas tout transcoder, on travaille plutôt de base en utf-8, Smiley cligne

Oui, j'ai toujours travaillé en base UTF-8 pour les données et les pages HTML, mais les fichiers php étaient réputés devoir être en codage "à l'ancienne".
J'aurais dû réfléchir que compte tenu que l'UTF-8 code les caractères US-ASCII sur 7 bits, on pouvait écrire les fichiers php en UTF-8 sans perturber l'interpréteur php d'Apache, pour autant que les caractères proprement UFT-8 sont des constantes du programme entre guillemets ou des données lues de fichiers XML.
Voilà ce que c'est d'être retraité: on a moins l'occasion de discuter avec des collègues et découvrir des choses qui sont évidentes... a posteriori.

Reste à faire le preg_replace aux petits oinions qui traitera le problème proprement dit... mais ce n'est pas réellement urgent.
Je vais plutôt donner la priorité à revoir mes fichiers de données pour enlever les codages &#xxx; superflus, en ne gardant que les &apos; &amp;, &lt; &gt; .. quoi d'autre encore?
Salut,

Est ce possible d'avoir le code de la page php qui fait la transformation ?
Moi je ne vois pas pourquoi il y a besoin de changer toutes les données en entrée ( que le codage des &xxxx; soit superflu ou non).
Dans le principe un &amp; en entrée dans les données doit resté un &amp; après transformation, et du coup je pense qu'un &amp; dans le code source de la page php sera valide pour le w3c. Et cela me semble valable aussi pour les autres &xxxx;
Modifié par mathieu1004 (07 Feb 2014 - 09:49)
mathieu1004 a écrit :
Est ce possible d'avoir le code de la page php qui fait la transformation ?

Le "vrai" code dans les "vraies" pages est inclus profondément dans des classes php qui s'appellent mutuellement. C'est pour cela que j'ai fait un petit programme de test http://tests.bonieux.com/html/amp-test.php qui utilise des données sont dans http://tests.bonieux.com/html/expos.xml

Le problème est d'éviter de générer des "&" qui sont refusés par les validateurs, même si apparemment les navigateurs les acceptent.

Apparemment quand le programme php lit le contenu du fichier xml qui contient un &amp;, il reçoit un caractère "&" et quand il génère le code HTML, il met donc un "&".
Il faudrait pouvoir dire: "remplacez les "&" par "&amp;", mais dans ce cas les caractères codés "&foo;" ou
"&#339;" ne seraient pas traités correctement".

Il faudrait donc faire un "preg_replace" astucieux pour traiter ce problème.

PS: par contre je ne suis pas sûr à 100% de ce que génère le php: je le récupère en effet par Ctrl-U sous Firefox, mais rien ne me dit que ce qu'affiche Firefox est exactement ce qu'il reçoit du serveur. Peut-être n'y a-t-il pas réellement de problème? Smiley eek
Modifié par PapyJP (07 Feb 2014 - 12:34)
Hum et je peux avoir le code php de la page amp-test.php ?
Histoire d'essayer de voir quelle fonction pourrait faire cette transformation de &amp; vers & :s.

Parce que si on regarde bien, le code source html de la page amp-test.php, on voit un &amp et un &quote mais je pense que ça ne vient pas du texte d'origine mais d'ajout dans votre traitement.
On voit que pour les données du xml, les &amps et le &#339;(oe) ont été transformés, ce qui me fait penser qu'une fonction transforme les entrées xml vers de l'utf-8. (et du coup logiquement (mis a part les ajouts perso) les seuls & qui vont rester seront les &amp d'origine)
Voici le code php inclus dans une page HTML


<?php
                $rootDir = $_SERVER['DOCUMENT_ROOT'];
                $eventDom = new DOMDocument();
                $eventFile = '/html/expos.xml';
                $eventDom -> load($eventFile);
                $xmlEventsElement = $eventDom -> documentElement;
                $xmlEvents = $xmlEventsElement -> getElementsByTagName('event');
                foreach($xmlEvents as $xmlEvent) {
                    $Event = new Event($xmlEvent);
                    echo $Event -> toHTML();
                }
                
                class Event {
                    var $name = '';
                    var $startDate = '';
                    var $endDate = '';
                    var $location = NULL;
                    public function __construct($xmlData = '') {
                        $xmlName = $xmlData -> getElementsByTagName('name') -> item(0);
                        $this -> name = $xmlName -> nodeValue;
                        $this -> startDate = $xmlData -> getAttribute('startDate');
                        $this -> endDate = $xmlData -> getAttribute('endDate');
                        $xmlLocation = $xmlData -> getElementsByTagName('location') -> item(0);
                        $this -> location = new Location($xmlLocation);
                    }
                   
                    function toHTML() {
                        $dateItem = '<span class="date">du ' . $this -> startDate . ' au ' . $this -> endDate . '</span>';
                        $expoItem = '<div class="title">Exposition &quot;' . $this -> name . '&quot;</div>';
                        $locationItem = $this -> location -> toHTML();
                        return '<div class="expo">' . $dateItem . $expoItem .$locationItem . '</div>' . "\n";
                    }
                }
                class Location {
                    var $name = '';
                    var $address = NULL;
                    public function __construct($xmlData = '') {
                        $xmlName = $xmlData -> getElementsByTagName('name') -> item(0);
                        $this -> name = $xmlName -> nodeValue;
                        $xmlAddress = $xmlData -> getElementsByTagName('address') -> item(0);
                        $this -> address = new Address($xmlAddress);
                    }
                    function toHTML() {
                        if($this -> name == '') $nameItem = '';
                        else $nameItem = '<div class="location_name">' . $this -> name . '</div>' . "\n";
                        return '<div class="location">' . $nameItem . $this -> address -> toHTML() . '</div>' . "\n";
                    }
                }
                class Address {
                    var $streetAddress = '';
                    var $addressLocality = '';
                    var $postalCode = '';
                    var $addressCountry = '';
                    public function __construct($xmlData = '') {
                        $xmlStreet = $xmlData -> getElementsByTagName('streetAddress') -> item(0);
                        $this -> streetAddress = $xmlStreet -> nodeValue;
                        $xmlLocality = $xmlData -> getElementsByTagName('addressLocality') -> item(0);
                        $this -> addressLocality = $xmlLocality -> nodeValue;
                        $xmlCode = $xmlData -> getElementsByTagName('postalCode') -> item(0);
                        $this -> postalCode = $xmlCode -> nodeValue;
                        $xmlCountry = $xmlData -> getElementsByTagName('addressCountry') -> item(0);
                        $this -> addressCountry = $xmlCountry -> nodeValue;
                    }
                    
                    function toHTML() {
                        if($this -> streetAddress == '') $streetItem = '';
                        else $streetItem = '<div class="street">' . $this -> streetAddress . '</div>' . "\n";
                        if($this -> postalCode == '') $codeItem = '';
                        else $codeItem = $this -> postalCode . " ";
                        if($this -> addressLocality == '') $localityItem = '';
                        else $localityItem = '<div class="locality">' . $codeItem . $this -> addressLocality . '</div>' . "\n";
                        if($this -> addressCountry == '') $countryItem = '';
                        else $countryItem = '<div class="country">' . $this -> addressCountry . '</div>' . "\n";
                        return '<div class="address">' . $streetItem . $localityItem . $countryItem . '</div>' . "\n";                       
                    }
                }
            ?>

La page HTML:
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="utf-8" />
        <title>Test &amp;amp;</title>
    </head>
    <body>
        <div>
            <h4>Expositions</h4>
            <?php /* voir le code ci-dessus */  ?>
        </div>
    </body>
</html>


Le fichier de données:

<?xml version="1.0" encoding="UTF-8"?>
<events>
    <event startDate="10/03/2014" endDate="13/03/2014">
        <name>Maison &amp; Objet</name>
        <location>
            <name>Art &amp; Culture</name>
            <address>
                <streetAddress>4 rue du Maréchal Joffre</streetAddress>
                <postalCode>27896</postalCode>
                <addressLocality>Le Haut C&#339;ur</addressLocality>
                <addressCountry lang="en">France</addressCountry>
            </address>
        </location>
    </event>
</events>
Bon ça confirme ce que je pensais que les &quote et &amp que l'on voit sont en dur dans le code et que le script php recupere les string interprété au lieu des strings du code source du xml.

Du coup quand on récupère les données du xml, il va falloir utiliser la fonction htmlspecialchars(); pour re transformer les caractères interprétés par le html en &xxx;
Cela devrait permettre de transformer les & mais aussi les guillemets et les < et > qui pourraient aussi poser.
Je viens de rentrer de week end et bien entendu je me suis précipité pour faire l'essai.
C'est vraisemblablement la bonne solution, mais il faut que je fasse attention aux effets de bords.
Mon générateur doit détecter dans quels cas utiliser ou non ce transcodage.
Je vais regarder cela à têt reposée.
Merci encore pour votre aide.
Modifié par PapyJP (09 Feb 2014 - 19:09)
Petit codicille:
Parti d'une recherche d'expression régulière complexe, j'en suis arrivé, grâce à vos conseils, à modifier l'encodage des fichiers *.php en UTF-8. À ce sujet je signale qu'il faut éviter un encodage "avec BOM". En effet cet encodage, qui permet d'indiquer qu'un fichier est en UTF-8 plutôt qu'en ASCII consiste à mettre un caractère spécifique (invisible en théorie) en tête de fichier. L'interpréteur php envoie ce caractère au client et il n'est donc plus possible de modifier les headers html par php, par exemple positionner un cookie.
L'expression régulière que je recherchais est remplacée avantageusement par htmlspecialchars().
Merci encore de votre aide!