【问题标题】:PHP DOM Search HTML and specify the location of an IMG within PPHP DOM 搜索 HTML 并在 P 中指定 IMG 的位置
【发布时间】:2012-02-13 19:50:20
【问题描述】:

我希望解析一些从 ckeditor 提交的 HTML。发布的 HTML 如下所示:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">#012<html><body><p>Text Before <img alt="HAMBURGER" height="20" src="/sites/all/modules/ckeditor/plugins/apoji/images/emoji-E120.png" title="HAMBURGER" width="20"> Text After</p></body></html>

(格式化,不声明一致性):

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
    <body>
        <p>
            Text Before
            <img alt="HAMBURGER" height="20" src="/sites/all/modules/ckeditor/plugins/apoji/images/emoji-E120.png" title="HAMBURGER" width="20">
            Text After
        </p>
    </body>
</html>

我一直在寻找类似下面的东西:

$DOM = new DOMDocument;
$DOM->loadHTML($input);

$items = $DOM->getElementsByTagName('*');
foreach ($items as $item) {
    switch ($item->nodeName) {
    case "p":
        $sms .= $item->nodeValue."\n";
        break;
    case "img":
        $img_out .= "IMG Attr: ".$item->getAttribute('title')."\n";
        break;
    }
}

我的目标是创建一个纯文本字符串,根据其标题替换图像,所以我有一个类似的字符串:

Text Before HAMBURGER Text After

我已经开始走 DOM 路线,因为这似乎是最好的方法,但现在我有两个问题:

  1. 如果我像上面那样遍历文档,IMG 会在文本之后结束, 不在中间。我怎样才能避免这种情况?
  2. 从 DOM 文档中提取所有纯文本的最佳方法,保持项目的顺序(链接到第 1 点)。

在此先感谢任何可以给我一些意见的人。

【问题讨论】:

  • 你会使用 JavaScript 吗? jQuery 很容易处理这个问题,然后你可以通过 AJAX 提交它。
  • 所以你真正的问题是“如何用它的标题属性替换一个 IMG 元素”,对吧?
  • 你的标记总是那么简单还是有更复杂的情况?

标签: php html dom


【解决方案1】:

我的目标是创建一个纯文本字符串,根据其标题替换图像,所以我有一个类似的字符串:

Text Before HAMBURGER Text After

一个选项是使用 XPath 查询来选择您想要的文本/标题,并输出它们各自的值。

$html = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><body><p>Text Before<img alt="HAMBURGER" height="20" src="/sites/all/modules/ckeditor/plugins/apoji/images/emoji-E120.png" title="HAMBURGER" width="20">Text After</p></body></html>';

$doc = new DOMDocument;
$doc->loadHTML($html);

$xpath = new DOMXPath($doc);
$nodes = $xpath->query('/html/body//text() | /html/body//img/@title');

$text = '';
foreach ($nodes as $node) {
    $text .= $node->nodeValue . ' ';
}

echo $text; // Text Before HAMBURGER Text After 

【讨论】:

  • 感谢@salathe,我喜欢这个解决方案!最后我使用了这样的一行:$newitem = new DOMElement('div', $item-&gt;getAttribute('title')); $item-&gt;parentNode-&gt;replaceChild($newitem, $item); 稍后在我使用的代码中:$html = $DOM-&gt;saveHTML(); $html = substr(strip_tags($html), 1);(是的,不理想)但我认为你的方法会给我一个更简洁的解决方案,非常感谢!
【解决方案2】:

您可以使用XPath 查找特定项目,然后使用replace them 查找新节点。

例如

<?php
foreach( range(0,2) as $i ) {
    $doc = new DOMDocument;
    $doc->loadhtml( getData($i) );
    foo($doc);
}


function foo(DOMDocument $doc) {
    $xpath = new DOMXPath($doc);
    foreach( $xpath->query('//p/img') as $img ) {
        $alt = $img->getAttribute('alt');

        $img->parentNode->replaceChild(
            $doc->createTextNode($alt),
            $img
        );
    }
    echo "\n---\n", $doc->savehtml(), "\n---\n";
}



function getData($i) {
    $rv = null;
    switch($i) {
        case 0; $rv = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><body><p>Text Before <img alt="HAMBURGER" height="20" src="/sites/all/modules/ckeditor/plugins/apoji/images/emoji-E120.png" title="HAMBURGER" width="20"> Text After</p></body></html>'; break;
        case 1; $rv = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
            <html>
                <body>
                    <p>
                        Text Before <img alt="HAMBURGER" height="20" src="/sites/all/modules/ckeditor/plugins/apoji/images/emoji-E120.png" title="HAMBURGER" width="20">
                        Text After
                    </p>
                </body>
            </html>';
            break;
        case 2; $rv = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
            <html>
                <body>
                    <p>
                        Text Before <img alt="HAMBURGER" height="20" src="/sites/all/modules/ckeditor/plugins/apoji/images/emoji-E120.png" title="HAMBURGER" width="20">
                        Text After
                    </p>
                    <p>
                        Text Before <img alt="HAMBURGER2" height="20" src="/sites/all/modules/ckeditor/plugins/apoji/images/emoji-E120.png" title="HAMBURGER" width="20">
                        Text After
                    </p>
                    <p>
                        Text Before <img alt="HAMBURGER3" height="20" src="/sites/all/modules/ckeditor/plugins/apoji/images/emoji-E120.png" title="HAMBURGER" width="20">
                        Text After
                    </p>
                </body>
            </html>';
            break;
    }   
    return $rv; 
}

打印

---
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p>Text Before HAMBURGER Text After</p></body></html>

---

---
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>
                    <p>
                        Text Before HAMBURGER
                        Text After
                    </p>
                </body></html>

---

---
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>
                    <p>
                        Text Before HAMBURGER
                        Text After
                    </p>
                    <p>
                        Text Before HAMBURGER2
                        Text After
                    </p>
                    <p>
                        Text Before HAMBURGER3
                        Text After
                    </p>
                </body></html>

---

对于您的问题 #2:请详细说明。可以像echo $doc-&gt;documentElement-&gt;textContent 一样简单。但也可能最终使用XSL(T)

【讨论】:

  • 我不认为他试图替换任何东西,相反,他似乎只是想按文档顺序获取所有文本和图像标题内容的字符串。
  • @salathe:是的,听起来不错(在问题的上下文中)。 +1 为您的回答...
【解决方案3】:

您可以简单地使用正则表达式替换:

<?php
$text = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">#012<html><body><p>Text Before <img alt=\"HAMBURGER\" height=\"20\" src=\"/sites/all/modules/ckeditor/plugins/apoji/images/emoji-E120.png\" title=\"HAMBURGER\" width=\"20\"> Text After</p></body></html>";
$match = array();
preg_match("/<p[^>]*>(.*(?=<\/p))/i", $text, $match);
echo preg_replace("/<img[^>]*title=\"([^\"]+)\"[^>]*>/i", "$1", $match[1]);
?>

【讨论】:

  • No!
  • Yes, in known and limited cases. 如果 HTML 的结构像给定示例中那样简单,则正则表达式可以正常工作。
  • 引用 OP:“我正在寻找解析一些从 ckeditor 提交的 HTML”。我认为可以肯定地假设这不会是一个已知且有限的案例
猜你喜欢
  • 2017-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-05
  • 2016-06-03
  • 2014-08-22
相关资源
最近更新 更多