Discussion:
Probleme de Librairie DOM
(trop ancien pour répondre)
DublinFrench
2009-10-04 13:12:17 UTC
Permalink
Salut

Je tente de remplacer des mots cles dans un contenu HTML mais je ne veux
pas remplacer des mots dans des liens, ou situés a l'interieurs de
définitions de tags (titles, ...). Je cherche a remplacer uniquement le
texte réel qui n'est pas situé a l'interieur de balises <a></a>.

Je me suis donc reporté sur la librairie DOM
http://us2.php.net/manual/en/book.dom.php

Mais j'ai des petits soucis avec cette librairie car je peux avoir du
cuntenu HTML dans mes $node->nodeValue meme si $node->hasChildNodes()
retourne false. Il y a meme des cas ou le $node->nodeValue est carrément
une balise HTML car commencant par <span ....

Voici une version réduite de mon script:

Class Parsing
{

public static $listforbiddenTags = array("a", "img", "javascript",
"css", "script");

public static function parseNodes($node, $keyWord, $replacement)
{
$node->normalize();
if ($node->hasChildNodes())
{
$subNodes = $node->childNodes;
foreach ($subNodes as $subNode)
{
parseNodes($subNode, $keyWord, $replacement);
}
}
else
{
if (!in_array($node->parentNode->nodeName,
self::$listforbiddenTags) && $node->nodeType == XML_TEXT_NODE
&& strlen(trim($node->wholeText))>=1 && used($node->nodeValue))
{
$newelement = self::$dom->createTextNode(str_replace($keyWord,
$replacement, $node->nodeValue));
$node->parentNode->replaceChild($newelement, $node);
$node->normalize();
}
}
}

}

$doc->loadHTML($content);
$root = $doc->firstChild;
$doc->normalizeDocument();
Parsing::$dom=$doc;
Parsing::parseNodes($doc, $keyWord, $replacement);


Merci pour vos idées :)

Cheers

DF




--
Mickael Wolff
2009-10-05 05:20:19 UTC
Permalink
Post by DublinFrench
if (!in_array($node->parentNode->nodeName,
self::$listforbiddenTags) && $node->nodeType == XML_TEXT_NODE
&& strlen(trim($node->wholeText))>=1 && used($node->nodeValue))
Tu devrais ranger ce test dans une fonction.
Post by DublinFrench
$newelement = self::$dom->createTextNode(str_replace($keyWord,
$replacement, $node->nodeValue));
Tu peux directement modifier DomNode::nodeValue.sur le noeud parent.

J'utiliserais domxpath :
<?php

$doc = @domdocument::load('http://localhost') ;
@$doc->validate() ;
$seeker = new domxpath($doc) ;

// je ne sais pas comment filtrer par un parent d'un certain type dans
xpath.
$txtList = $seeker->evaluate('//text()') ;

foreach($txtList as $txt)
{
if(isGoodText($txt))
replaceText($txt, array('Bienvenue', 'lettre'), array('Maljour',
'courrier')) ;
}

echo $doc->saveXML() ;

function isGoodText(domnode $txt)
{
$pn = $txt->parentNode ;
return !in_array($pn->tagName, array('a')) ;
}

function replaceText(domnode $txt, $key, $replacement)
{
$content = $txt->nodeValue ;
$txt->nodeValue = str_replace($key, $replacement, $content) ;
}
--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
DublinFrench
2009-10-05 08:27:50 UTC
Permalink
Post by Mickael Wolff
Post by DublinFrench
if (!in_array($node->parentNode->nodeName,
self::$listforbiddenTags) && $node->nodeType == XML_TEXT_NODE
&& strlen(trim($node->wholeText))>=1 &&
used($node->nodeValue))
Tu devrais ranger ce test dans une fonction.
Yep, tu as raison. Les trucs grossissent, grossissent, et apres il faut
aller les ranger. :)
Post by Mickael Wolff
<?php
Je vais aller regarder. La librairie DOM ne me permets pas de faire ce
que je désire, le HTML est mal parcouru. Par exemple, si un node
contient une balise <a> , on ne pourra pas travailler sur la chaine qui
suit la balise </a> mais qui est toujours dans le meme node.

