使用 DOM 和 xpath 设置无样式链接的样式


Style unstyled links with DOM and xpath

对于我正在构建的系统,我正在定义一个存储在LINKSTYLE中的通用style,该应该应用于尚未样式化(内联(a元素。我对DOMDocumentxpath不是很有经验,我无法弄清楚出了什么问题。

感谢戈登,我更新了我的代码:

libxml_use_internal_errors(true);    
$html  = '<a href="#">test</a>'.
         '<a href="#" style="border:1px solid #000;">test2</a>';
$dom    = new DOMDocument();
$dom->loadHtml($html);
$dom->normalizeDocument();  
$xpath = new DOMXPath($dom);
foreach($xpath->query('//a[not(@style)]') as $node)
    $node->setAttribute('style','border:1px solid #000');
return $html;

有了这个更新的代码,我不再收到错误,但是a元素没有样式化。

使用 libxml_use_internal_errors(true) 来抑制由 loadHTML 引起的解析错误。

  • libxml_use_internal_errors() — 禁用 libxml 错误并允许用户获取错误信息

XPath 查询无效,因为contains需要在样式属性中搜索值。

  • fn:contains($arg1 as xs:string?, $arg2 as xs:string?) as xs:boolean

如果要查找没有样式元素的所有锚点,只需使用

//a[not(@style)]

看不到更改,因为您正在返回存储在 $html 中的字符串。使用 DOMDocument 加载字符串后,必须在运行查询并修改该字符串的 DOMDocument 内部表示形式后将其序列化回来。

示例(演示(

$html = <<< HTML
<ul>
    <li><a href="#foo" style="font-weight:bold">foo</a></li>
    <li><a href="#bar">bar</a></li>
    <li><a href="#baz">baz</a></li>
</ul>
HTML;
$dom = new DOMDocument;
$dom->loadHTML($html);
$xp = new DOMXpath($dom);
foreach ($xp->query('//a[not(@style)]') as $node) {
    $node->setAttribute('style', 'font-weight:bold');
}
echo $dom->saveHTML($dom->getElementsByTagName('ul')->item(0));

输出:

<ul>
<li><a href="#foo" style="font-weight:bold">foo</a></li>
    <li><a href="#bar" style="font-weight:bold">bar</a></li>
    <li><a href="#baz" style="font-weight:bold">baz</a></li>
</ul>

请注意,为了将saveHTML与参数一起使用,您至少需要 PHP 5.3.6。

当您在文档内将&用于创建实体引用以外的其他目的(例如 &quot; (。

通常,当您分隔 GET 参数时,这会发生在 URL 中。

您可以使用 Gordon 的建议忽略此错误或修复它(将&的出现次数替换为 &amp; (。

我想知道是否有可能更 CCS 地解决这个问题,例如使用选择器。在 CSS3 中,可以只处理那些没有 style 属性的<a>标记:

a:not([style]) {border:1px solid #000;}

因此,如果您的文档已经有样式表,则可以轻松添加。

如果没有,则必须将<style>添加到文档中。这也可以用DomDocument完成,但我发现它有点复杂。然而,我让它为一些小游戏工作:

libxml_use_internal_errors(true);    
$html  = '<a href="#">test</a>'.
         '<a href="#" style="border:1px solid #000;">test2</a>';
$dom = new DOMDocument();
$dom->loadHtml($html);
$dom->normalizeDocument();
// ensure that there is a head element, body will always be there
// because of loadHtml();
$head = $dom->getElementsByTagName('head');
if (0 == $head->length) {
    $head = $dom->createElement('head');
    $body = $dom->getElementsByTagName('body')->item(0);
    $head = $body->parentNode->insertBefore($head, $body);
} else {
    $head=$head->item(0);
}
// append style tag to head.
$css = 'a:not([style]) {border:1px solid #000;}';
$style = $dom->createElement('style');
$style->nodeValue=$css;
$head->appendChild($style);
$dom->formatOutput = true;
$output = $dom->saveHtml();
echo $output;

示例输出:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head><style>a:not([style]) {border:1px solid #000;}</style></head>
<body>
<a href="#">test</a><a href="#" style="border:1px solid #000;">test2</a>
</body>
</html>

如果 CSS 与其他更高的选择器发生冲突,这不是一个简单的解决方案。 不过!important可能会有所帮助。

网页片段

就获取更改的 HTML 片段而言,这是一些可以与戈登建议一起使用的附加代码。只是正文标签的内部html,这次我玩了一下SPL:

// get html fragment
$output = implode('', array_map(
  function($node) use ($dom) { return $dom->saveXml($node); },
  iterator_to_array($xpath->query('//body/*'), false)))
  ;

foreach 绝对更具可读性和内存友好性:

// get html fragment
$output = '';
foreach($xpath->query('//body/*') as $node) 
  $output .= $dom->saveXml($node)
  ;