Load html content from ajax response - php

I am creating an application in opencart in which the controller returns output in json form. If i do $('.my-div').html(json['output']) then its working fine. But how can i filter particular div or table from that response and put only that filtered html in my div. I know about $('.my-div').load('index.php?route=mymodule/subpage' .my-div > * ); But it doesn't work as my controller is created to return output not to generate.
What my controller returns is
$json['output'] = $this->load->view('default/template/mymodule/mytemplate.tpl', $data);
Edit
What i am getting in response is
json['output'] = '<div>......</div><table class="myclass"></table>';
I want to load only myclass in my div. So how can i filter only myclass table from response.? I've tried filter but its giving me error.

Like Raghubendra said, it's better to only keep the html you need in the .tpl file, but if you can't do that for whatever reason, you can try to filter it on the server side using xPath [it's not the fastest way, but it's a clean way to get the result]. Here is how I think you can do it:
$output = $this->load->view('default/template/mymodule/mytemplate.tpl', $data);
$dom = new DOMDocument();
#$dom->loadHTML($output); // # is to suppress all warnings related to the fact that html is not a proper dom document
$xpath = new DOMXPath($dom);
$match = $xpath->query('//table[#class="myclass"]');
/* $match is not an array, it implements 'Traversable', you can't access your <table> node using $match[0],
you need a foreach that will only loop once if you have one <table class="myclass"> element */
foreach($match as $table) {
$json['output'] = $table->ownerDocument->saveHTML($table); // saveHTML allows you to get the output in an HTML string
}
N.B: Please note that you need to change this code in case you have multiple <table class="myclass">, I would recommend using iterator_to_array($match); to transform the node list to an array so you can access it using $match[0]... and avoid the foreach.

If you want only a part of the html in your div then why are you rendering the whole tpl file. Why don't you remove the html code that you don't want to use.
Suppose if your mytemplate.tpl has
<div>
---------
--------
</div>
<table class="myclass"></table>
<div>
---------
--------
</div>
Then why don't you only keep the table code are remove all the other code as you are not using it while rendering the tpl file.

Related

How can you hide html element with php?

if you do in php:
$dom = new DOMDocument();
$dom->loadHTML($pageUrl);
$dom->getElementById(eleId);
How can you hide the element. I know how you can do it with css and js. But I want to know it with php.
I’m going to assume that you’re trying to have the element initially hidden i.e. in existence, but not visible, upon the browser’s initial rendering and you already know that PHP can’t directly instruct the browser to hide elements.
Following your example, you could do:
$eleId = “div_to_hide”;
$dom = new DOMDocument();
$dom->loadHTML($pageUrl);
$target_elem = $dom->getElementById($eleId);
if ($target_elem) {
$target_elem-> setAttribute('style','display: none;');
}
Or you could create a “script” element containing JavaScript code to execute after the resource has totally downloaded to hide it at run-time.
Or you could create a “style” element in your DOMDocument object in which you’d put CSS content referencing the target element (by selector) to apply initial “display: none;” CSS.
Just other ideas, but the snippet above follows your paradigm.

php dom replacedChild, save as html and continue parsing

I created a php parser for editing the html which is created by a CMS. The first thing I do is parse a custom tag for adding modules.
After that things like links, images etc. are if needed updated, changed or w/e. This all works.
Now I noticed that when a custom tag is replaced with the html the module generated this html is NOT processed by the rest of the actions.
For example; all links with a href of /pagelink-001 are replaced with the actual link of the current page. This works for the initial loaded html, not the replaced tag. Below I have a short version of the code. I tried saving it with saveHtml() and load it with loadHtml() and things like that.
I'm guessing this is because $doc with the loaded html is not updated as such.
My code:
$html = 'Link1<customtag></customtag>';
// Load the html (all other settings are not shown to keep it simple. Can be added if this is important)
$doc->loadHTML($html);
// Replace custom tag
foreach($xpath->query('//customtag') as $module)
{
// Create fragment
$return = $doc->createDocumentFragment();
// Check the kind of module
switch($module)
{
case 'news':
$html = $this->ZendActionHelperThatReturnsHtml;
// <div class="news">Link2</div>
break;
}
// Fill fragment
$return->appendXML($html);
// Replace tag with html
$module->parentNode->replaceChild($return, $module);
}
foreach($doc->getElementsByTagName('a') as $link)
{
// Replace the the /pagelink with a correct link
}
In this example Link1 href is replaced with the correct value, however Link2 is not. Link2 does correctly appear as a link and all that works fine.
Any directions of how I can update the $doc with the new html or if that is indeed the problem would be awesome. Or please tell me if I'm completely wrong (and where to look)!
Thanks in advance!!
It seemed that I was right and the returned string was a string and not html. I discovered in my code the innerHtml function from #Keyvan that I implemented at some point. This resulted in my function being this:
// Start with the modules, so all that content can be fixed as well
foreach($xpath->query('//customtag') as $module)
{
// Create fragment
$fragment = $doc->createDocumentFragment();
// Check the kind of module
switch($module)
{
case 'news':
$html = htmlspecialchars_decode($this->ZendActionHelperThatReturnsHtml); // Note htmlspecialchars_decode!
break;
}
// Set contents as innerHtml instead of string
$module->innerHTML = $html;
// Append child
$fragment->appendChild($module->childNodes->item(0));
// Replace tag with html
$module->parentNode->replaceChild($fragment, $module);
}

php extract body tag content

