【问题标题】:Move img before parent paragraph using simple-html-dom使用 simple-html-dom 将 img 移动到父段落之前
【发布时间】:2016-05-31 04:50:48
【问题描述】:

好吧,我真的被困在了这个:/ 到目前为止,已尝试标题和 DOMDocument 中提到的 SimpleHTMLDom .. $html 将来自我的 Processwire 驱动页面中的 CKEditor,我制作了一个 textformatter 来自动对输出进行后处理。

所以这是测试数据

<?php
$html = <<<_DATA
    <p><img src="http://placehold.it/100x100"><img src="http://placehold.it/130x100">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam</p>
_DATA;

这是我的 SimpleHTMLDom 尝试

<?php
$dom = str_get_html($html);
$imgs = $dom->find('img');

foreach ($imgs as $img) {
    $i = $img->outertext;
    $img->outertext = '';
    $img->parent()->outertext = $i . $img->parent()->outertext;
}
echo $dom->save();
$dom->clear();

上面的 $html 中只有一个 img 并且一切都按预期工作,但是这两个(或更多)返回重复。

  1. 问题,它改变了排序顺序,所以 130x100 的图像将是第一个。 我知道我在预先设置,但我不知道如何更改它。试图将所有图像填充到一个变量中,以便它们保持有序,但是我不知道如何将它添加到段落中。..

  2. 1234563最后两个(正如我所说,1 可以正常工作)

我做错了什么?

这在单独的问题中可能会更好,但我想表明我也尝试过 DOMDocument 但无法让 insertBefore 工作(根本) 我尝试了不同的变体(在下面的代码中未注释)

<?php
include_once "./classes/SmartDOMDocument.class.php";
$dom = new SmartDOMDocument();
$dom->loadHTML($html);

$imgs = $dom->getElementsByTagName('img');

foreach ($imgs as $img) {
    $i = $dom->createElement('img');
    $i->src = $img->getAttribute('src');
    $img->parentNode->insertBefore($i, $img->parentNode);
    // $img->insertBefore($i, $img->parentNode);
    // $dom->insertBefore($i, $img->parentNode);
    $img->parentNode->removeChild($img);
}

echo $dom->saveHTMLExact();

如果某些内容没有得到充分的记录或被问到,请随时发表评论,我会尽力解释得更好:)

编辑: html(来自上面提到的所见即所得)有时会在段落的中间或末尾保存图像,可能包含单个或多个图像(未定义的数量),并且会有该html中有多个段落

编辑:应该包括我希望输出的方式

所以这是输入

<p>
    <img src="http://placehold.it/100x100">
    <img src="http://placehold.it/130x100">
    <img src="http://placehold.it/160x100">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam
</p>

这应该是结果

<div class="inlineGallery">
    <figure><img src="http://placehold.it/100x100"></figure>
    <figure><img src="http://placehold.it/130x100"></figure>
    <figure><img src="http://placehold.it/160x100"></figure>
</div>
<p>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam
</p>

很抱歉没有提到这些图像应该被包裹在图形中,然后在容器中。单个图像不需要额外的容器,但这实际上并不重要。 我用完整的代码进行了测试。在图中包装图像,在适用的地方添加 figcaption 并将多个图包装在一个 div 中,一切都适用于只有单个图像的文章,然后我在另一篇文章中遇到了一些类似于上面测试数据的 html这导致提到的重复..所以我剥离了代码以查看问题出在哪里没有运气..这就是为什么我只是在问题中添加了这个简单的代码,因为我认为一旦这个工作正常,另一个也可以工作;-)

希望现在更清楚了吗?!

【问题讨论】:

  • 您没有尝试将其分配到另一个单独的容器中,您只是对图像标签感兴趣,对吧?
  • 为什么坚持使用 DOM 有什么意义吗?为什么不只是简单的字符串替换?
  • @RodrigoDuterte 听起来很有趣,但我现在不知道该怎么做:S 也许你有一个例子?如果不存在,尝试将包含第一个图像的 div 附加到段落中,否则将以下图像附加到该 div 但每个图像都有自己的 div
  • @faster 你有一些简单的示例代码吗?

