使用 DomDocument 将 HTML、CSS 和 JavaScript 从文件中分离出来

Separate HTML, CSS, and JavaScript from file with DomDocument

我正在使用 PHP 加载远程文件,然后尝试使用 DomDocument 解析它。该文件包含 HTML、CSS(在 style 标签内)和 JavaScript(在 script 标签内)。然后我通过将 htmlcssjs 传递到解析它的函数中来单独加载它。我的想法是,我可以使用核心 WordPress 方法在适当的位置显示这些内容。

这是我最接近的:

libxml_use_internal_errors( true );
$document = wp_remote_retrieve_body( $response ); // this is the remote HTML file
// create a new DomDocument object
$html = new DOMDocument( '1.0', 'UTF-8' );
// load the HTML into the DomDocument object (this would be your source HTML)
$html->loadHTML( $document, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
if ( 'html' === $part ) {
    $xpath  = new DOMXPath( $html );
    $remove = $xpath->query( "//*[style or script]" );
    foreach ( $remove as $node ) {
        $node->parentNode->removeChild($node);
    }
} elseif ( 'css' === $part ) {
    $xpath  = new DOMXPath( $html );
    $remove = $xpath->query( "//*[not(self::style)]" );
    foreach ( $remove as $node ) {
        $node->parentNode->removeChild($node);
    }
} elseif ( 'js' === $part ) {
    $xpath  = new DOMXPath( $html );
    $remove = $xpath->query( "//*[not(self::script)]" );
    foreach ( $remove as $node ) {
        $node->parentNode->removeChild($node);
    }
}

ob_start();
echo $html->saveHTML();
$output = ob_get_contents();
ob_end_clean();

这会导致一些问题:

  1. 在 CSS 和 JavaScript 输出中,它保留了 stylescript 标签,我正在想办法删除它。
  2. 在 HTML 输出中,它保留了 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><head></head><body>,我也想将其删除。

我不确定是否需要朝另一个方向进行,或者我是否只需要一个小东西来移除这些包装元素。但是我很难让 xpath 与我想要保留的元素相关联,而不是与我想要删除的元素相关联,这就是我最终达到的结果。

问题出在 DomNode 上。查看 DOMDocument remove script tags from HTML source,这会让您了解如何修改代码。

对于您的 html 案例,您可以只保存 <body> 元素,而不是保存整个 DOMDocument。

libxml_use_internal_errors( true );
$document = wp_remote_retrieve_body( $response ); // this is the remote HTML file
// create a new DomDocument object
$html = new DOMDocument( '1.0', 'UTF-8' );
// load the HTML into the DomDocument object (this would be your source HTML)
$html->loadHTML( $document, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
if ( 'html' === $part ) {
    // get all <body> elements
    $body_elements = $html->getElementsByTagName( 'body' );
    // it is to be assumed that there is only one <body> element.
    $body = $body_elements->item( 0 );
    // get the HTML contained within that body element
    $output = $body->ownerDocument->saveHTML( $body );
} else {
    // ...
}

对于 CSS 和 JS 元素,我不确定为什么你只需要获取它们的内部内容而不需要包含标签,但是与我们刚刚对 [=14 所做的类似的方法=] 会起作用:1. select 元素,2. foreach 遍历元素数组,3. 获取每个元素的内部保存(我 相信 但是我不确定这将是一个 DOMText 对象)并连接这些字符串以创建最终的 $output 变量。

CSS 和 JS 的另一种方法:采用现有方法的 <script><tag> 元素簇,将它们插入空白 DOMDocument's <head> to save their containing <head> as an HTML string, and then enqueue that string via an anonymous function on WordPress' wp_enqueue_scripts勾:

/**
 * 
 */
function wpse_66361476_alert() {
    $output = "<script>alert('hello');</script>"; // demonstration content
    add_action(
        'wp_enqueue_scripts',
        function() use ($output) {
            echo $output;
        }
    );
}
add_action('init', 'wpse_66361476_alert');

如果您不控制输出的 CSS 和 JS(和 HTML),这种方法是危险的。无论你在这里加载什么,iframe 可能会更好。

如果您的主机尚未使用前端缓存,要提高页面加载速度,您可能需要研究使用 WordPress 的缓存功能来缓存已解析的元素。 Here's a short overview;与您的托管服务提供商联系,看看他们是否有具体建议。