Как заставить HTML5 работать с DOMDocument?

Я пытаюсь проанализировать HTML-код с помощью DOMDocument, внести в него такие вещи, как изменения, а затем собрать его обратно в строку, которую я отправляю на вывод.

Но есть несколько проблем с синтаксическим анализом, а это означает, что то, что я отправляю в DOMDocument, не всегда возвращается в той же форме :)

Вот список:

  1. с использованием ->loadHTML:

    • форматирует мой документ независимо от настроек saveWhitespaceи formatOutput(потеря пробелов в предварительно отформатированном тексте)
    • выдает мне ошибки, когда у меня есть теги html5, такие как
      ,
      и т. д. Но их можно подавить, так что я могу с этим жить.
    • создает несогласованную разметку — например, если я добавляю Элемент (с самозакрывающимся тегом), после синтаксического анализа/сохранения HTML вывод будет
  2. с использованием ->loadXML:

    • кодирует сущности например >из или теги: body > div становится body > div
    • все теги закрываются таким же образом, например становится ; но это можно исправить с помощью регулярного выражения.

Я не пробовал HTML5lib, но предпочел бы DOMDocument вместо пользовательского синтаксического анализатора из соображений производительности.


Обновление:

Таким образом, как упомянутый Honeymonster, использование CDATA устраняет основную проблему с loadXML.

Можно ли как-то предотвратить самозакрытие всех пустых тегов HTML, кроме определенного набора, без использования регулярного выражения?

Прямо сейчас у меня есть:

$html = $dom->saveXML($node);

$html = preg_replace_callback('#<(\w+)([^>]*)\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) ? "<{$matches[1]}{$matches[2]} />" : "<{$matches[1]}{$matches[2]}></{$matches[1]}>";
}, $html);
</code></pre><p>, который работает, но он также будет выполнять замены в содержимом CDATA, чего я не хочу... </p></p>
         </div>
         <div class="votes-question">
            <div class="vote-count" itemprop="upvoteCount">19</div><i class="fa fa-thumbs-o-up"></i>
         </div>
         <div class="tags">
            <a href="/questions/tagged/domdocument" class="tag"  title="domdocument" rel="tag">domdocument</a> <a href="/questions/tagged/html5" class="tag"  title="html5" rel="tag">html5</a> <a href="/questions/tagged/php" class="tag"  title="php" rel="tag">php</a>         </div>
         <div class="clearfix"></div>
         <div class="action-time">
            задан Alex            <span title="30 May 2012 в 13:24 ">30 May 2012 в 13:24 </span>
         </div>
         
         <a class="s-link" href="/questions/654490/kak-zastavit-html5-rabotat-s-domdocument" title="поделиться">поделиться</a>
      </div>
   </div>
  <div style="height:100px;margin:10px 0px;" class="">

    <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <!-- siteask before post --> <ins class="adsbygoogle"      style="display:block;height:100px"
                                                                                                                             data-ad-client="ca-pub-2355906945027976"
                                                                                                                             data-ad-slot="" data-ad-format="auto"></ins>
    <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script>

    </div>
   <div class="answers" id="answers">
   
      <h2 class="pull-left"><span itemprop="answerCount">0</span> ответов</h2>
      <div class="clearfix"></div>

      <div class="answer-pager">
         <div class="pagination">
                     </div>
      </div>

            <div style="margin-top: 20px;">
          Другие вопросы по тегам:          <div class="tags" style="display: inline-block; float: none;">
         <a href="/questions/tagged/domdocument" class="tag"  title="domdocument" rel="tag">domdocument</a> <a href="/questions/tagged/html5" class="tag"  title="html5" rel="tag">html5</a> <a href="/questions/tagged/php" class="tag"  title="php" rel="tag">php</a>       </div>
        <h3 class="m-t-20">Похожие вопросы:</h3>

        <div class="related-block">
          <ul>
                          <li><div class='votes-answer green'><span class='vote-count'>78</span> <i class="fa fa-thumbs-o-up"></i></div> <a href="/questions/131613/skrytye-funkcii-php-zakrytyj" title="Скрытые функции PHP? [закрытый]">Скрытые функции PHP? [закрытый]</a> - 16 November 2012 17:08 </li>
                            <li><div class='votes-answer green'><span class='vote-count'>43</span> <i class="fa fa-thumbs-o-up"></i></div> <a href="/questions/172039/luchshij-redaktor-php-dlja-zakrytogo-vista" title="Лучший редактор PHP для [закрытого] Vista">Лучший редактор PHP для [закрытого] Vista</a> - 15 September 2008 22:49 </li>
                            <li><div class='votes-answer green'><span class='vote-count'>31</span> <i class="fa fa-thumbs-o-up"></i></div> <a href="/questions/13430/kak-rasschitat-chislo-yanvar-mesyacz-mezhdu-dvumya-datami-s-ispol-zovaniem-php-duplicate" title="как рассчитать число Январь месяц между двумя датами с использованием php [duplicate] ">как рассчитать число Январь месяц между двумя датами с использованием php [duplicate] </a> - 22 March 2017 17:23 </li>
                            <li><div class='votes-answer green'><span class='vote-count'>30</span> <i class="fa fa-thumbs-o-up"></i></div> <a href="/questions/28166/problema-s-prilozheniem-php-swiftmailer-dublikat" title="Проблема с приложением PHP SwiftMailer [дубликат] ">Проблема с приложением PHP SwiftMailer [дубликат] </a> - 12 March 2018 02:52 </li>
                            <li><div class='votes-answer green'><span class='vote-count'>30</span> <i class="fa fa-thumbs-o-up"></i></div> <a href="/questions/26916/kak-poluchit-identifikator-ot-tekushhego-url-i-sdelat-novy-j-url-v-ajax-duplicate" title="как получить идентификатор от текущего url и сделать новый url в ajax [duplicate] ">как получить идентификатор от текущего url и сделать новый url в ajax [duplicate] </a> - 15 February 2016 09:55 </li>
                            <li><div class='votes-answer green'><span class='vote-count'>30</span> <i class="fa fa-thumbs-o-up"></i></div> <a href="/questions/28161/peredacha-identifikatora-iz-url-adresa-identifikator-takzhe-otobrazhaetsya-po-ssy-lke-no-ne-obnovlyaet-danny-e-v-baze-danny-x-my" title="Передача идентификатора из URL-адреса, идентификатор также отображается по ссылке, но не обновляет данные в базе данных MySQL [duplicate] ">Передача идентификатора из URL-адреса, идентификатор также отображается по ссылке, но не обновляет данные в базе данных MySQL [duplicate] </a> - 12 March 2018 02:52 </li>
                            <li><div class='votes-answer green'><span class='vote-count'>30</span> <i class="fa fa-thumbs-o-up"></i></div> <a href="/questions/14646/kak-soxranit-fajl-php-ot-vy-polneniya-nabrav-tochny-j-url-adres-stranicy-duplicate" title="Как сохранить файл php от выполнения, набрав точный URL-адрес страницы [duplicate] ">Как сохранить файл php от выполнения, набрав точный URL-адрес страницы [duplicate] </a> - 6 June 2013 15:10 </li>
                          </ul>
        </div>

      </div>
   </div>
   
