PHP&;XML:如何删除“外部的所有空白”;端子元件”;


PHP & XML: How to remove all whitespaces outside "terminal elements"

首先让我们定义"终端元素"(用于本问题的特定目的)。

我所说的"终端元素"是指内部不包含其他元素元件。

元素参考:http://www.w3schools.com/xml/xml_elements.asp

如何使用PHP从XML文档/节点中删除"终端元素"之外的所有空白(换行符、回车符、制表符和空格)?

规则:只有PHP本机XML解析器(没有正则表达式)。

"终端元素"(叶元素节点)外的所有空白都在文本节点内(因为所有文本都在文本结点内)。因此,如果获得了终端元素之外的所有文本节点,就可以从这些节点中删除所有空白字符。这已经是答案了。

让我们简单地从XML文档中的一个文本节点中删除空白开始。

由于PHP使用UTF-8作为XML解析器的字符编码(在本例中我使用DOMDocument),preg_replace在这里很方便,因为它知道UTF-8和空白字符是什么:

/** @var DomText $text */
$text->nodeValue = preg_replace('~'s+~u', '', $text->textContent);

这将删除文本节点中的所有空白。这是一个演示:

$doc = new DOMDocument();
$doc->loadXML('<root> Very Simple Demo </root>');
$text = $doc->documentElement->childNodes->item(0);
/** @var DomText $text */
$text->nodeValue = preg_replace('~'s+~u', '', $text->textContent);
$doc->save('php://output');

输出:

<?xml version="1.0"?>
<root>VerySimpleDemo</root>

正如您所看到的,空格字符将从该文档中唯一的文本节点中删除。

有了更大的文档和"终端元素",这自然会更有趣,但工作原理基本相同。唯一的区别是获取所有不属于叶元素节点的文本节点。这最好使用xpath查询来完成:

//*[*]/text()

内容如下:所有文本节点都是包含其他元素的元素的子节点。让我们使用以下XML(文件content.xml)作为示例:

<?xml version="1.0"?>
<content>
    <parent>
        <child id="1">
            <title>child 1</title>
            <child id="1">
                <title>
                    child 1.1 with whitespace
                </title>
            </child>
        </child>
    </parent>
</content>

它既包含这样的叶元素,也包含具有子元素的其他元素。它还很好地显示了用于元素缩进的空白。

加载后:

$file = __DIR__ . '/content.xml';
$doc = new DOMDocument();
$doc->load($file);

执行xpath查询需要一个DOMXPath

$xp    = new DOMXPath($doc);
$texts = $xp->query('//*[*]/text()');

剩下的就是迭代所有这些文本节点,并应用上面的空白删除:

foreach ($texts as $text) {
    /** @var DomText $text */
    $text->nodeValue = preg_replace('~'s+~u', '', $text->textContent);
}

结果是:

<?xml version="1.0"?>
<content><parent><child id="1"><title>child 1</title><child id="1"><title>
                    child 1.1 with whitespace
                </title></child></child></parent></content>

这应该能回答问题。但是,如果没有更多的细节或一点"但是…",它就不会是XML

请注意,xpath中的"text()"表示所有类型的文本节点,包括CDATA部分。如果CDATA部分仅包含空白,则上面的代码会在输出中呈现一个空的CDATA部分("<![CDATA[]]>")。一种处理方法是从文档中删除空节点:

/** @var DomText $text */
$text->nodeValue = preg_replace('~'s+~u', '', $text->textContent);
if (!$text->length) {
    $text->parentNode->removeChild($text);
}

然后,这将从文档中删除所有清空的文本节点。保持文档树的整洁。希望这能有所帮助。

DOMDocument::normalizeDocument可以满足您的需求。

如果要规范化单个元素,可以调用DOMNode::normalize