J'ai des centaines de fichiers HTML qui doivent être convertis en XML. Nous utilisons ces HTML pour servir le contenu des applications mais maintenant nous devons servir ces contenus en XML.
Les fichiers HTML sont contient, tableaux, div, image, p, b ou balises fortes, etc.
J'ai recherché des applications sur Google, mais je n'ai pas encore réussi.
Pourriez-vous suggérer un moyen de convertir ces contenus de fichiers en XML?
J'ai réussi à utiliser l'utilitaire de ligne de commande tidy
. Sous linux, je l'ai installé rapidement avec apt-get install tidy
. Ensuite, la commande:
tidy -q -asxml --numeric-entities yes source.html >file.xml
a donné un fichier xml, que j'ai pu traiter avec le processeur xslt. Cependant, j'avais besoin de configurer correctement les dtds xhtml1.
Voici leur page d'accueil: html-tidy.org (et l'héritage: HTML Tidy )
J'ai trouvé un moyen de convertir (même mauvais) du HTML en XML bien formé. J'ai commencé à baser cela sur la fonction DOM loadHTML. Cependant, au fil du temps, plusieurs problèmes se sont produits et j'ai optimisé et ajouté des correctifs pour corriger les effets secondaires.
function tryToXml($dom,$content) {
if(!$content) return false;
// xml well formed content can be loaded as xml node tree
$fragment = $dom->createDocumentFragment();
// wonderfull appendXML to add an XML string directly into the node tree!
// aappendxml will fail on a xml declaration so manually skip this when occurred
if( substr( $content,0, 5) == '<?xml' ) {
$content = substr($content,strpos($content,'>')+1);
if( strpos($content,'<') ) {
$content = substr($content,strpos($content,'<'));
}
}
// if appendXML is not working then use below htmlToXml() for nasty html correction
if(!@$fragment->appendXML( $content )) {
return $this->htmlToXml($dom,$content);
}
return $fragment;
}
// convert content into xml
// dom is only needed to prepare the xml which will be returned
function htmlToXml($dom, $content, $needEncoding=false, $bodyOnly=true) {
// no xml when html is empty
if(!$content) return false;
// real content and possibly it needs encoding
if( $needEncoding ) {
// no need to convert character encoding as loadHTML will respect the content-type (only)
$content = '<meta http-equiv="Content-Type" content="text/html;charset='.$this->encoding.'">' . $content;
}
// return a dom from the content
$domInject = new DOMDocument("1.0", "UTF-8");
$domInject->preserveWhiteSpace = false;
$domInject->formatOutput = true;
// html type
try {
@$domInject->loadHTML( $content );
} catch(Exception $e){
// do nothing and continue as it's normal that warnings will occur on nasty HTML content
}
// to check encoding: echo $dom->encoding
$this->reworkDom( $domInject );
if( $bodyOnly ) {
$fragment = $dom->createDocumentFragment();
// retrieve nodes within /html/body
foreach( $domInject->documentElement->childNodes as $elementLevel1 ) {
if( $elementLevel1->nodeName == 'body' and $elementLevel1->nodeType == XML_ELEMENT_NODE ) {
foreach( $elementLevel1->childNodes as $elementInject ) {
$fragment->insertBefore( $dom->importNode($elementInject, true) );
}
}
}
} else {
$fragment = $dom->importNode($domInject->documentElement, true);
}
return $fragment;
}
protected function reworkDom( $node, $level = 0 ) {
// start with the first child node to iterate
$nodeChild = $node->firstChild;
while ( $nodeChild ) {
$nodeNextChild = $nodeChild->nextSibling;
switch ( $nodeChild->nodeType ) {
case XML_ELEMENT_NODE:
// iterate through children element nodes
$this->reworkDom( $nodeChild, $level + 1);
break;
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
// do nothing with text, cdata
break;
case XML_COMMENT_NODE:
// ensure comments to remove - sign also follows the w3c guideline
$nodeChild->nodeValue = str_replace("-","_",$nodeChild->nodeValue);
break;
case XML_DOCUMENT_TYPE_NODE: // 10: needs to be removed
case XML_PI_NODE: // 7: remove PI
$node->removeChild( $nodeChild );
$nodeChild = null; // make null to test later
break;
case XML_DOCUMENT_NODE:
// should not appear as it's always the root, just to be complete
// however generate exception!
case XML_HTML_DOCUMENT_NODE:
// should not appear as it's always the root, just to be complete
// however generate exception!
default:
throw new exception("Engine: reworkDom type not declared [".$nodeChild->nodeType. "]");
}
$nodeChild = $nodeNextChild;
} ;
}
Maintenant, cela permet également d'ajouter plus de morceaux html dans un XML dont j'avais besoin pour moi-même. En général, il peut être utilisé comme ceci:
$c='<p>test<font>two</p>';
$dom=new DOMDocument('1.0', 'UTF-8');
$n=$dom->appendChild($dom->createElement('info')); // make a root element
if( $valueXml=tryToXml($dom,$c) ) {
$n->appendChild($valueXml);
}
echo '<pre/>'. htmlentities($dom->saveXml($n)). '</pre>';
Dans cet exemple '<p>test<font>two</p>'
sera joliment sorti en XML bien formé comme '<info><p>test<font>two</font></p></info>
'. La balise racine info est ajoutée car elle permettra également de convertir '<p>one</p><p>two</p>
'qui n'est pas XML car il n'a pas un élément racine. Cependant, si vous html possède à coup sûr un élément racine, la racine supplémentaire <info>
la balise peut être ignorée.
Avec cela, je tire du vrai XML sympa du HTML non structuré et même corrompu!
J'espère que c'est un peu clair et que cela pourrait aider d'autres personnes à l'utiliser.
N'oubliez pas que HTML et XML sont deux concepts distincts dans l'arborescence des langages de balisage. Vous ne pouvez pas exactement remplacer HTML par XML . XML peut être considéré comme une forme généralisée de HTML, mais même cela n'est pas précis. Vous utilisez principalement HTML pour afficher les données et XML pour transporter (ou stocker) les données.
Ce lien est utile: Comment lire HTML en XML?