Per*_*ses 3 php encoding dom libxml2
我想使用PHP 标准库的DOM部分对PHP文档执行某些操作.正如其他人已经发现的那样,人们必须处理解码后的实体.为了说明困扰我的是什么,我举了一个简单的例子.
假设我们有以下代码
$doc = new DOMDocument();
$doc->loadXML(<XML data>);
$xpath = new DOMXPath($doc);
$node_list = $xpath->query(<some XPath>);
foreach($node_list as $node) {
//do something
}
Run Code Online (Sandbox Code Playgroud)
如果循环中的代码是类似的
$attr = "<some string>";
$val = $node->getAttribute($attr);
//do something with $val
$node->setAttribute($attr, $val);
Run Code Online (Sandbox Code Playgroud)
它工作正常.但如果它更像
$text = $node->textContent;
//do something with $text
$node->nodeValue = $text;
Run Code Online (Sandbox Code Playgroud)
并且$text包含一些已解码的&,它不会被编码,即使根本没有做任何事情$text.
此刻,我申请的htmlspecialchars上$text之前,我设置$node->nodeValue它.现在我想知道
我必须处理的XML文档主要是feed,因此解决方案应该非常通用.
编辑
事实证明我的原始问题的范围是错误的,对不起.在这里,我提供了一个实际描述行为的例子.
$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();
Run Code Online (Sandbox Code Playgroud)
如果我在CLI上执行此代码
php beeb.php |egrep 'link|Warning'
Run Code Online (Sandbox Code Playgroud)
我得到的结果就像
<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 >
(并且,如果省略循环)并根据警告
警告:main():第15行的/private/tmp/beeb.php中未终止的实体引用ns_source = PublicRSS20-sa
当我申请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 = "&";
echo "After Edit 2: ", $doc->saveXML($text), "\n";
Run Code Online (Sandbox Code Playgroud)
然后输出如下(PHP 5.0.0 - 5.5.0):
Before Edit: *
After Edit 1: &
After Edit 2: &amp;
Run Code Online (Sandbox Code Playgroud)
这表明,设置nodeValue一个的DOMText-node期望一个UTF-8编码的字符串和DOM库自动编码XML保留字符.
所以,你应该不适用htmlspecialchars()在任何文本添加这种方式.这将创建一个双重编码.
在您编写体验时,我建议您在命令行/ IDE中执行一个独立的PHP示例,以便您可以准确地查看输出.并不是说您的浏览器将其呈现为HTML,然后您认为保留的XML字符尚未编码.
正如您所指出的那样,您不是在编辑节点DOMText而是在编辑DOMElement节点.它的工作方式有点不同,这里的&角色需要作为实体&而不是逐字传递,但只有这个角色.
所以这需要更多的工作:
DOMText节点.一切都将完美编码.DOMText节点表单作为子节点添加到第一步.并做了.在这里你的内在foreach修改显示:
foreach($node_list as $node) {
$text = $doc->createTextNode($node->textContent);
$node->nodeValue = "";
$node->appendChild($text);
}
Run Code Online (Sandbox Code Playgroud)
对于你的具体例子,虽然我必须承认我不明白为什么你这样做,因为这不会改变值,所以它不需要这个.
提示:在PHP中DOMDocument可以直接打开这个feed,你不需要在这里卷曲:
Run Code Online (Sandbox Code Playgroud)$doc = new DOMDocument(); $doc->load("http://feeds.bbci.co.uk/news/rss.xml?edition=uk");