OVH Cloud OVH Cloud

construction de liste (html)

6 réponses
Avatar
newdb
bonsoir toutes et tous,

je n'arrive pas à résoudre un problème de mise en forme de liste.
une requête (mysql) me ramène un tableau du style :

Livre_1 ; Chapitre_1 ; Paragraphe_1 ; Alinéa_1
Livre_1 ; Chapitre_1 ; Paragraphe_1 ; Alinéa_2
Livre_1 ; Chapitre_1 ; Paragraphe_2 ; Alinéa_1
Livre_1 ; Chapitre_1 ; Paragraphe_2 ; Alinéa_2
Livre_1 ; Chapitre_1 ; Paragraphe_2 ; Alinéa_3
Livre_1 ; Chapitre_12 ; Paragraphe_T ; Alinéa_1a
Livre_1 ; Chapitre_1 ; Paragraphe_T ; Alinéa_b
Livre_1 ; Chapitre_1 ; Paragraphe_Y ; Alinéa_1
Livre_1 ; Chapitre_1 ; Paragraphe_1 ; Alinéa_bc
Livre_1 ; Chapitre_1 ; Paragraphe_1 ; Alinéa_x
Livre_2 ; Chapitre_A ; Paragraphe_A ; Alinéa_a
Livre_2 ; Chapitre_A ; Paragraphe_A ; Alinéa_b
Livre_2 ; Chapitre_A ; Paragraphe_B ; Alinéa_1a
Livre_2 ; Chapitre_A ; Paragraphe_B ; Alinéa_1b
Livre_2 ; Chapitre_A ; Paragraphe_B ; Alinéa_1c

je cherche à obtenir ça :

<li>Livre_1
<ul>
<li>Chapitre_1
<ul>
<li>Paragraphe_1
<ul>
<li>Alinéa_1</li>
<li>Alinéa_2</li>
</ul>
</li>
<li>Paragraphe_2
<ul>
<li>Alinéa_1</li>
<li>Alinéa_2</li>
<li>Alinéa_3</li>
</ul>
</li>
</ul>
</li>
<li>Chapitre_12
<ul>
<li>Paragraphe_T
<ul>
<li>Alinéa_1a</li>
<li>Alinéa_b</li>
</ul>
</li>
<li>Paragraphe_Y
<ul>
<li>Alinéa_1</li>
<li>Alinéa_bc</li>
<li>Alinéa_x</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Livre_2
<ul>
<li>Chapitre_A
<ul>
<li>Paragraphe_A
<ul>
<li>Alinéa_a</li>
<li>Alinéa_b</li>
</ul>
</li>
<li>Paragraphe_B
<ul>
<li>Alinéa_1a</li>
<li>Alinéa_1b</li>
<li>Alinéa_1c</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>

j'ai bien essayé avec une variable temporaire (dans ma boucle while qui
lit tout mon tableau) :

[ ... ]

$tmp = "";
while ($tableau = mysql_fetch_array($idresultat)) {
if ($tableau[Paragraphe'] != $tmp) {
$tmp = $tableau['Paragraphe'];
echo "<li>".$tableau['Paragraphe'])."\r\n";
echo"<ul>\r\n";
}
}
echo"<li>".$tableau['Alinea'])."</li>\r\n";
}
echo"</ul>\r\n";
echo"</li>\r\n";

[ ... ]

mais je n'arrive qu'à coder un niveau et il m'en faudrait quatre.

si quelqu'un (qu'une) pouvait m'indiquer une piste (heu, vu mon niveau,
plutôt balisée quand même, la piste...) je lui en serais bien
reconnaissant.


--
@@@@@
E -00 comme on est very beaux dis !
' `) /
|\_ =="

6 réponses

Avatar
Olivier Miakinen

[...]

j'ai bien essayé avec une variable temporaire (dans ma boucle while qui
lit tout mon tableau) :

