Como fazer HTML5 trabalhar com DOMDocument?

Estou tentando analisar o código HTML com DOMDocument, fazer coisas como mudanças, e depois montá-lo de volta para uma string que eu envio para a saída.

Mas há alguns problemas em relação à análise, o que significa que o que eu envio para o DOMDocument nem sempre retorna na mesma forma 🙂

Aqui está uma lista:

  1. usando -> loadHTML :

    • formata meu documento, independentemente das configurações preserveWhitespace e formatOutput (perdendo espaços em branco no texto pré-formatado)
    • me dá erros quando tenho tags html5 como
      ,

      etc. Mas elas podem ser suprimidas, então eu posso viver com isso.
    • produz marcação inconsistente – por exemplo, se eu adicionar um elemento (com uma tag de auto-fechamento), depois de analisar / saveHTML a saída será
  2. usando -> loadXML :

    • codifica entidades como > de tags ou : body > div torna-se body > div body > div
    • todas as tags são fechadas da mesma maneira, por exemplo, se torna ; mas isso pode ser corrigido com uma regex.

Não tentei HTML5lib mas prefiro DOMDocument em vez de um analisador personalizado por motivos de desempenho


Atualizar:

Assim, como o Honeymonster mencionou o uso do CDATA, repara o principal problema com o loadXML.

Existe alguma maneira de evitar o fechamento automático de todas as tags HTML vazias, além de um determinado conjunto, sem usar o regex?

