空节点的非法自闭节点表示法 - 使用PHP DOMDocument输出XHTML

C.O*_*.O. 11 php xml validation xhtml xpath

我在PHP中使用XPATH处理XML兼容的XHTML输入,如下所示:

$xml=new DOMDocument();
$xml->loadXML(utf8_encode($temp));
[...]
$temp=utf8_decode($xml->saveXML());
Run Code Online (Sandbox Code Playgroud)

出现的问题是根据HTML5规范可能不会自动关闭的节点,例如

<textarea id="something"></textarea>
Run Code Online (Sandbox Code Playgroud)

或由JS利用的div

<div id="someDiv" class="whaever"></div>
Run Code Online (Sandbox Code Playgroud)

回来吧

<textarea id="something" />
Run Code Online (Sandbox Code Playgroud)

<div id="someDiv" class="whaever" />
Run Code Online (Sandbox Code Playgroud)

我目前通过使用来解决这个问题str_replace,但这是不可能的,因为我需要匹配个别情况.我怎么解决这个问题?

同时XPATH坚持要求推出

xmlns:default="http://www.w3.org/1999/xhtml
Run Code Online (Sandbox Code Playgroud)

在新创建的各个节点上,它会放置类似的东西<default:p>.如何在不诉诸愚蠢搜索的情况下停止此操作并替换为:

$temp=str_replace(' xmlns:default="http://www.w3.org/1999/xhtml" '," ",$temp);
$temp=str_replace(' xmlns:default="http://www.w3.org/1999/xhtml"'," ",$temp);
$temp=str_replace('<default:',"<",$temp);
$temp=str_replace('</default:',"</",$temp);
Run Code Online (Sandbox Code Playgroud)

编辑:我真的遇到麻烦的搜索和替换,我不打算用RegExp攻击输出XHTML.考虑这个例子:

<div id="videoPlayer0" class="videoPlayerPlacement" data-xml="video/cp_IV_a_1.xml"/>
Run Code Online (Sandbox Code Playgroud)

显然,自我关闭的div是非法的(至少在一个上下文中,我不能输出mime application/xhtml + xml但是我被迫使用mime text/html),而在所有其他情况下,他们肯定不会验证.

Dan*_*ndo 4

可以使用技巧来标准化“非空”标签。这不是官方解决方案,但它有效。

function export_html(DOMDocument $dom)
{
    $voids = [
        'area',
        'base',
        'br',
        'col',
        'colgroup',
        'command',
        'embed',
        'hr',
        'img',
        'input',
        'keygen',
        'link',
        'meta',
        'param',
        'source',
        'track',
        'wbr',
    ];

    // Every empty node; 
    // there is no reason to match nodes with content inside.
    $query = '//*[not(node())]';
    $nodes = (new DOMXPath($dom))->query($query);

    foreach ($nodes as $node) {
        if (in_array($node->nodeName, $voids)) {
            // A void tag.
            continue;
        }
        // Not a void tag. We inject a placeholder content.
        $node->appendChild(new DOMComment('NOT_VOID'));
    }
    
    // We remove the placeholders.
    return str_replace('<!--NOT_VOID-->', '', $dom->saveXML());
}
Run Code Online (Sandbox Code Playgroud)

在你的例子中

$dom = new DOMDocument();
$dom->loadXML(<<<XML
<html>
    <textarea id="something"></textarea>
    <div id="someDiv" class="whaever"></div>
</html>
XML
);
Run Code Online (Sandbox Code Playgroud)

echo export_html($dom);将产生

<?xml version="1.0"?>
<html>
    <textarea id="something"></textarea>
    <div id="someDiv" class="whaever"></div>
</html>
Run Code Online (Sandbox Code Playgroud)