I'm trying what should be very easy, but I can't get it to work. Which makes me wonder if I'm using the right workflow.
I have a simple html page which I load in my desktop application as a help file. This page has no menu just the content.
On my website I want to have a more sophisticated help system. So I want to use a php file which will show a menu, breadcrums and a header and footer.
To not duplicate my help content I want to load the original HTML help file and add its body content to my enhanced help page.
I'm using this code to extract the title:
function getURLContent($filename){
$url = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR . $filename;
$doc = new DOMDocument;
$doc->preserveWhiteSpace = FALSE;
#$doc->loadHTMLFile($url);
return $doc;
}
function getSingleElementValue($element){
if (!is_null($element)) {
$node = $element->childNodes->item(0);
return $node->nodeValue;
}
}
$doc = getURLContent("test.html");
$title = getSingleElementValue($doc->getElementsByTagName('title')->item(0));
echo $title;
The title is correctly extracted.
Now I try to extract the body:
function getBodyContent($element){
$mock = new DOMDocument;
foreach ($element->childNodes as $child){
$mock->appendChild($mock->importNode($child, true));
}
return $mock->saveHTML();
}
$body = getBodyContent($doc->getElementsByTagName('body')->item(0));
echo $body;
The getBodyContent() function is one of the several options I tried.
All of them return the whole HTML tag, including the HEAD tag.
My question is: Is this a correct workflow or should I use something else?
Thanks.
Update: My final goal is to have a website with multiple pages that has the help files accessible via a menu. These pages will be generated using something like generate.php?page=test.html. I'm not yet at this part. The goal is also to not duplicate the content of test.html because this file will be used in my desktop application (using a web control). In my desktop application I don't need the menu and such.
Update #2: I had to add <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> to the html-file I want to read and now I do get the body content. Unfortunaly all tags are strips. I'll need to fixed that as well.
The problem is that saveHTML() will return an actual document. You don't want this. Instead, you want just what you put in.
Thankfully, you can do this much more easily.
function getBodyContent(DOMNode $element) {
$doc = $element->ownerDocument;
$wrapper = $doc->createElement('div');
foreach( $element->childNodes as $child) {
$wrapper->appendChild($child);
}
$element->appendChild($wrapper);
$html = $doc->saveHTML($wrapper);
return substr($html, strlen("<div>"), -strlen("</div>"));
}
This wraps the contents into a single element of known tag representation (the body may have attributes that make it unknown), gets the rendered HTML from that element, and strips off the known tag of the wrapper.
I'd also like to suggest an improvement to getSingleElementValue:
function getSingleElementValue(DOMNode $element) {
return trim($element->textContent);
}
Note also the use of type hints to ensure that your functions are indeed getting the kind of thing that is expected - this is useful as it means we no longer need to check "does $element->ownerDocument exist? does $element->ownerDocument->saveHTML() do what we think it does?" and other such questions. It ensures we have a DOMNode, so we know it has those things.

manipulate html navigation with php dom

I need to add classes to the navigation HTML being output from a function in a custom CMS.
The only way I can get the output I need is to parse the HTML with PHP.
I am using PHP's DOM methods to look through the HTML and add a class to any <li> element that contains a child <ul> (top level navigation items).
So far it's working, but I have 2 questions:
Is there a more efficient way for me to go through this DOM data? It seems cumbersome to me, but that could just be my lack of experience.
In some cases, my <li> elements may already have a class, how can I add to the existing class attribute without destroying what may or may not already be there?
-
<?
$mcms_nav = getContent(
// call to cms that returns navigation html as a string
// ex. <ul id="pnav"><li>home</li>....</ul>
);
$dom = new DOMDocument();
$dom->preserveWhiteSpace = FALSE;
$dom->loadHTML($mcms_nav);
$x = new DOMXPath($dom);
foreach($x->query('//ul/li/ul') as $node)
{
$parent = $node->parentNode;
$parent_attr = $dom->createAttribute('class');
$parent_attr->value = 'has-flyout';
$parent->appendChild($parent_attr);
$flyout_attr = $dom->createAttribute('class');
$flyout_attr->value = 'flyout';
$node->appendChild($flyout_attr);
}
$mcms_nav = $dom->getElementByID('pnav');
echo $dom->saveHTML($mcms_nav);
?>
Not really. You could take the XML class from the CakePHP framework, turn this into an array, manipulate the array, and turn it back. Not sure if that's an option in your case. http://book.cakephp.org/2.0/en/core-utility-libraries/xml.html
You can use dom->hasAttribute() and dom->getAttribute() to get the existing attribute contents if they exist.
Also, a new job wouldn't hurt ;)

PHP search content for ID and add Class

I need a simple function that will search my wordpress content for a specific ID, and than add a class to the same element the ID is in.
Its for a video player plugin that displays itself via shortcode. My problem is the plugin gives each element an ID as follows, id="video-1-player", id="video-2-player". So the function needs to search the content for id="video-(any number)-player" and than insert a class in there.
thanks!
EDIT
heres the answer that worked for me.
https://stackoverflow.com/a/6180884/278629
Use the DOMDocument class to represent your document as an object. Query for the ID you're seeking, and add a class onto it. From there you can spit the HTML back out.
Simple example:
// HTML to be handled (could very well be read in)
$html = "<!DOCTYPE html><html><body><p id='foo'>Foo</p></body></html>";
// Create and load our DOMDocument object
$doc = new DOMDocument();
$doc->loadHTML($html);
// Find and manipulate our paragraph
$foo = $doc->getElementById("foo");
$foo->setAttribute("class", "bar");
// Return the entire document HTML
echo $doc->saveHTML();
Alternatively, if you only wanted the HTML for the affected element:
echo $doc->saveHTML($foo);
The generated HTML follows:
<!DOCTYPE html>
<html>
<body>
<p id="foo" class="bar">Foo</p>
</body>
</html>
Note that the above code doesn't first check to see if the class attribute is already present on the element. You should perform that check so as to not lose any pre-existing classes that might already be on the element.

Categories