标签: php html domdocument simple-html-dom php-parser


【解决方案1】:

所以这是完成所质疑工作的基本代码

// turn double linebreaks into paragraphs <br><br> to </p><p>
$value = preg_replace('#(?:<br\s*/?>\s*?){2,}#', '</p><p>', $value);

$dom = str_get_html($value);

/* first getting all <p> */
$paragraphs = $dom->find('p');

foreach ($paragraphs as $p) {
    $imgs = $p->find('img');

    /* init gallery container */
    $gallery = "<div class='gallery'>";
    foreach  ($imgs as $img) {
        /* get the current image */
        $i = $img->outertext;
        /* wrap in link */
        $i = "<a href='Link'>$i</a>";
        /* append to gallery */
        $gallery .= $i;
        /* remove original image from paragraph */
        $img->outertext = '';
    }
    /* close new gallery */
    $gallery .= "</div>";
    /* remove unnecessary <br> */
    $newParagraph = trim(preg_replace( '#^\s*(?:<br\s?\/?>)*\s*|(?:<br\s?\/?>)*\s*$#', '', trim($p->innertext)));
    /* wrap tidied text into <p> */
    $newParagraph = "<p>$newParagraph</p>";
    /* replace old paragraph by gallery and new paragraph */
    $p->outertext = $gallery . $newParagraph;
}
// save dom to $value
$value = $dom->save();
// clear dom
$dom->clear();

但谁对我使用它的完整计划感兴趣,应该看看 Processwire 论坛https://processwire.com/talk/topic/13471-better-ckeditor-image-insertion-at-least-for-me/

【讨论】:

    【解决方案2】:

    更新示例 :-)

    <?php
        $html = "asdasd <p><img class=\"wrap\" src=\"http://placehold.it/100x100\">    <img class=\"wrap\" src=\"http://placehold.it/130x100\">  <img class=\"wrap\" src=\"http://placehold.it/160x100\">    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam</p> asdasd    ";
    
        $pattern = '/(<p>)((<img [^>]+>\s*)+)(.+?)(<\/p>)/i';
    
        $replacement = '<div class="inlineGallery">${2}</div> ${1} ${4}${5}';
        $html2 = preg_replace($pattern, $replacement, $html);
    
        $pattern2 = '/(<img class=\"wrap\" [^>]+>)/i';
        $replacement2 = '<figure>${1}</figure>';
        echo preg_replace($pattern2, $replacement2, $html2);
    ?>
    

    这可能可以在一个正则表达式中完成,但这是我的解决方案。您必须对这些图像进行一些识别才能进行第二次运行。

    【讨论】:

    • 感谢您的代码,用两张图片尝试了您的第一个代码,结果第一张图片被添加到段落之前,但第二张图片保持不变..用所需结果示例编辑了我的问题
    • 嗯..那些图像没有类..实际上我不明白他们为什么需要一个?防止匹配其他图像?这没问题,因为我只处理所见即所得的输出,无论如何我都在处理所有图像..但是当我删除class=\"wrap\" 时,它会变得混乱..留下它会在 inlineGallery 中填充一些图像,但不是全部..你不是,偶然地,知道如何修复simple_html_dom?我第一次使用正则表达式对此进行了编码,并且总是遇到一些混乱..这就是我切换到 dom 解析器的原因..但是现在移动部分出现了问题..
    • 如果您处理字符串中的所有图像,则只需从第二个模式中删除换行 ` $pattern2 = '/(]+>)/i';`
    • 如果你仍然热衷于使用 simple_html_dom,你需要先找到所有的 'p',然后对于每一个,找到所有图像,将它们从 p 中拉出,然后替换整个 p带有结果的节点。我会改用 xslt,那里的代码会更简洁。
    • 不,他们不通知。现在您的解决方案看起来既干净又合理:-)
    猜你喜欢
    • 2014-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    • 1970-01-01
    • 2013-03-10
    相关资源
    最近更新 更多