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

illegal self closing node notation for empty nodes - outputting XHTML with PHP DOMDocument

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

1
2
3
4
$xml=new DOMDocument();
$xml->loadXML(utf8_encode($temp));
[...]
$temp=utf8_decode($xml->saveXML());

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

1
<textarea id="something"></textarea>

或div以供JS

使用

1
 

重新显示为

1
<textarea id="something" />

1
 

我目前使用str_replace解决了这个问题,但这不是胡说八道,因为我需要匹配各种情况。我该如何解决?

同时XPATH坚持推出

1
xmlns:default="http://www.w3.org/1999/xhtml

以及在新创建的各个节点上,它会放置<default:p>之类的东西。我该如何停止而不求助于愚蠢的搜索并像这样替换:

1
2
3
4
$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);

编辑:我真的在愚蠢的搜索和替换上遇到了麻烦,并且我不打算用RegExp攻击输出XHTML。考虑以下示例:

1
 

显然,自关闭div是非法的(至少在一种情况下,我无法将其作为mime application / xhtml xml输出,但被迫使用mime text / html),并且在所有其他情况下,它们肯定不会验证。


很抱歉收到的答复很晚,但是您知道...是圣诞节。 :D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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 $n) {
                if (! in_array($n->nodeName, $voids)) {
                        // If it is not a void/empty tag,
                        // we need to leave the tag open.
                        $n->appendChild(new DOMComment('NOT_VOID'));
                }
        }

        // Let's remove the placeholder.
        return str_replace('<!--NOT_VOID-->', '', $dom->saveXML());
}

在您的示例中

1
2
3
4
5
6
7
8
$dom = new DOMDocument();
$dom->loadXML(<<<XML
<html>
        <textarea id="something"></textarea>
       
</html>
XML

);

echo export_html($dom);将产生

1
2
3
4
5
<?xml version="1.0"?>
<html>
    <textarea id="something"></textarea>
   
</html>

圣诞快乐! ^ _ ^


您是否不知道可以编写HTML5并将其用作XML,请看以下内容:"对于许多人来说似乎不太清楚。因此,让我们保持记录吧。HTML5可以用html和XML编写。

接下来要实际将任何PHP示例用作XML,请设置相应的标头:

1
header("content-type: application/xhtml+xml; charset=UTF-8");

在实际的XML文档中,如果没有不使用斜杠,就不能编写任何自闭标签。没有而不是</br>等。有了这个前奏,让我们继续...

我们发现在

中使用LIBXML_NOEMPTYTAG选项

1
2
3
4
$xml=new DOMDocument();
$xml->loadXML(utf8_encode($temp));
  // do stuff with the DOM
$temp=utf8_decode($xml->saveXML(NULL, LIBXML_NOEMPTYTAG));

不能"解决"问题,但可以解决该问题。 HTML5规范命名了多个" void elements "。它们是:area, base, br, col, embed, hr, img, input, keygen, link, meta, param, source, track, wbr并引用其规范:"无效元素不能包含任何内容(由于没有结束标签,因此不能在开始标签和结束标签之间放置任何内容)。 "

由于缺少定义的内容,因此可以通过简单的RegExp(缺少实际解决方案)使用void元素来实现此目的:

1
$temp = preg_replace('#></(area|base|br|col|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)>#si', '/>', $temp);

之后,我们可以继续进行我在问题中遇到的其他愚蠢修补程序:

1
2
3
$temp=str_replace(' xmlns:default="http://www.w3.org/1999/xhtml"','',$temp);
$temp=str_replace('<default:',"<",$temp);
$temp=str_replace('</default:',"</",$temp);