Agora eu tenho:

 $html = $dom->saveXML($node); $html = preg_replace_callback('#]*)\s*/>#s', function($matches){ // ignore only these tags $xhtml_tags = array('br', 'hr', 'input', 'frame', 'img', 'area', 'link', 'col', 'base', 'basefont', 'param' ,'meta'); // if a element that is not in the above list is empty, // it should close like `` (for eg. empty ``) return in_array($matches[1], $xhtml_tags) ? "" : ""; }, $html);</code> </pre>
<p>  que funciona, mas também irá replace o conteúdo do CDATA, o que não quero … </p>
		    <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle"
     style="display:block; text-align:center;"
     data-ad-layout="in-article"
     data-ad-format="fluid"
     data-ad-client="ca-pub-4943387893641281"
     data-ad-slot="9988150711"></ins>
<script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script>
        
		
		<div class="list-group list-group-flush">

    


	<div class="list-group-item list-group-item-action flex-column align-items-start">
		      	<p>  Infelizmente, ou possivelmente, o domdocument é projetado para não tentar preservar a formatação do documento original.  Isto é para tornar o estado interno do analisador mais fácil de gerenciar, mantendo todos os elementos do mesmo estilo.  A maioria dos analisadores criará uma representação de tree na memory e não se preocupará com a formatação textual até que o usuário solicite tal.  É por isso que suas tags auto-fechadas são emitidas com tags de fechamento separadas.  A boa notícia é que não importa. </p>
<p>  Quanto a etiquetas de estilo e tags de script, ficando <code><></code> convertido em <code><></code>  , você pode evitar a conversão envolvendo o conteúdo do elemento em questão com as tags de cdata recomendadas, assim: </p>
<pre> <code><style> /*<![CDATA[*/ body > div { width: 50%; } /*]]>*/ </style></code> </pre>
<p>  O comentário <code>/* */</code> torno das declarações de cdata é permitir clientes quebrados que não conhecem as seções de cdata e, em vez disso, tratam as declarações como código CSS.  Se você estiver usando o documento somente internamente, então você pode omitir o <code>/* */</code> comment envolve e apenas a declaração de cdata.  Você pode encontrar problemas com os clientes quebrados acima mencionados se você manipular o documento e, em seguida, enviá-lo para o navegador sem verificar se os <code>/* */</code> comentários são mantidos;  Não tenho certeza se domdocument irá reter isso ou não. </p>
</div>
</li><!-- #comment-## -->
<div class="list-group-item list-group-item-action flex-column align-items-start">
		      	<p>  Use html5lib .  Pode analisar html5 e produzir um DOMDocument.  Exemplo: </p>
<pre> <code>require_once '/path/to/HTML5/Parser.php'; $dom = HTML5_Parser::parse('<html><body>...');</body></html></code> </pre>
<p>  Documentação </p>
</div>
</li><!-- #comment-## -->
<div class="list-group-item list-group-item-action flex-column align-items-start">
		      	<p>  Se você quiser suportar HTML5, não toque no DOMDocument. </p>
<p>  Atualmente, a melhor opção parece ser <a href="https://github.com/Masterminds/html5-php" rel="nofollow ugc">https://github.com/Masterminds/html5-php</a> </p>
<p>  Anteriormente, a melhor opção foi <a href="https://github.com/html5lib/html5lib-php" rel="nofollow ugc">https://github.com/html5lib/html5lib-php</a>, mas, como a descrição diz, está “atualmente não mantida”.  E este tem sido status desde outubro de 2011, então não aguento mais a respiração. </p>
<p>  Não usei <code>html5-php</code> na produção, então não posso fornecer experiências do mundo real sobre isso.  Eu usei o <code>html5lib-php</code> na produção e eu diria que está analisando documentos bem formados corretamente, mas ele tem erros inesperados com alguns erros de syntax simples.  Por outro lado, parece implementar o algoritmo da agência de adoção e alguns outros casos de canto estranhos corretamente.  Se <code>html5lib-php</code> ainda fosse mantido, eu ainda preferiria.  No entanto, como as coisas atualmente estão em pé, eu preferiria usar <code>html5-php</code> e possivelmente ajudar a consertar os erros restantes lá. </p>
</div>
</li><!-- #comment-## -->
<div class="list-group-item list-group-item-action flex-column align-items-start">
		      	<p>  Eu tentei html5lib e html5php, mas nem trabalhei com o HTML que eu recebi.  Uma alternativa que foi capaz de analisar o HTML foi: <a href="https://github.com/ivopetkov/html5-dom-document-php" rel="nofollow ugc">https://github.com/ivopetkov/html5-dom-document-php</a> </p>
<p>  A class principal estende o DomDocument nativo do PHP. </p>
</div>
</li><!-- #comment-## -->
<div class="list-group-item list-group-item-action flex-column align-items-start">
		      	<p>  Ao inicializar domDocument, faça o seguinte: </p>
<pre> <code>$dom = new DOMDocument(5, 'UTF-8');</code> </pre>
</div>
</li><!-- #comment-## -->

 		<div class='row'>
			<div class='col'>
				<ul><li><a class="text-dark" href="https://php.docow.com/por-que-domdocument-aninha-as-palavras-de-paragrafo.html" rel="bookmark" class="text-dark" title="Por que DOMDocument aninha as palavras de parágrafo ()?">Por que DOMDocument aninha as palavras de parágrafo ()?</a></li><li><a class="text-dark" href="https://php.docow.com/php-domdocument-encontrando-elementos-especificos.html" rel="bookmark" class="text-dark" title="PHP DOMDocument, encontrando elementos específicos">PHP DOMDocument, encontrando elementos específicos</a></li><li><a class="text-dark" href="https://php.docow.com/erros-advertencias-php-domdocument-em-html5-tags.html" rel="bookmark" class="text-dark" title="Erros / advertências PHP DOMDocument em html5-tags">Erros / advertências PHP DOMDocument em html5-tags</a></li><li><a class="text-dark" href="https://php.docow.com/loadhtml-libxml_html_noimplied-em-um-fragment-html-gera-tags-incorretas.html" rel="bookmark" class="text-dark" title="loadHTML LIBXML_HTML_NOIMPLIED em um fragment html gera tags incorretas">loadHTML LIBXML_HTML_NOIMPLIED em um fragment html gera tags incorretas</a></li><li><a class="text-dark" href="https://php.docow.com/php-extraindo-a-string-entre-duas-tags-pelo-conteudo-do-childs.html" rel="bookmark" class="text-dark" title="PHP: Extraindo a string entre duas tags pelo conteúdo do childs">PHP: Extraindo a string entre duas tags pelo conteúdo do childs</a></li><li><a class="text-dark" href="https://php.docow.com/removendo-o-aviso-docdocument-enquanto-analisa-o-conteudo-da-pagina.html" rel="bookmark" class="text-dark" title="Removendo o aviso DocDocument enquanto analisa o conteúdo da página">Removendo o aviso DocDocument enquanto analisa o conteúdo da página</a></li><li><a class="text-dark" href="https://php.docow.com/convertendo-indentacao-com-preg_replace-sem-retorno-de-chamada.html" rel="bookmark" class="text-dark" title="Convertendo indentação com preg_replace (sem retorno de chamada)">Convertendo indentação com preg_replace (sem retorno de chamada)</a></li><li><a class="text-dark" href="https://php.docow.com/php-change-dom-useragent.html" rel="bookmark" class="text-dark" title="PHP change DOM useragent">PHP change DOM useragent</a></li></ul>			</div>
		</div>
	</div>
		
		
        </div>
		

	
	
    </div>
    <div class="col-md-4 order-3">
	
        <div class="card border-0">
            <div class="card-header">Intereting Posts</div>
				<ul>
				<li><a class="text-dark" href="https://php.docow.com/usando-domdocument-e-possivel-obter-todos-os-elementos-que-existem-dentro-de-um-determinado-dom.html" rel="bookmark" class="text-dark" title="Usando DOMDocument, é possível obter todos os elementos que existem dentro de um determinado DOM?">Usando DOMDocument, é possível obter todos os elementos que existem dentro de um determinado DOM?</a></li><li><a class="text-dark" href="https://php.docow.com/posso-obter-irmaos-com-o-domdocument-do-php.html" rel="bookmark" class="text-dark" title="Posso obter irmãos com o DOMDocument do PHP?">Posso obter irmãos com o DOMDocument do PHP?</a></li><li><a class="text-dark" href="https://php.docow.com/como-posso-obter-o-html-serializado-de-um-elemento-com-domdocument-do-php.html" rel="bookmark" class="text-dark" title="Como posso obter o HTML serializado de um elemento com DOMDocument do PHP?">Como posso obter o HTML serializado de um elemento com DOMDocument do PHP?</a></li><li><a class="text-dark" href="https://php.docow.com/php-domdocument-recebendo-atributo-de-tag.html" rel="bookmark" class="text-dark" title="PHP DOMDocument recebendo Atributo de Tag">PHP DOMDocument recebendo Atributo de Tag</a></li><li><a class="text-dark" href="https://php.docow.com/php-dom-altere-o-tipo-de-documento-domdocument-existente.html" rel="bookmark" class="text-dark" title="PHP DOM: altere o tipo de documento DOMDocument existente">PHP DOM: altere o tipo de documento DOMDocument existente</a></li><li><a class="text-dark" href="https://php.docow.com/isolamento-bullet-simplexmlelement.html" rel="bookmark" class="text-dark" title="Isolamento Bullet SimpleXMLElement">Isolamento Bullet SimpleXMLElement</a></li><li><a class="text-dark" href="https://php.docow.com/por-que-o-curl-retorna-uma-string-vazia.html" rel="bookmark" class="text-dark" title="Por que o CURL retorna uma string vazia?">Por que o CURL retorna uma string vazia?</a></li><li><a class="text-dark" href="https://php.docow.com/loop-over-domdocument.html" rel="bookmark" class="text-dark" title="Loop over DOMDocument">Loop over DOMDocument</a></li><li><a class="text-dark" href="https://php.docow.com/parse-html-com-html-domdocument-do-php.html" rel="bookmark" class="text-dark" title="Parse HTML com HTML DOMDocument do PHP">Parse HTML com HTML DOMDocument do PHP</a></li><li><a class="text-dark" href="https://php.docow.com/xml-criar-elemento-nova-linha.html" rel="bookmark" class="text-dark" title="XML – Criar elemento – Nova linha">XML – Criar elemento – Nova linha</a></li><li><a class="text-dark" href="https://php.docow.com/como-posso-combinar-facilmente-dois-documentos-xml-com-o-mesmo-no-pai-em-um-unico-documento.html" rel="bookmark" class="text-dark" title="Como posso combinar facilmente dois documentos XML com o mesmo nó pai em um único documento?">Como posso combinar facilmente dois documentos XML com o mesmo nó pai em um único documento?</a></li>				</ul>
        </div>
	<div class="card border-0">
		
	</div>
</div>
</div>

   <div class="clearfix mt-5"></div>
    <hr />
<footer>
        <ul class="list-inline text-center">
        <li class="list-inline-item">© 2017 Desenvolvimento PHP</li>
        <li class="list-inline-item"><a href="/topics">Topics</a></li>
        <li class="list-inline-item"><a href="#">Terms</a></li>
        <li class="list-inline-item"><a href="#">Privacy Policy</a></li>
        </ul>
</footer>

</div>     
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>
  </body>
<!-- Default Statcounter code for Docow.com
http://www.docow.com -->
<script type="text/javascript">
var sc_project=11834752; 
var sc_invisible=1; 
var sc_security="f5f97ab7"; 
</script>
<script type="text/javascript"
src="https://www.statcounter.com/counter/counter.js"
async></script>
<noscript><div class="statcounter"><a title="Web Analytics"
href="https://statcounter.com/" target="_blank"><img
class="statcounter"
src="https://c.statcounter.com/11834752/0/f5f97ab7/1/"
alt="Web Analytics"></a></div></noscript>
<!-- End of Statcounter Code -->
</html>