使用PHP DOM时的nodeValue

时间:2016-06-13 19:37:57

标签: php dom

我正在使用解析器输出PHP DOM的特定元素,例如HTML页面中的标题标签,图像等(我无法控制页面),我想得到nodeValue / textContent没有连接的DOM节点,在可视HTML中没有保留有效的空格(读取:换行符)。

例如,导出标题标签的当前代码如下,简单明了:

SCHYEAR

这对于标准字符串非常有用,但是如果你有HTML,例如:

function getHeadingTags($content){
    $this->dom = new DomDocument();
    @$this->dom->loadHTML($contents);

    $this->xpath = new DOMXPath($this->dom);
    $this->xpath->registerNamespace("php", "http://php.net/xpath");
    $this->xpath->registerPHPFunctions();

    $nodes = $this->xpath->query('//h1|//h2|//h3|//h4|//h5|//h6');

    $results = array();

    if ($nodes->length > 0)
    {       
        foreach ($nodes as $node)
        {                   
            $results[$node->tagName][] = trim($node->textContent);
        }
    }

    return $results;
}

结果是令人讨厌的串联字符串:

<h1>This is a heading<br>that spans two lines</h1>

当然,人们可以预先放置This is a headingthat spans two lines 元素,但它只是感觉有点hacky。通过使用递归<br>和foreach循环我已经处理了元素的层次结构我只是想知道是否有一个解决方案不需要我觉得非常hacky找到并替换其余的工作顶级DOM元素。

我认为这也是列表的问题,例如以下代码:

$node->childNodes

我假设<ul> <li>Test</li> <li>Test2</li> </ul> 上的nodeValue输出类似于<ul>而不是希望TestTest2我知道这是预期的行为但是我希望有一个体面的工作,如果有人有一个可以交?

2 个答案:

答案 0 :(得分:1)

您可以递归搜索DOMText节点的节点的子节点,并使用空格连接它们:

function getNodeText(DOMNode $node) {
    if (is_a($node, "DOMText"))
        return trim($node->nodeValue);

    $nodeValues = array();
    foreach ($node->childNodes as $child)
    {
        $nodeText = getNodeText($child);
        if ($nodeText != "")
        {
            $nodeValues[] = $nodeText;
        }
    }
    return trim(implode(" ", $nodeValues));
}

function getHeadingTags($content) {
    $dom = new DomDocument();
    $dom->loadHTML($content);

    $xpath = new DOMXPath($dom);
    $xpath->registerNamespace("php", "http://php.net/xpath");
    $xpath->registerPHPFunctions();

    $nodes = $xpath->query('//h1|//h2|//h3|//h4|//h5|//h6');

    $results = array();

    if ($nodes->length > 0)
    {       
        foreach ($nodes as $node)
        {                   
            $results[$node->tagName][] = getNodeText($node);
        }
    }

    return $results;
}

请在此处查看示例:https://3v4l.org/pYMFr

答案 1 :(得分:0)

您可能需要逻辑地(在您的脑海中)分离值和输出。

  1. 假设某人有100个&lt; / br&gt; -Tags,或许你不想渲染它,并且用你的简短例子清楚地表明了你所写的内容。
  2. 另一种选择是打印html标签或仅打印内容(标签之间)。
  3. 一个主张是用特殊符号替换某些节点(即br-tag用\ n和tab bei \ t)。
  4. 如果您对在线编辑器有所了解(比如您在插入问题的stackoverflow上),您可能知道段落标签可能只是添加到前端但文本通常是在数据库中没有p-tags的情况下保存的
  5. 第4点指出了这一点:当您将数据保存在数据库中时,您要解析它们可能与您打印输出时的数据不同。
  6. 如果你想保留一些标签的逻辑,比如h1-h6或列表暗示某些换行也许你想解析另一个现有的结构格式。您可以使用“markdown”[1]或“ReStructuredText”[2]。
  7. 根据您遇到问题的时间,您可以使用“markdown”之类的内容来替换HTML-Tags,或者只是替换一些像您想要的换行符。我编写了一些解析器,并且经常将原始HTML保存在数据库字段中,因此我始终可以控制在分隔字段中保存的节点。

    关于列表,您可以替换&lt; / li&gt;由&lt; / br&gt;。 如果你永远不知道你解析的页面,你可能会假设还包括许多其他标签,即dl,dt,dd,address,....

    即使您按照标准验证所有HTML标签,也不能保证它们像这样使用。一个例子是使用ul-lists构建的菜单,在CSS样式化之后,页面上的显示通常会大不相同,因此可以更改元素的许多属性,并且不能依赖块元素的原始属性或内联 - 元件。

    [1] https://en.wikipedia.org/wiki/Markdown [2] https://en.wikipedia.org/wiki/ReStructuredText