Merci pour ton script que je vais aller tester de ce pas.

@++

DF
DublinFrench
2009-10-05 14:46:42 UTC
Permalink
Post by DublinFrench
Merci pour ton script que je vais aller tester de ce pas.
$content = "
<ul>
<li>title: possibility to <a href=\"www.test.com\">define the title</a>
from the link regards where this title is located</li>
</ul>
";

$doc = domdocument::load($content) ;
@$doc->validate() ;
$seeker = new domxpath($doc) ;


=> I/O warning : failed to load external entity

Bon c'est pas grave, j'ai bien avancé avec mes expressions régulières.
Cela me semble encore imparfait, mais visiblement jouer avec le DOM a
ses limites. J'ai des soucis comportementaux flagrants, du style ne pas
pouvoir accepter ce qui se situe _apres_ une balise html dans un node
qui est présenté comme étant du texte pure bien que contenant une
balise. regexp rulez for today.

@++

DF
Mickael Wolff
2009-10-05 22:40:22 UTC
Permalink
Post by DublinFrench
$doc = domdocument::load($content) ;
=> I/O warning : failed to load external entity
Il FAUT lire la documentation. Tu remarqueras que jevdonnais un
chemin vers un fichier, pas le contenu.
Post by DublinFrench
Bon c'est pas grave, j'ai bien avancé avec mes expressions régulières.
Cela me semble encore imparfait, mais visiblement jouer avec le DOM a
ses limites. J'ai des soucis comportementaux flagrants, du style ne pas
pouvoir accepter ce qui se situe _apres_ une balise html dans un node
qui est présenté comme étant du texte pure bien que contenant une
balise. regexp rulez for today.
Ca dépend de la qualité du HTML de base. Mais noramlement, il ne
devrait pas y avoir de problème. J'ai essayé moi-meme d'utiliser les
regex pour parser du HTML (PHP4). C'est difficile, il faut beaucoup de
méthode pour arriver à faire quelque chose de correct. Et si tu
n'arrives pas à utiliser le DOM, je ne pense pas que tu ais le niveau
nécessaire.

Utilises le DOM. Je te conseillerais de lire toute la documentation
pour avoir une vue d'ensemble des fonctionnalités.
--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
DublinFrench
2009-10-06 09:26:31 UTC
Permalink
Post by Mickael Wolff
Ca dépend de la qualité du HTML de base.
Ce point est malheureusement incontrolable. Le contenu saisie provient
d'un CK editor.


Mais noramlement, il ne
Post by Mickael Wolff
devrait pas y avoir de problème. J'ai essayé moi-meme d'utiliser les
regex pour parser du HTML (PHP4). C'est difficile, il faut beaucoup de
méthode pour arriver à faire quelque chose de correct.
Je suis arrivé a placer mes liens et tooltips sur mes mots clés non
situés dans des définitions de balises et n'étant pas déja un lien.
Post by Mickael Wolff
Et si tu
n'arrives pas à utiliser le DOM, je ne pense pas que tu ais le niveau
nécessaire.
Utilises le DOM. Je te conseillerais de lire toute la documentation
pour avoir une vue d'ensemble des fonctionnalités.
Le DOM a ses limites qui m'empechent de faire les choses correctements.

Exemple:

content = "
<ul>
<li>title: possibility to <a href=\"www.test.com\">define the
title</a> from the link regards where this title is located</li>
</ul>
";

