将HTML转换为XML

19

我有数百个需要转换成 XML 的 HTML 文件。我们使用这些 HTML 来为应用程序提供内容,但现在我们必须将这些内容作为 XML 提供。

HTML 文件包含表格、div、图片、p、b 或 strong 标签等等。

我在谷歌上搜索并找到了一些应用程序,但目前还没有实现。

您能否建议一种将这些文件内容转换为 XML 的方法?


请记住,HTML和XML是标记语言树中的两个不同概念。你不能简单地用XML替换HTML。XML可以被视为HTML的一种广义形式,但即使如此也不够精确。你主要使用HTML来显示数据,而使用XML来传递(或存储)数据。这个链接很有帮助:https://dev59.com/rG035IYBdhLWcg3wW-pa 更多信息 - HTML和XML之间的区别 - Caffeinated
请查看此帖子。然后,非常仔细地查看第四条评论。为什么要将HTML转换为XML? - Rob W
@bahadirarslan:你需要说明你想要做什么。最坏的情况下,如果你愿意,你可以将HTML文档转换成一个愚蠢的XML表示形式,将每个字符放入自己的元素中(这可能不是你想要的,但你已经将HTML文档转换成了XML)。 - Bruno
1
HTML解析器比XML更容忍错误。如果你很幸运,将其转换为XHTML文档,通过在前面加上<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">就足够了(将脚本包装在<script>块中,在//<![CDATA[<newline> ...content... //]]></script>部分)。当你的HTML不是格式良好时,你必须寻找一个HTML解析器,它提供了导出为XML选项。 - Rob W
可能是如何将HTML作为XML读取?的重复问题。 - Don Roby
显示剩余2条评论
2个回答

20

我使用tidy命令行工具获得了成功。在Linux上,我通过apt-get install tidy快速安装它。然后运行以下命令:

tidy -q -asxml --numeric-entities yes source.html >file.xml

生成一个XML文件,我可以用XSLT处理器对其进行处理。但我需要正确设置xhtml1 DTD。

这是他们的主页:html-tidy.org(以及旧版主页:HTML Tidy


7
还有一个工具是 xmllint -html -xmlout。 - Steven D. Majewski
3
有时我也会使用它。我认为你应该把它单独作为一个答案。 - Jarekczek
它会从HTML文件中删除JavaScript吗? - Alaa
通常情况下这个方法是有效的,但是对于一些HTML5文档,我会得到空输出。 - mirabilos
Tidy的主页一看就知道,他们自2008年以来就没有更新这个项目了。这也许可以解释问题。 - Jarekczek
新的(现代化的)整洁主页可以在以下网址找到:http://www.html-tidy.org - Mark Thomson

3

我找到了一种将(即使是糟糕的)HTML转换为格式良好的XML的方法。 我开始基于DOM loadHTML函数进行操作。 然而,随着时间的推移,出现了几个问题,因此我进行了优化并添加了补丁以纠正副作用。

  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;
        } ;
    }

现在这个功能也允许将更多的html片段添加到一个XML中,而我自己也需要使用它。通常可以像这样使用:
        $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>';

在此示例中,'<p>test<font>two</p>'将被美观地输出为格式良好的XML,如'<info><p>test<font>two</font></p></info>'。添加了 info 根标签,因为它还允许转换 '<p>one</p><p>two</p>',而这个不是XML,因为它没有一个根元素。但是,如果你的HTML肯定有一个根元素,那么可以跳过额外的 <info> 根标签。
通过这种方法,我可以从非结构化甚至损坏的HTML中获取真正漂亮的XML!
我希望这能更加清晰,并对其他人使用它提供帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接