gpt4 book ai didi

php - PHP 中的 DOM : Decoded entities and setting nodeValue

转载 作者:可可西里 更新时间:2023-11-01 00:14:42 25 4
gpt4 key购买 nike

我想使用 PHP 使用 DOM 对 XML 文档执行某些操作它的标准库的一部分。正如其他人已经discovered ,然后必须处理解码的实体。为了说明困扰我的问题,我举了一个简单的例子。

假设我们有如下代码

$doc = new DOMDocument();
$doc->loadXML(<XML data>);

$xpath = new DOMXPath($doc);
$node_list = $xpath->query(<some XPath>);

foreach($node_list as $node) {
//do something
}

如果循环中的代码是这样的

$attr = "<some string>";
$val = $node->getAttribute($attr);
//do something with $val
$node->setAttribute($attr, $val);

它工作正常。但如果更像是

$text = $node->textContent;
//do something with $text
$node->nodeValue = $text;

$text 包含一些解码的&,它不会被编码,即使根本没有对$text 做任何事情。

此刻,我申请htmlspecialchars在我设置 $node->nodeValue 之前在 $text 上。现在我想知道

  1. 如果这足够了,
  2. 如果没有,什么就足够了,
  3. 如果有更优雅的解决方案,例如属性操作。

我必须处理的 XML 文档主要是提要,因此解决方案应该非常通用。


编辑

原来我原来的问题范围不对,抱歉。在这里,我提供了一个实际发生所描述行为的示例。

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://feeds.bbci.co.uk/news/rss.xml?edition=uk");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);

$doc = new DOMDocument();
$doc->loadXML($output);

$xpath = new DOMXPath($doc);
$node_list = $xpath->query('//item/link');

foreach($node_list as $node) {
$node->nodeValue = $node->textContent;
}
echo $doc->saveXML();

如果我在 CLI 上执行这段代码

php beeb.php |egrep 'link|Warning'

我得到这样的结果

<link>http://www.bbc.co.uk/news/world-africa-23070006#sa-ns_mchannel=rss</link>

应该是

<link>http://www.bbc.co.uk/news/world-africa-23070006#sa-ns_mchannel=rss&ns_source=PublicRSS20-sa</link>

(并且是,如果循环被省略)并根据警告

Warning: main(): unterminated entity reference ns_source=PublicRSS20-sa in /private/tmp/beeb.php on line 15

当我将 htmlspecialchars 应用于 $node->textContent 时,它工作正常,但我觉得这样做很不舒服。

最佳答案

您的问题基本上是是否设置 DOMText::nodeValue到 XML 编码字符串或逐字字符串。

所以让我们尝试一下,将其设置为 &'& 看看会发生什么:

$doc = new DOMDocument();
$doc->loadXML('<root>*</root>');

$text = $doc->documentElement->childNodes->item(0);

echo "Before Edit: ", $doc->saveXML($text), "\n";

$text->nodeValue = "&";

echo "After Edit 1: ", $doc->saveXML($text), "\n";

$text->nodeValue = "&amp;";

echo "After Edit 2: ", $doc->saveXML($text), "\n";

然后输出如下(PHP 5.0.0 - 5.5.0):

Before Edit: *
After Edit 1: &amp;
After Edit 2: &amp;amp;

这表明设置 DOMText 节点的 nodeValue 需要 UTF-8 编码字符串,DOM 库会自动对 XML 保留字符进行编码。

因此,您不应htmlspecialchars() 应用到以这种方式添加的任何文本上。这会产生双重编码。

当您编写时,您会遇到相反的情况,我建议您在命令行上/在您的 IDE 中执行一个独立的 PHP 示例,以便您可以准确地看到输出。并不是说您的浏览器将其呈现为 HTML,然后您认为保留的 XML 字符未被编码。


正如您所指出的,您不是在编辑 DOMText,而是在编辑 DOMElement 节点。它的工作方式有点不同,这里 & 字符需要作为实体 & 而不是逐字传递,但是只有这个字符。

所以这需要更多的工作:

  1. 读出文本内容并将其转换为DOMText 节点。一切都将被完美编码。
  2. 删除元素节点的节点值,使其为空。
  3. DOMText 节点表单附加为子节点。

完成了。这里你的内部 foreach 修改显示:

foreach($node_list as $node) {
$text = $doc->createTextNode($node->textContent);
$node->nodeValue = "";
$node->appendChild($text);
}

对于你的具体例子,尽管我必须承认我不明白你为什么这样做,因为这不会改变值(value),所以它不需要这个。

Tip: In PHP DOMDocument can open this feed directly, you don't need curl here:

$doc = new DOMDocument();
$doc->load("http://feeds.bbci.co.uk/news/rss.xml?edition=uk");

关于php - PHP 中的 DOM : Decoded entities and setting nodeValue,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17321770/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com