Если я пытаюсь загрузить документ HTML в PHP DOM, я получаю сообщение об ошибке в строках of:
Error DOMDocument::loadHTML() [domdocument.loadhtml]: ID someAnchor already defined in Entity, line: 9
Я не могу понять почему. Вот код, который загружает строку HTML в DOM.
Первый без тега привязки, а второй с ним. Второй документ выдает ошибку.
Надеюсь, вы сможете вырезать и вставить его в сценарий и запустить его, чтобы увидеть тот же результат:
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
$stringWithNoAnchor = <<<EOT
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body >
<h1>Hello</h1>
</body>
</html>
EOT;
$stringWithAnchor = <<<EOT
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body >
<h1>Hello</h1>
<a name="someAnchor" id="someAnchor"></a>
</body>
</html>
EOT;
class domGrabber
{
public $_FileErrorStr = '';
/**
*@desc DOM object factory does the work of loading the DOM object
*/
public function getLoadAsDOMObj($htmlString)
{
$this->_FileErrorStr =''; //reset error container
$xmlDoc = new DOMDocument();
set_error_handler(array($this, '_FileErrorHandler')); // Warnings and errors are suppressed
$xmlDoc->loadHTML($htmlString);
restore_error_handler();
return $xmlDoc;
}
/**
*@desc public so that it can catch errors from outside this class
*/
public function _FileErrorHandler($errno, $errstr, $errfile, $errline)
{
if ($this->_FileErrorStr === null)
{
$this->_FileErrorStr = $errstr;
}
else {
$this->_FileErrorStr .= (PHP_EOL . $errstr);
}
}
}
$domGrabber = new domGrabber();
$xmlDoc = $domGrabber->getLoadAsDOMObj($stringWithNoAnchor );
echo 'PHP Version: '. phpversion() .'<br />'."\n";
echo '<pre>';
print $xmlDoc->saveXML();
echo '</pre>'."\n";
if ($domGrabber->_FileErrorStr)
{
echo 'Error'. $domGrabber->_FileErrorStr;
}
$xmlDoc = $domGrabber->getLoadAsDOMObj($stringWithAnchor);
echo '<pre>';
print $xmlDoc->saveXML();
echo '</pre>'."\n";
if ($domGrabber->_FileErrorStr)
{
echo 'Error'. $domGrabber->_FileErrorStr;
}
Я получаю следующее в моем представлении исходного кода Firefox:
PHP Version: 5.2.9<br />
<pre><?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml"><head><title>My document</title><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /></head><body>
<h1>Hello</h1>
</body></html>
</pre>
<pre><?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml"><head><title>My document</title><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /></head><body>
<h1>Hello</h1>
<a name="someAnchor" id="someAnchor"></a>
</body></html>
</pre>
Error
DOMDocument::loadHTML() [<a href='domdocument.loadhtml'>domdocument.loadhtml</a>]: ID someAnchor already defined in Entity, line: 9
Итак, почему DOM сообщает, что someAnchor уже определен?
Обновление:
Я экспериментировал с обоими
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
$stringWithNoAnchor = <<<EOT
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body >
<p>stringWithNoAnchor</p>
</body>
</html>
EOT;
$stringWithAnchor = <<<EOT
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body >
<p>stringWithAnchor</p>
<a name="someAnchor" id="someAnchor" ></a>
</body>
</html>
EOT;
$stringWithAnchorButOnlyIdAtt = <<<EOT
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body >
<p>stringWithAnchorButOnlyIdAtt</p>
<a id="someAnchor"></a>
</body>
</html>
EOT;
class domGrabber
{
public $_FileErrorStr = '';
public $useHTMLMethod = TRUE;
/**
*@desc DOM object factory does the work of loading the DOM object
*/
public function loadDOMObjAndWriteOut($htmlString)
{
$this->_FileErrorStr ='';
$xmlDoc = new DOMDocument();
set_error_handler(array($this, '_FileErrorHandler')); // Warnings and errors are suppressed
if ($this->useHTMLMethod)
{
$xmlDoc->loadHTML($htmlString);
}
else {
$xmlDoc->loadXML($htmlString);
}
restore_error_handler();
echo "<h1>";
echo ($this->useHTMLMethod) ? 'using xmlDoc->loadHTML() ' : 'using $xmlDoc->loadXML()';
echo "</h1>";
echo '<pre>';
print $xmlDoc->saveXML();
echo '</pre>'."\n";
if ($this->_FileErrorStr)
{
echo 'Error'. $this->_FileErrorStr;
}
}
/**
*@desc public so that it can catch errors from outside this class
*/
public function _FileErrorHandler($errno, $errstr, $errfile, $errline)
{
if ($this->_FileErrorStr === null)
{
$this->_FileErrorStr = $errstr;
}
else {
$this->_FileErrorStr .= (PHP_EOL . $errstr);
}
}
}
$domGrabber = new domGrabber();
echo 'PHP Version: '. phpversion() .'<br />'."\n";
$domGrabber->useHTMLMethod = TRUE; //DOM->loadHTML
$domGrabber->loadDOMObjAndWriteOut($stringWithNoAnchor);
$domGrabber->loadDOMObjAndWriteOut($stringWithAnchor );
$domGrabber->loadDOMObjAndWriteOut($stringWithAnchorButOnlyIdAtt);
$domGrabber->useHTMLMethod = FALSE; //use DOM->loadXML
$domGrabber->loadDOMObjAndWriteOut($stringWithNoAnchor);
$domGrabber->loadDOMObjAndWriteOut($stringWithAnchor );
$domGrabber->loadDOMObjAndWriteOut($stringWithAnchorButOnlyIdAtt);
Если вы загружаете XML-файлы (в этом случае XHTML — это XML), вам следует использовать DOMDocument::loadXML()
, а не DOMDocument:: loadHTML()
.
В HTML как name
, так и id
вводят идентификатор. Итак, вы повторяете идентификатор «someAnchor», отсюда и ошибка.
Однако валидатор W3C разрешает повторяющиеся идентификаторы в форме, которую вы показываете . Это может быть ошибка libmxl2.
В этом отчете об ошибке для libxml2 пользователь предлагает исправление, которое будет учитывать только атрибут name
в качестве идентификатора:
Согласно спецификациям HTML и XHTML, только атрибут имени элемента разделяет пространство имен с атрибутами id. Для некоторых элементов можно утверждать что несколько экземпляров с одним и тем же именем не имеют смысла, но они должны тем не менее, не следует рассматривать в том же пространстве имен, что и идентификатор других элементов атрибуты.
См. http://www.zvon.org/xxl/xhtmlReference/Output/Strict/attr_name.html для всех элементы, которые принимают атрибуты имени и их семантику.