</div>      </div>
      <aside class="sidebar">
        <div class="awrap">

<script async src="https://yastatic.net/pcode-native/loaders/loader.js"></script>
<script>
    (yaads = window.yaads || []).push({
        id: "553274-2",
        render: "#id-553274-2"
    });
</script>
<div id="id-553274-2"></div>
          <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle"
     style="display:inline-block;width:300px;height:600px"
     data-ad-client="ca-pub-2355906945027976"
     data-ad-slot="8038370725"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>


        </div>
      </aside>

    </div>
  </div>
  <footer class="footer">
    <div class="wrapper wrapper--sm">
      <div class="footer-navs-col">
        <div class="footer-nav footer-nav--menu">

          <div class="footer-coryright">© 2017 - 2020 Вопросы и ответы по программированию</div>
        </div>
        <div class="footer-nav footer-nav--catalog">
        </div>
      </div>
      <div class="footer-contacts-col">
        <div class="soc-widget-col">
        </div>
      </div>
      <div class="clearfix"></div>
    </div>

  </footer>

</div>

<script type="text/javascript" src="/js/ui/jquery-ui-1.8.16.custom.min.js"></script>
<script type="text/javascript" src="/js/ui/external/jquery.cookie.js"></script>

<script type="text/javascript" src="/js/versions/menu.ru.u1607887878.js"></script>


<script type="text/javascript" src="/js/jquery.fancybox.min.js"></script>
<script type="text/javascript" src="/js/slick.min.js"></script>
<script type="text/javascript" src="/js/jquery.maskedinput.min.js"></script>

<script type="text/javascript" src="/js/versions/scripts.ru.u1607887878.js"></script>


<!-- Yandex.Metrika counter --> <script type="text/javascript" > (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; var z = null;m[i].l=1*new Date(); for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }} k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); ym(90030325, "init", { clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true }); </script> <noscript><div><img src="https://mc.yandex.ru/watch/90030325" style="position:absolute; left:-9999px;" alt="" /></div></noscript> <!-- /Yandex.Metrika counter -->


<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-123993370-1"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'UA-123993370-1');
</script>

</div>
<script type="application/ld+json">
  {
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "Программирование - вопросы и ответы",
  "alternateName": "Программирование - вопросы и ответы",
  "url": "https://legkovopros.ru",
  "potentialAction": {
     "@type": "SearchAction",
     "target": "https://legkovopros.ru/search?search={search_term_string}",
     "query-input": "required name=search_term_string"
   }
}
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Программирование - вопросы и ответы",
  "url": "https://legkovopros.ru",
  "logo": "https://legkovopros.ru/i/logo.png",
  "email": "info@legkovopros.ru",
   "telephone": ""

}




</script>
</body>
</html>