How to use DOMDocument insertBefore - php

I have a div and I'm trying to insert a couple elements (h3 and p) into the div ahead of the existing h3 and p elements already living inside the div. The PHP documentation for insertBefore (http://www.php.net/manual/en/domnode.insertbefore.php) says this is exactly what should happen, but instead of inserting ahead of the existing elements, its replacing all existing elements inside my 'content' div.
Here's my code:
$webpage = new DOMDocument();
$webpage->loadHTMLFile("news.html");
$headerelement = $webpage->createElement('h3', $posttitle);
$pelement = $webpage->createElement('p', $bodytext);
$webpage->formatOutput = true;
$webpage->getElementById('content')->insertBefore($headerelement);
$webpage->getElementById('content')->insertBefore($pelement);
$webpage->saveHTMLFile("newpost.html");
I'm sure I'm just not understanding something... any help would be appreciated, thanks.

It's because you're not specifying a reference node that the inserted node should be inserted before. Think of it like this:
$whatTheElementIsInsertedInto->insertBefore($theElement, $whatItIsInsertedBefore)
Live demo (click).
$dom = new DOMDocument();
$dom->loadHtml('
<html><head></head>
<body>
<div id="content">
<h3>Original h3</h3>
</div>
</body>
</html>
');
//find the "content" div
$content = $dom->getElementById('content');
//find the first h3 tag in "content"
$origH3 = $content->getElementsByTagName('h3')->item(0);
//create a new h3
$newH3 = $dom->createElement('h3', 'new h3!');
//insert the new h3 before the original h3 of "content"
$content->insertBefore($newH3, $origH3);
echo $dom->saveHTML();

Related

PHP XPath how to wrap contents of p's in a span

I don't know if you can read JS Jquery but this is what I'd like to do server sided instead of client sided: $('p').wrapInner('<span class="contentsInP" />'); I'd like to take all existing paragraphs from a page and wrap their contents in a new span with a specific class.
Luckily all my documents are HTML5 in its XML flavour and are valid so that in PHP I can do this (simplified):
$xml=new DOMDocument();
$xml->loadXML($html);
$xpath = new DOMXPath($xml);
// How to go on in here to wrap my p's?
$output=$xml->saveXML();
How do I get PHP's DOMXPath to do my wrapping?
EDIT: Fiddled with this based on the comment but couldn't make it work
// based on http://stackoverflow.com/questions/8426391/wrap-all-images-with-a-div-using-domdocument
$xml=new DOMDocument();
$xml->loadXML(utf8_encode($temp));
$xpath = new DOMXPath($xml);
//Create new wrapper div
$new_span = $xml->createElement('span');
$new_span->setAttribute('class','contentsInP');
$ps = $xml->getElementsByTagName('p');
//Find all p
//Iterate though p
foreach ($ps AS $p) {
//Clone our created span
$new_span_clone = $new_span->cloneNode();
//Replace p with this wrapper span
$p->parentNode->replaceChild($new_span_clone,$p);
//Append the p's contents to wrapper span
// THIS IS THE PROBLEM RIGHT NOW:
$new_span_clone->appendChild($p);
}
$temp=$xml->saveXML();
The above wraps the p in a span but I need a span wrapping the p's contents while keeping the p around the span... Furthermore the above fails if the p has a class, then it won't be touched.
In attempting to adapt that other answer, the primary thing that needs to change with it is to get all child nodes of the <p> element, first remove them as children from <p> then append them as children onto the <span>. Then finally, append the <span> as a child node of the <p>.
$html = <<<HTML
<!DOCTYPE html>
<html>
<head><title>xyz</title></head>
<body>
<div>
<p><a>inner 1</a></p>
<p><a>inner 2</a><div>stuff</div><div>more stuff</div></p>
</div>
</body>
</html>
HTML;
$xml=new DOMDocument();
$xml->loadXML(utf8_encode($html));
//Create new wrapper div
$new_span = $xml->createElement('span');
$new_span->setAttribute('class','contentsInP');
$ps = $xml->getElementsByTagName('p');
//Find all p
//Iterate though p
foreach ($ps AS $p) {
//Clone our created span
$new_span_clone = $new_span->cloneNode();
// Get an array of child nodes from the <p>
// (because the foreach won't work properly over a live nodelist)
$children = array();
foreach ($p->childNodes as $child) {
$children[] = $child;
}
// Loop over that list of child nodes..
foreach ($children as $child) {
// Remove the child from the <p>
$p->removeChild($child);
// Append it to the span
$new_span_clone->appendChild($child);
}
// Lastly, append the <span> as a child to the <p>
$p->appendChild($new_span_clone);
}
$temp=$xml->saveXML();
Given the input HTML fragment, this should produce output like: (demonstration...)
<!DOCTYPE html>
<html>
<head><title>xyz</title></head>
<body>
<div>
<p><span class="contentsInP"><a>inner 1</a></span></p>
<p><span class="contentsInP"><a>inner 2</a><div>stuff</div><div>more stuff</div></span></p>
</div>
</body>
</html>

How to select Content of ALL div's with PHP

I want to select contents of every DIV tags in PHP.
Just imagine we have this HTML page :
<html>
<body>
<div class="one">Content1</div>
<span>blah..</span>
<div class="two">Content2</div>
</body>
</html>
Now , i want to have every DIV tag content, For example from that HTML code , I want to have Content1 in One variable and the Content2 in the other Variable and so on ....
Just need to access the parts easily. Just this.
Every page have random number of DIV tags, so i need a flexable Code to detect DIV tags and put the content of every one in array or any type of variable..
How to do it ?
DOMDocument
$divs = array();
$HTML = '<html>
<body>
<div class="one">Content1</div>
<span>blah..</span>
<div class="two">Content2</div>
</body>
</html>';
$doc = new DOMDocument();
$doc->loadHTML($HTML);
foreach($doc->getElementsByTagName('div') as $div) {
array_push($divs, $div->textContent);
}
var_dump($divs);
example
try to use strip_tags() function:
http://php.net/manual/en/function.strip-tags.php
You can download PHP Simple HTML DOM Parser
And access the div tags like this :
$html = file_get_html('urltopage.com');
foreach($html->find('div') as $e)
echo $e->innertext . '<br>';

Adding style tags to head with PHP DOMDocument

I want to create and add a set of <style> tags to the head tags of an HTML document.
I know I can start out like this:
$url_contents = file_get_contents('http://example.com');
$dom = new DOMDocument;
$dom->loadHTML($url_contents);
$new_elm = $dom->createElement('style', 'css goes here');
$elm_type_attr = $dom->createAttribute('type');
$elm_type_attr->value = 'text/css';
$new_elm->appendChild($elm_type_attr);
Now, I also know that I can add the new style tags to the HTML like this:
$dom->appendChild($ss_elm);
$dom->saveHTML();
However, this would create the following scenario:
<html>
<!--Lots of HTML here-->
</html><style type="text/css">css goes here</style>
The above is essentially pointless; the CSS is not parsed and just sits there.
I found this solution online (obviously didn't work):
$head = $dom->getElementsByTagName('head');
$head->appendChild($new_elm);
$dom->saveHTML();
Thanks for the help!!
EDIT:
Is it possible?
getElementsByTagName returns an array of nodes, so probably try
$head->[0]->appendChild($new_elm);
$head = $dom->getElementsByTagName('head');
Return a DOMNodeList. I think it will be better to get the first element like this
$head = $dom->getElementsByTagName('head')->item(0);
So $head will be a DOMNode object. So you can use the appendChild method.
This is the solution that worked for me
// Create new <style> tag containing given CSS
$new_elm = $dom->createElement('style', 'css goes here');
$new_elm->setAttribute('type', 'text/css');
// Inject the new <style> Tag in the document head
$head = $dom->getElementsByTagName('head')->item(0);
$head->appendChild($new_elm);
You can also add this line at the end to have a clean indentation
// Add a line break between </style> and </head> (optional)
$head->insertBefore($dom->createTextNode("\n"));

PHP -- Closing end DIV tag

I need to figure the closing tag for below code
<div class="emph"><div class="level"> Some testing </div></div>
In this i need to find the correct tag for parent DIV. my goal is to add the class name before the closing DIV like below
<div class="emph"><div class="level"> Some testing <!--level--></div><!--emph--></div>
For that i need to find the exact closing Parent DIV.
is that possible to achieve in PHP?
You can use simpleXML (or any other XML class) - for each div element, read it's class and append at the end of node content. It's not exactly finding the closing tag, but achieves your specified goal.
Sample code:
$dom = new DOMDocument;
$dom->loadXML($xml);
$divs = $dom->getElementsByTagName('div');
foreach ($divs as $div) {
if ($div->getAttribute('class')!='') {
$div->nodeValue = $div->nodeValue.'<!--'.$div->getAttribute('class').'-->';
}
}
echo $dom->saveXML();
While printing the divs in PHP keep an array $div_array = array()
As soon as you open a div do:
array_push($div_array, 'emph'); // or 'level' depending on the classname
As soon as you're ready to print the closing tag, ask for the value of the last div by:
array_pop($div_array);
// for example
echo '<!-- '.array_pop($div_array).' -->';
Popping the array also deletes the last entry of the array. Which is what you want I presume.

Zend_Dom_Query query element issue

I have an issue where I have a div that doesnt have a class or id. Is it possible to select an div element when I know its innerText ie
<div class="thishere"></div>
<div>Search on a this text</div>
If not, the div before it has a class, how do i find its next sibling?
$selector = new Zend_Dom_Query($response->getBody());
$nodes = $selector->query('????');
Using JavaScript you can loop through every element on the page like this says and find that div with the special class. Then, you'll know that the next element in the loop will be that second div and you can get its contents using element.innerHTML.
$text = <<<text
<div class="thishere"></div>
<div>Search on a this text</div>
text;
$selector = new Zend_Dom_Query ($text);
$nodes = $selector->queryXpath('//div[contains(text(),"Search on a this text")]');
foreach ($nodes as $node)
{
...
}

Categories