样式与DOM和xpath的无风格链接

时间:2011-06-21 09:27:01

标签: php xpath domdocument

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

感谢Gordon我更新了我的代码:

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元素无法设置样式。

3 个答案:

答案 0 :(得分:2)

使用libxml_use_internal_errors(true)来抑制源自loadHTML的解析错误。

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

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

即可
//a[not(@style)]

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

示例(demo

$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 with an argument, you need at least PHP 5.3.6.

答案 1 :(得分:1)

当您使用内部文档&用于创建实体引用(例如&quot;)之外的其他目的时,会发生第一个错误(编辑之前)。

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

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

答案 2 :(得分:1)

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

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片段,这是一些可以与gordons建议一起使用的附加代码。只是body标签的内部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)
  ;