$tmp = "";
while ($tableau = mysql_fetch_array($idresultat)) {
if ($tableau[Paragraphe'] != $tmp) {
$tmp = $tableau['Paragraphe'];
echo "<li>".$tableau['Paragraphe'])."rn";
echo"<ul>rn";
}
}
echo"<li>".$tableau['Alinea'])."</li>rn";
}
echo"</ul>rn";
echo"</li>rn";

mais je n'arrive qu'à coder un niveau et il m'en faudrait quatre.


Eh bien tu fais la même chose, mais avec trois variables temporaires,
$tmp_livre, $tmp_chap, $tmp_paragr. Pas besoin d'en avoir une pour
l'alinéa, car je suppose qu'il change à chaque fois.

Cela devrait donner quelque chose comme cela, où je te laisse rajouter
indentation et sauts de ligne à ta guise. Note qu'à chaque fois que la
variable $tmp_XXX d'un niveau change, toutes les variables $tmp_YYY des
sous-niveaux sont réinitialisées à la valeur vide "" (ce qui explique
mon commentaire de la deuxième ligne, comme quoi il est normalement
inutile de les initialiser au début).


$tmp_livre = "";
$tmp_chap = $tmp_paragr = ""; /* a priori inutile */

while ($tableau = mysql_fetch_array($idresultat)) {

if ($tableau['Livre'] != $tmp_livre) {
if ($tmp_livre != "") {
/* On change de livre, ce n'est pas le premier */
/* ferme paragraphe + chapitre + livre */
echo "</ul></li></ul></li></ul></li>";
}
$tmp_livre = $tableau['Livre'];
$tmp_chap = "";
/* ouvre un nouveau livre */
echo "<li>".$tmp_livre."<ul>";
}

if ($tableau['Chapitre'] != $tmp_chap) {
if ($tmp_chap != "") {
/* nouveau chapitre dans le même livre */
/* ferme paragraphe + chapitre */
echo "</ul></li></ul></li>";
}
$tmp_chap = $tableau['Chapitre'];
$tmp_paragr = "";
/* ouvre un nouveau chapitre dans le livre */
echo "<li>".$tmp_chap."<ul>";
}

if ($tableau['Paragraphe'] != $tmp_paragr) {
if ($tmp_paragr != "") {
/* nouveau paragraphe dans le même chapitre */
/* ferme paragraphe */
echo "</ul></li>";
}
$tmp_paragr = $tableau['Paragraphe'];
/* ouvre un nouveau paragraphe dans le chapitre */
echo "<li>".$tmp_paragr."<ul>";
}

/* écrit un nouvel alinéa dans un paragraphe */
echo "<li>".$tableau['Alinea']."</li>";

} /* fin while */

if ($tmp_livre != "") {
/* ferme paragraphe + chapitre + livre */
echo "</ul></li></ul></li></ul></li>";
}

Avatar
Olivier Miakinen

si quelqu'un (qu'une) pouvait m'indiquer une piste (heu, vu mon niveau,
plutôt balisée quand même, la piste...) je lui en serais bien
reconnaissant.


Une autre idée, suite à ma première réponse. Cette autre méthode a
probablement l'avantage de gagner en lisibilité.

À partir de ton tableau initial, tu construis un arbre, soit avec des
tableaux imbriqués, soit avec des classes et objets, et ensuite tu n'as
plus qu'à écrire en HTML le contenu de l'arbre. J'ai la flemme de
détailler, mais si cela peut t'aider...

Avatar
Bruno Desthuilliers
denisb wrote:
bonsoir toutes et tous,

je n'arrive pas à résoudre un problème de mise en forme de liste.
une requête (mysql) me ramène un tableau du style :

(snip resultat requete et code HTML désiré)


j'ai bien essayé avec une variable temporaire (dans ma boucle while qui
lit tout mon tableau) :

(snip code)


mais je n'arrive qu'à coder un niveau et il m'en faudrait quatre.

si quelqu'un (qu'une) pouvait m'indiquer une piste


Utilise autant de variables temporaires que nécessaire...

(heu, vu mon niveau,
plutôt balisée quand même, la piste...) je lui en serais bien
reconnaissant.