Class Parsing
{
public static $listforbiddenTags = array("a", "img", "javascript",
"css", "script");
public static $dom = null;

function parseNodes($node, $keyWord, $replacement)
{
if ($node->hasChildNodes())
{
$subNodes = $node->childNodes;
foreach ($subNodes as $subNode)
{
self::parseNodes($subNode, $keyWord, $replacement);

}
else if (isset($node->nodeValue))
{

$newelement =
self::$dom->createTextNode(str_replace($keyWord, $replacement,
$node->nodeValue));
$node->parentNode->replaceChild($newelement, $node);
}
}
}

$keyWord="title";
$replacement="GOT YOU";

$doc = new DomDocument('1.0', 'UTF-8');

$doc->loadHTML($content);
$root = $doc->firstChild;
//$doc->normalizeDocument();

Parsing::$dom=$doc;

Parsing::parseNodes($doc, $keyWord, $replacement);

$content=$doc->saveHTML();

print(($content));



/* OUTPUT

<br />node->nodeType => 3 <->
<br />node->value: title: possibility to
<br />node->nodeType => 3 <->
<br />node->value:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><ul>
<li>GOT YOU: possibility to <a href="www.test.com">define the title</a>
from the link regards where this title is located</li>
</ul></body></html>

/*ce qui ne va pas:

1 - le dernier title n'a pas été remplacé. Pire que ca, la partie
"from the link regards where this title is located" ne passe JAMAIS dans
le contenu de $node->nodeValue (j'ai fait des prints)

2 - Il y a maintenant des tags HTML supplémentaires, mais c'est pas
trop grave je peux les enlever apres.


Donc pour moi a ce stade, le DOM, c'est NIET.

Cheers

DF
Mickael Wolff
2009-10-06 13:15:11 UTC
Permalink
Post by DublinFrench
content = "
<ul>
<li>title: possibility to <a href=\"www.test.com\">define the
title</a> from the link regards where this title is located</li>
</ul>
";
C'est normal que ça ne marche pas, le document n'est pas complet. Il
faut utiliser DomDocumentFragment pour gérer les fragments, me semble-t-il.
--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
DublinFrench
2009-10-06 22:59:42 UTC
Permalink
Post by Mickael Wolff
Post by DublinFrench
content = "
<ul>
<li>title: possibility to <a href=\"www.test.com\">define the
title</a> from the link regards where this title is located</li>
</ul>
";
C'est normal que ça ne marche pas, le document n'est pas complet.
J'ai absolument le même résultat avec

$content = "
<html>
<head><title>pouet</title>
</head>
<body>
<ul>
<li>title: possibility to <a href=\"www.test.com\">define the title</a>
from the link regards where this title is located</li>
</ul>
</body>
</html>
";
Post by Mickael Wolff
Il
faut utiliser DomDocumentFragment pour gérer les fragments, me semble-t-il.
Le nom est prometteur, mais la page est assez peu explicite.
http://th2.php.net/manual/en/class.domdocumentfragment.php

Ne serait ce pas pour rattacher un fragment html a un node ?

@++

DF
Mickael Wolff
2009-10-07 19:12:41 UTC
Permalink
Post by DublinFrench
J'ai absolument le même résultat avec
$content = "
<html>
<head><title>pouet</title>
</head>
<body>
<ul>
<li>title: possibility to <a href=\"www.test.com\">define the title</a>
from the link regards where this title is located</li>
</ul>
</body>
</html>
";
Le document est toujours incomplet. Il manque la DTD à utiliser. Si
le document génère des warning ou des erreurs à l'ouverture du fichier,
ou à sa validation, l'outil DOMDocument ne fonctionnera pas.
Post by DublinFrench
Post by Mickael Wolff
Il
faut utiliser DomDocumentFragment pour gérer les fragments, me semble-t-il.
Le nom est prometteur, mais la page est assez peu explicite.
http://th2.php.net/manual/en/class.domdocumentfragment.php
Ne serait ce pas pour rattacher un fragment html a un node ?
Un fragment est un node comme les autres. DomDocument::adoptChild et
DomDocument::insertChild devraient t'aider.
--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
Loading...