PHP: removing multiple child tags
<div class="article_content">
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<ul>
<li>UPDATE mytable SET tax = amount</li>
</ul>
<p>after you can remove it</p>
<p> </p> <!-- dot want to delete this line -->
<ul><li>ALTER TABLE mytable DROP COLUMN amount;</li>
</ul>
</div>
I want to remove everything <p> </p>
until the first ul
or any tag appears for example <p>.... content .... </p>
.
If I'm going to use this str_replace("<p> </p>","",$string);
one it will remove all blank lines from the string. But I want to delete lines before the first occurrence.
Hopefully this helps you by deleting all the child nodes it starts at
until a new tag appears with some content.
<?php
ini_set('display_errors', 1);
header("Content-Type:text/html; charset=UTF-8");
$string= <<<HTML
<html><body><div class="article_content">
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<ul>
<li>UPDATE mytable SET tax = amount</li>
</ul>
<p>after you can remove it</p>
<p> </p> <!-- dot want to delete this line -->
<ul><li>ALTER TABLE mytable DROP COLUMN amount;</li>
</ul>
</div></body></html>
HTML;
$object = new DOMDocument();
$object->loadHTML($string);
$remove=array();
$nodelist=$object->getElementsByTagName("div")->item(0)->childNodes;
foreach($nodelist as $node)
{
if($node instanceof DOMElement)
{
if($node->tagName=='p' && str_replace(" ","",htmlentities($node->textContent))=="")
{
$remove[]=$node;
}
else
{
break;
}
}
}
foreach($remove as $node)
{
$node->parentNode->removeChild($node);
}
echo $object->saveHTML();
source to share
I think you should try jQuery instead of PHP because jQuery is the best library for moving and manipulating the DOM.
Try the snippet below, hope it is better for you.
$(function() {
$(".article_content p").each(function() {
var self = $(this),
arr = []; // get all blank elements in array
if (self.text().trim().length == 0 // check its length
&&
(self.prev().text().trim().length === 0 || // checking previous element is blank or not
self.next().text().trim().length === 0)) { // checking next element is blank or not
arr.push(self); // if all are blank then add in array
}
// now remove all elements
$(arr).each(function() {
$(this).remove()
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="article_content">
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<ul>
<li>UPDATE mytable SET tax = amount</li>
</ul>
<p>after you can remove it</p>
<p> </p>
<!-- dot want to delete this line -->
<ul>
<li>ALTER TABLE mytable DROP COLUMN amount;</li>
</ul>
</div>
source to share
It might be possible client side like jQuery
- ... prevAll () : - Get the immediately preceding sibling of each element in the set of matched elements. If a selector is provided, it retrieves the previous sibling only if it matches that selector.
- ... first () : - Reduce the set of matched elements to the first in the set.
Example shown below: -
$(function() {
var pTag = $( "ul" ).first().prevAll('p');
pTag.remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<div class="article_content">
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<ul>
<li>UPDATE mytable SET tax = amount</li>
</ul>
<p>after you can remove it</p>
<p> </p> <!-- dot want to delete this line -->
<ul><li>ALTER TABLE mytable DROP COLUMN amount;</li>
</ul>
</div>
source to share
You can go the same way when inserting data into the database. The default creates a paragraph element each time you press Enter: Change the default CKEDITOR setting.
config.autoParagraph = false;
and also you can set the input mode as BR and other appropriate
config.enterMode = CKEDITOR.ENTER_BR;
source to share
// Press F11 to toggle full screen editting (Ctrl+โ+F on Mac OS).
// Press Ctrl+Shift+F to format code.
$string = '
<div class="article_content">
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<ul>
<li>UPDATE mytable SET tax = amount</li>
</ul>
<p>after you can remove it</p>
<p> </p> <!-- dot want to delete this line -->
<ul><li>ALTER TABLE mytable DROP COLUMN amount;</li>
</ul>
</div>
';
$remove=array();
$dom = new DOMDocument;
$dom->loadHTML($string);
//$newstring = $dom->getElementsByTagName('<p> </p>')->item(4);
$newstring = $dom->getElementsByTagName('p');
foreach($newstring as $stringnode)
{
if($stringnode->tagName=='p' && str_replace(" ","",htmlentities($stringnode->textContent))=="")
{
$remove[]=$stringnode;
}
else
{
break;
}
}
foreach($remove as $node)
{
$node->parentNode->removeChild($node);
}
echo $dom->saveHTML();
source to share
It is good practice to use the DOM when working with HTML structure. But in this particular case, unlike other answers, I prefer regexes more:
(?s)<(?:(?:ul|p>(?:(?! )|[^>]*</p>\s*(*ACCEPT)))).*\K
Regex explanation:
(?s) # Enable DOTALL modifier
< # Match a `<`
(?: # Start of non-capturing group (a)
(?: # Start of NCG (b)
ul # Match `ul`
| # OR
p> # Match `p>`
(?: # Start of NGC (c)
(?! ) # Shouldn't be followed by ` `
| # OR
[^>]*</p>\s* # Otherwise match whole `p` tag
(*ACCEPT) # Force engine to end current matching attempt
) # End of NGC (c)
) # End of NGC (b)
).*\K # End of NGC (a), match up to the end of input string and throw it away
PHP code:
echo preg_replace('~(?s)<(?:(?:ul|p>(?:(?! )|[^>]*</p>\s*(*ACCEPT)))).*\K~', '', $html);
source to share