Bon, alors d'abord quelques notions générales, puis des solutions
pratiques (la 'bonne solution' (tm) est tout en bas du post, solution
n°3...)

<theorie-generale>
Ta structure (livre/chapitre/alinea/etc...) est une arborescence (ie :
comme un système de fichiers avec les dossiers et les documents).
Traditionnellement, pour travailler sur des arborescences, on utilise
des fonction 'récursives' (qui se rapellent elles-mêmes).

exemple de fonction récursive pour afficher le contenu d'un répertoire :
(Q&D, et non testé)

function affrep($chemin_racine) {
echo "<ul>";
echo "<li> dossier $chemin_racine</li>n";

$d = dir($chemin_racine);
while ($entry = $d->read()) {
$chemin_courant = $chemin_racine . '/$entry';

if (is_file($chemin_courant)) {
echo "<li>fichier $chemin_courant</li>n";
}
elseif (is_dir($chemin_courant)) {
// appel recursif
affrep($chemin_courant);
}
}

echo "</ul>n";
}
</theorie-generale>


Ca, c'était pour étaler ma science... Tu n'aura a priori pas besoin
d'une telle solution, puisque dans ton cas, tu a l'avantage d'avoir une
'profondeur' fixe (4 niveaux) et bien définie.

<solution num='1' type='QuickAndDirty'>
Je suppose que le schema de ta base est quelquechose comme :

livre (*id_livre*, titre_livre, ...)
chapitre(*id_livre*, *id_chapitre*, titre_chapitre, ...)
paragraphe(*id_livre*, *id_chapitre*, *id_para*, titre_para,...)
alinea(*id_livre*, *id_chapitre*, *id_para*, *id_alinea*, ...)

Tu a donc la possibilité de 'décomposer' la requête :

$livres = requete_livres(); // renvoie la liste des livres
echo "<ul>n";
foreach ($livres as $livre) {
echo "<li>" . $livre['titre_livre'] . "</li>n";
// renvoie la liste des chapitres pour le livre 'id_livre'
$chapitres = requete_chapitres($livre['id_livre']);
echo "<ul>n";
foreach ($chapitres as $chapitre) {
echo "<li>" . $chapitre['titre_chapitre'] . "</li>n";
// renvoie la liste des paragraphes pour
// le livre 'id_livre' et le chapitre 'id_chapitre'
$paras = requete_paras($livre['id_livre'],
$chapitre['id_chapitre']);
echo "<ul>n";
foreach ($paras as $para) {
echo "<li>" . $para['titre_para'] . "</li>n";
// renvoie la liste des alineas pour
// le livre 'id_livre' et le chapitre 'id_chapitre'
// et le paragraphe 'id_para'
$alineas = requete_alineas($livre['id_livre'],
$chapitre['id_chapitre'],
$para['id_para']
);

echo "<ul>n";
foreach ($alineas as $alinea) {
echo "<li>" . $para[???] . "</li>n";
}
echo "</ul>n";
} // paras
echo "</ul>n";
} // chapitres
echo "</ul>n";
} // livres
echo "</ul>n";

C'est la solution la plus simple du point de vue conception et codage.
Par contre, pour ce qui est des perfs, c'est plus que moyen faible -
disons que ça va pour faire la navigation dans un (petit) site, mais
guère plus.
</solution>

<solution num='2' type='Cleaner'>
Prémisses d'une solution 'propre' (dans ton cas du moins): utiliser
autant de variables temporaires que nécessaire :

