| Current Path : /home/juvelize/saulnois/tmp/install_695d2cf0b4957/src/ |
| Current File : /home/juvelize/saulnois/tmp/install_695d2cf0b4957/src/TDom.php |
<?php
/*
* @package Tech Fry Library
* @license https://www.gnu.org/licenses/gpl-3.0.en.html
*/
namespace TechFry\Library;
defined('_JEXEC') or die;
// Class for handling HTML and XML
class TDom extends THelper
{
public $dom;
public $code;
public function __construct($code = '', $source_type = 'html')
{
$this->dom = new \DOMDocument;
$this->code = $code;
if ($code)
{
if ($source_type == 'html')
{
$code = htmlspecialchars_decode(htmlentities($code));
// LIBXML_HTML_NOIMPLIED - turns off the automatic adding of implied html/body elements
// LIBXML_HTML_NODEFDTD - prevents a default doctype being added
// The @ suppresses warnings and errors
$dom->preserveWhiteSpace = false;
@$dom->loadHTML($code, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
}
else
{
$this->dom->loadXML($code);
}
}
}
public static function get_dom($code, $source_type = 'html')
{
$dom = new \DOMDocument;
if ($source_type == 'html')
{
// $code = mb_convert_encoding($code, 'HTML-ENTITIES', 'UTF-8'); // Depreciated
$code = htmlspecialchars_decode(htmlentities($code));
// LIBXML_HTML_NOIMPLIED - turns off the automatic adding of implied html/body elements
// LIBXML_HTML_NODEFDTD - prevents a default doctype being added
$dom->preserveWhiteSpace = false;
@$dom->loadHTML($code, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
}
elseif ($source_type == 'xml')
{
$dom->loadXML($code);
}
return $dom;
}
// 02. Get array of HTML elements
public function get_html($config = [])
{
$tag = $config['tag'];
$attr_name = $config['attr_name'] ?? '';
$attr_value = $config['attr_value'] ?? '';
$content = $config['content'] ?? '';
$relation = $config['relation'] ?? '';
$xpath = new \DOMXpath($this->dom);
$q = $this->get_xpath_query($tag, [$attr_name, $attr_value], $content);
$elements = $xpath->query($q); // DOMNodeList
if ($elements->length == 0)
{
return false;
}
foreach ($elements as $node)
{
// $node - DOMElement or DOMNode
if (!$relation)
{
$html_arr[] = $dom->saveHTML($node);
}
else
{
$html_arr[] = $dom->saveHTML($node->$relation);
}
}
return $html_arr;
}
// 03. Get array of element content
public function get_content($config = [])
{
$tag = $config['tag'];
$attr_name = $config['attr_name'] ?? '';
$attr_value = $config['attr_value'] ?? '';
$content = $config['content'] ?? '';
$relation = $config['relation'] ?? '';
$xpath = new \DOMXpath($this->dom);
$q = $this->get_xpath_query($tag, [$attr_name, $attr_value], $content);
$elements = $xpath->query($q);
if ($elements->length == 0)
{
return false;
}
foreach ($elements as $node)
{
if (!$relation)
{
$values[] = $node->textContent;
}
else
{
$values[] = $node->$relation->textContent;
}
}
return $values;
}
// 04. Get array of attribute values
public function get_attr($config = [])
{
$tag = $config['tag'];
$attr_name = $config['attr_name'] ?? '';
$attr_value = $config['attr_value'] ?? '';
$content = $config['content'] ?? '';
$relation = $config['relation'] ?? '';
$target = $config['target_attr'];
$xpath = new \DOMXpath($this->dom);
$q = $this->get_xpath_query($tag, [$attr_name, $attr_value], $content);
$elements = $xpath->query($q);
if ($elements->length == 0)
{
return false;
}
foreach ($elements as $node)
{
if (!$relation)
{
$attr_values[] = $node->getAttribute($target);
}
else
{
$attr_values[] = $node->$relation->getAttribute($target);
}
}
return $attr_values;
}
// 05. Add attribute value
public function add_attr($config = [])
{
$tag = $config['tag'];
$attr_name = $config['attr_name'] ?? '';
$attr_value = $config['attr_value'] ?? '';
$elements = $this->dom->getElementsByTagName($tag);
if (\is_array($attr_value))
{
foreach ($elements as $k => $node)
{
$node->setAttribute($attr_name, $attr_value[$k]);
}
}
else
{
foreach ($elements as $node)
{
$node->setAttribute($attr_name, $attr_value);
}
}
return $dom->saveHTML();
}
// 06. Remove all attributes from HTML except some
public function rem_attr($noremove = [])
{
$xpath = new \DOMXPath($this->dom);
$elements = $xpath->query('//@*');
foreach ($elements as $node)
{
if (!in_array($node->nodeName, $noremove))
{
$node->parentNode->removeAttribute($node->nodeName);
}
}
return $dom->saveHTML();
}
// 07. Remove complete element from html code
public function rem_element($config = [])
{
$tag = $config['tag'];
$attr_name = $config['attr_name'] ?? '';
$attr_value = $config['attr_value'] ?? '';
$content = $config['content'] ?? '';
$xpath = new \DOMXpath($this->dom);
$q = $this->get_xpath_query($tag, [$attr_name, $attr_value], $content);
$elements = $xpath->query($q);
if ($elements->length == 0)
{
return $html;
}
foreach ($elements as $node)
{
$node->remove();
}
return $this->dom->saveHTML();
}
// 08. Scan - Return array of all tag names in html or xml
public function get_all_tags()
{
$xpath = new \DOMXpath($this->dom);
$elements = $xpath->query('//*');
$tag_names[] = [];
foreach ($elements as $k => $node)
{
// $node->nodeType; // 1 for DOMElement, 2 for DOMAttr, 3 for DOMText
// $node->parentNode, $node->parentElement
// $node->childNodes,
$tag_names[$k]['tag_name'] = $node->tagName;
$tag_names[$k]['id'] = $node->getAttribute('id') ?? '';
$tag_names[$k]['class'] = $node->getAttribute('class') ?? '';
$tag_names[$k]['total_children'] = $node->childElementCount;
}
return $tag_names;
}
// 09. Scan for specific html or xml tag
public function tag_scan($config = [])
{
$tag = $config['tag'];
$attr_name = $config['attr_name'] ?? '';
$attr_value = $config['attr_value'] ?? '';
$content = $config['content'] ?? '';
$xpath = new \DOMXpath($this->dom);
$q = $this->get_xpath_query($tag, [$attr_name, $attr_value], $content);
$elements = $xpath->query($q);
$info[] = [];
foreach ($elements as $i => $node)
{
if ($node->attributes->length)
{
$info[$i]['attributes'] = $node->attributes->length;
for ($num = 0; $num < $node->attributes->length; $num++)
{
$info[$i]['attr_names'] .= '<small>';
$info[$i]['attr_names'] .= $node->attributes->item($num)->nodeName . '=' . $node->attributes->item($num)->nodeValue . '<br>';
$info[$i]['attr_names'] .= '</small>';
}
}
else
{
$info[$i]['attributes'] = 0;
$info[$i]['attr_names'] = '';
}
$info[$i]['parent'] = $node->parentNode->tagName;
$info[$i]['node_value'] = '<small>' . substr($node->nodeValue, 0, 200) . '</small>';
}
return $info;
}
// 10. Scan for specific attribute
public function attr_scan()
{
$attr_name = $config['attr_name'] ?? '';
$attr_value = $config['attr_value'] ?? '';
$xpath = new \DOMXpath($this->dom);
$q = '//' . $tag;
if ($attr_name)
{
$q .= '//@' . $attr_name;
if ($attr_value)
{
$q .= '="' . $attr_value . '"';
}
$q .= ']';
}
$elements = $xpath->query($q);
$info[] = [];
foreach ($elements as $i => $node)
{
$info[$i]['tag'] = $node->ownerElement->tagName;
$info[$i]['value'] = $node->nodeValue;
$info[$i]['node_path'] = $node->getNodePath();
}
return $info;
}
// 11. Get array of attribute values as associative array
public function get_smart_attr($code, $tag, $value_attr, $key_attr = '', $source_type = 'html')
{
$tag = $config['tag'];
$xpath = new \DOMXpath($this->dom);
$q = '//' . $tag;
$elements = $xpath->query($q);
if ($elements->length == 0)
{
return false;
}
foreach ($elements as $node)
{
$key_name = $node->getAttribute($key_attr);
if ($key_name)
{
$key_name = preg_replace('/[^A-Za-z_]/', '_', $key_name);
$attr_values[$key_name] = $node->getAttribute($value_attr);
}
}
return $attr_values;
}
public function get_xpath_query($tag, $attribute = [], $content = '')
{
// Refer: https://www.php.net/manual/en/domxpath.query.php
// root, tags (nodes), attributes, values, combination of tags attributes & values
/*
/node Root of the document
//node Anywhere in the document
* wildcard can be used instead of node name
[@attribute="value"]
[n] select n-th node (starts at 1)
. Current node
.. Parent of current node
preceding:: selects all preceding nodes (above)
following:: selects all following nodes (below)
preceding-sibling:: selects preceding siblings (above)
following-sibling:: selects following siblings (below)
a[contains(text(), "social")]
//a[starts-with(text(), "social")]
//a[ends-with(text(), "Twitter")]
//p[string-length(text())>10]
@attribute selects attribute by name (DOMAttr)
text() (DOMText)
*/
// All nodes of tag
$q = '//' . $tag;
// Filter by attribute
if (isset($attribute[0]) && $attribute[0])
{
$attr .= $attribute[0];
if (isset($attribute[1]) && $attribute[1] != '')
{
$first_char = substr($attribute[1], 0, 1);
switch ($firstChar)
{
case '^':
$val = substr($value, 1);
$q .= = "starts-with(@$attr, '$val')";
break;
case '~':
$val = substr($value, 1);
$q .= = "contains(@$attr, '$val')";
break;
case '$':
$val = substr($value, 1);
$q .= = "substring(@$attr, string-length(@$attr) - " . (strlen($val) - 1) . ") = '$val'";
break;
default:
$q .= = "@$attr='$value'";
break;
}
}
else
{
$q .= '[@' . $attribute[0];
}
$q .= ']';
}
// Filter by content value
if ($content != '')
{
$first_char = substr($content, 0, 1);
switch ($firstChar)
{
case '^':
$val = substr($content, 1);
$q .= = "starts-with(text(), '$val')";
break;
case '~':
$val = substr($content, 1);
$q .= "contains(text(), '$val')";
break;
case '$':
$val = substr($content, 1);
$q .= = "substring(text(), string-length(text()) - " . (strlen($val) - 1) . ") = '$val'";
break;
default:
$q .= "text()='$content'";
break;
}
}
return $q;
}
}