<?php
// pour test...
$data = Array(
Array("livre"=>"Livre_1", "chapitre"=>"Chapitre_1",
"para"=>"Paragraphe_1", "alinea"=>"Alinéa_1"),
Array("livre"=>"Livre_1", "chapitre"=>"Chapitre_1",
"para"=>"Paragraphe_1", "alinea"=>"Alinéa_2"),
Array("livre"=>"Livre_1", "chapitre"=>"Chapitre_1",
"para"=>"Paragraphe_2", "alinea"=>"Alinéa_1"),
Array("livre"=>"Livre_1", "chapitre"=>"Chapitre_1",
"para"=>"Paragraphe_2", "alinea"=>"Alinéa_2"),
Array("livre"=>"Livre_1", "chapitre"=>"Chapitre_1",
"para"=>"Paragraphe_2", "alinea"=>"Alinéa_3"),
Array("livre"=>"Livre_1", "chapitre"=>"Chapitre_12",
"para"=>"Paragraphe_T", "alinea"=>"Alinéa_1a"),
Array("livre"=>"Livre_1", "chapitre"=>"Chapitre_1",
"para"=>"Paragraphe_T", "alinea"=>"Alinéa_b"),
Array("livre"=>"Livre_1", "chapitre"=>"Chapitre_1",
"para"=>"Paragraphe_Y", "alinea"=>"Alinéa_1"),
Array("livre"=>"Livre_1", "chapitre"=>"Chapitre_1",
"para"=>"Paragraphe_1", "alinea"=>"Alinéa_bc"),
Array("livre"=>"Livre_1", "chapitre"=>"Chapitre_1",
"para"=>"Paragraphe_1", "alinea"=>"Alinéa_x"),
Array("livre"=>"Livre_2", "chapitre"=>"Chapitre_A",
"para"=>"Paragraphe_A", "alinea"=>"Alinéa_a"),
Array("livre"=>"Livre_2", "chapitre"=>"Chapitre_A",
"para"=>"Paragraphe_A", "alinea"=>"Alinéa_b"),
Array("livre"=>"Livre_2", "chapitre"=>"Chapitre_A",
"para"=>"Paragraphe_B", "alinea"=>"Alinéa_1a"),
Array("livre"=>"Livre_2", "chapitre"=>"Chapitre_A",
"para"=>"Paragraphe_B", "alinea"=>"Alinéa_1b"),
Array("livre"=>"Livre_2", "chapitre"=>"Chapitre_A",
"para"=>"Paragraphe_B", "alinea"=>"Alinéa_1c")
);

// les variables temporaires
$livre_courant = "";
$chap_courant = "";
$para_courant = "";

// nb : pas besoin de variable temporaire pour
// les alineas qui seront toujours affichés

echo "<ul>n";
//while ($tableau = mysql_fetch_array($idresultat)) {
foreach($data as $tableau) {

// livres
if ($tableau['livre'] != $livre_courant) {
// si on n'est pas sur le premier livre,
// il faut fermer les balises ul précédentes
// (livre, chapitre et para)
if (! empty ($livre_courant)) {
echo "</ul>n</ul>n</ul>n";
}

$livre_courant = $tableau['livre'];
// on n'oublie pas de réinitialiser les chapitres
$chapitre_courant = "";

// et on commence la nouvelle liste
echo "<li>$livre_courant</li>n";
echo "<ul>n";

}

// chapitres
if ($tableau['chapitre'] != $chapitre_courant) {
// si on n'est pas sur le premier chapitre du livre,
// il faut fermer les balises ul précédentes (chapitre et para)
if (! empty ($chapitre_courant)) {
echo "</ul>n</ul>n";
}
$chapitre_courant = $tableau['chapitre'];
// on n'oublie pas de réinitialiser les paragraphes
$para_courant = "";

// et on commence la nouvelle liste
echo "<li>$chapitre_courant</li>n";
echo "<ul>n";
}

// paragraphes
if ($tableau['para'] != $para_courant) {
// si on n'est pas sur le premier paragraphe du chapitre,
// il faut fermer la balise ul précédente (para)
if (! empty ($para_courant)) {
echo "</ul>n";
}
$para_courant = $tableau['para'];

// et on commence la nouvelle liste
echo "<li>$para_courant</li>n";
echo "<ul>n";
}

// alinea : on affiche de toutes façons
echo "<li>" . $tableau['alinea'] . "</li>n";
}
echo "</ul>n</ul>n</ul>n</ul>n";
?>

Tu remarquera dans ce code pas mal de répétitions... Le traitement des
changement de livre/chapitre/para est structurellement invariant, seuls
quelques paramètres changent.

Ceci appelle bien évidemment une factorisation...
</solution>


<solution num='3' type='Clean'>
Après factorisation des redondances, on arrive à ça :

<?php
//$data -> cf snippet précédent

$courant = Array('livre'=>'', 'chapitre'=>'', 'para'=>'');

function
affiche(&$tab, &$courant, $section, $niveau, $section_suivante=null)
{
if ($tab[$section] != $courant[$section]) {
// si on n'est pas sur le premier livre,
// il faut fermer les balises ul précédentes
if (! empty ($courant[$section])) {
for($i = 0; $i < $niveau; $i++) {
echo "</ul>n";
}
}

$courant[$section] = $tab[$section];
// on n'oublie pas de réinitialiser la section suivante
if ($section_suivante) {
$courant[$section_suivante] = "";
}
// et on commence la nouvelle liste
echo "<li>" . $tab[$section] . "</li>n";
echo "<ul>n";
}
}

echo "<ul>n";
//while ($tableau = mysql_fetch_array($idresultat)) {
foreach($data as $tableau) {

// livres
affiche($tableau, $courant, 'livre', 3, 'chapitre');

// chapitres
affiche($tableau, $courant, 'chapitre', 2, 'para');

// paragraphes
affiche($tableau, $courant, 'para', 1);

// alinea
echo "<li>" . $tableau['alinea'] . "</li>n";
}
echo "</ul>n</ul>n</ul>n</ul>n";
?>
</solution>

Voili voila... ne te reste plus qu'à adapter à ton besoin. (pour les
honoraires, j'acceptes les règlements en CB, chèques et espèces !-)

HTH
Bruno

Avatar
Olivier Miakinen

<solution num='2' type='Cleaner'>
Prémisses d'une solution 'propre' (dans ton cas du moins): utiliser
autant de variables temporaires que nécessaire :

[...]

// et on commence la nouvelle liste
echo "<li>$para_courant</li>n";
echo "<ul>n";


Nous sommes *presque* d'accord.

La différence essentielle entre ton exemple et le mien, c'est que tu
fermes les <li> trop tôt, en imbriquant donc un <ul> directement dans un
autre <ul>, ce qui -- à mon humble avis -- n'est pas valide.

Tu peux noter que l'exemple de denisb n'avait pas ce défaut :

<li>Paragraphe_2
<ul>
<li>Alinéa_1</li>
<li>Alinéa_2</li>
<li>Alinéa_3</li>
</ul>
</li>




Voili voila... ne te reste plus qu'à adapter à ton besoin. (pour les
honoraires, j'acceptes les règlements en CB, chèques et espèces !-)


Ah oui, moi aussi. ;-)


Avatar
Bruno Desthuilliers
Olivier Miakinen wrote:

<solution num='2' type='Cleaner'>
Prémisses d'une solution 'propre' (dans ton cas du moins): utiliser
autant de variables temporaires que nécessaire :

[...]

// et on commence la nouvelle liste
echo "<li>$para_courant</li>n";
echo "<ul>n";



Nous sommes *presque* d'accord.

La différence essentielle entre ton exemple et le mien, c'est que tu
fermes les <li> trop tôt, en imbriquant donc un <ul> directement dans un
autre <ul>, ce qui -- à mon humble avis -- n'est pas valide.


Au temps pour moi, tu a bien sûr raison. Depuis que je bosse dans une
agence Web, je ne fais presque plus de HTML !-)


Voili voila... ne te reste plus qu'à adapter à ton besoin. (pour les
honoraires, j'acceptes les règlements en CB, chèques et espèces !-)



Ah oui, moi aussi. ;-)


<OP>
denis, si tu nous entends !-)
</OP>

Bruno


Avatar
newdb
<OP>
denis, si tu nous entends !-)
</OP>


oui oui oui. clair et fort...
grand merci donc (avec un petit retard)
à vous deux (bruno et olivier) !

--
@@@@@
E -00 comme on est very beaux dis !
' `) /
|_ =="