<?php
if ( ! class_exists('PMXI_Render')){
class PMXI_Render{
public function __construct(){
}
public static function xml_find_repeating(DOMElement $el, $path = '/')
{
$path .= $el->nodeName;
if ( ! $el->parentNode instanceof DOMDocument) {
$path .= '[1]';
}
$children = array();
foreach ($el->childNodes as $child) {
if ($child instanceof DOMElement) {
if ( ! empty($children[$child->nodeName])) {
return $path . '/' . $child->nodeName;
} else {
$children[$child->nodeName] = true;
}
}
}
// reaching this point means we didn't find anything among current element children, so recursively ask children to find something in them
foreach ($el->childNodes as $child) {
if ($child instanceof DOMElement) {
$result = slef::xml_find_repeating($child, $path . '/');
if ($result) {
return $result;
}
}
}
// reaching this point means we didn't find anything, so return element itself if the function was called for it
if ('/' . $el->nodeName == $path) {
return $path;
}
return NULL;
}
public static function render_csv_element(DOMElement $el, $shorten = false, $path = '/', $ind = 1, $lvl = 0)
{
$path .= $el->nodeName;
if ( ! $el->parentNode instanceof DOMDocument and $ind > 0) {
$path .= "[$ind]";
}
echo '<div class="xml-element csv_element lvl-' . esc_attr($lvl) . ' lvl-mod4-' . ($lvl % 4) . '" title="' . esc_attr($path) . '">';
if ($el->hasChildNodes()) {
$is_render_collapsed = $ind > 1;
if ($lvl) echo '<div class="csv-tag opening"><span class="csv-tag-name">' . esc_html($el->nodeName) . '</span>'; echo '</div>';
if (1 == $el->childNodes->length and $el->childNodes->item(0) instanceof DOMText) {
$child = $el->childNodes->item(0);
if (!empty($child->wholeText)){
self::render_csv_text(trim($child->wholeText), $shorten, $is_render_collapsed);
}
elseif (is_callable(array($child, 'nodeValue'), true) && isset($child->nodeValue)){
self::render_csv_text(trim($child->nodeValue), $shorten, $is_render_collapsed);
}
} else {
echo '<div class="csv-content' . ($is_render_collapsed ? ' collapsed' : '') . '">';
$indexes = array();
foreach ($el->childNodes as $child) {
if ($child instanceof DOMElement) {
empty($indexes[$child->nodeName]) and $indexes[$child->nodeName] = 0; $indexes[$child->nodeName]++;
self::render_csv_element($child, $shorten, $path . '/', $indexes[$child->nodeName], $lvl + 1);
} elseif ($child instanceof DOMText) {
self::render_csv_text(trim($child->wholeText), $shorten);
} elseif ($child instanceof DOMComment) {
if (preg_match('%\[pmxi_more:(\d+)\]%', $child->nodeValue, $mtch)) {
$no = intval($mtch[1]);
echo '<div class="xml-more">[ ⇓ ' . sprintf(__('<strong>%s</strong> %s more', 'wp_all_import_plugin'), $no, _n('element', 'elements', $no, 'wp_all_import_plugin')) . ' ⇓ ]</div>';
}
}
}
echo '</div>';
}
//echo '<div class="xml-tag closing"><span class="xml-tag-name">' . $el->nodeName . '</span></div>';
} else {
echo '<div class="xml-tag opening empty"><span class="xml-tag-name">' . wp_kses_post($el->nodeName) . '</span>'; self::render_xml_attributes($el); echo '</div>';
}
echo '</div>';
}
protected static function render_csv_text($text, $shorten = false, $is_render_collapsed = false)
{
if (empty($text) and 0 !== (int)$text) {
return; // do not display empty text nodes
}
if (preg_match('%\[more:(\d+)\]%', $text, $mtch)) {
$no = intval($mtch[1]);
echo '<div class="xml-more">[ ⇓ ' . sprintf(__('<strong>%s</strong> %s more', 'wp_all_import_plugin'), $no, _n('element', 'elements', $no, 'wp_all_import_plugin')) . ' ⇓ ]</div>';
return;
}
$more = '';
if ($shorten and preg_match('%^(.*?\s+){20}(?=\S)%', $text, $mtch)) {
$text = $mtch[0];
$more = '<span class="xml-more">[' . __('more', 'wp_all_import_plugin') . ']</span>';
}
$is_short = strlen($text) <= 40;
$newtext = htmlspecialchars($text);
//$newtext = preg_replace('%(?<!\s)\b(?!\s|\W[\w\s])|\w{20}%', '$0​', $newtext); // put explicit breaks for xml content to wrap
echo '<div class="xml-content textonly' . ($is_short ? ' short' : '') . ($is_render_collapsed ? ' collapsed' : '') . ' '. (is_numeric($text) ? 'is_numeric' : '') .'">' . wp_kses_post($newtext . $more) . '</div>';
}
public static $option_paths = array();
public static function render_xml_elements_for_filtring(DOMElement $el, $originPath ='', $lvl = 0){
$path = $originPath;
if ("" != $path){
if ($lvl > 1) $path .= "->" . $el->nodeName; else $path = $el->nodeName;
if (empty(self::$option_paths[$path]))
self::$option_paths[$path] = 1;
else
self::$option_paths[$path]++;
echo '<option value="'. esc_attr($path) .'['. esc_attr(self::$option_paths[$path]) .']">' . esc_html($path) . '['. esc_html(self::$option_paths[$path]) .']</option>';
}
else $path = $el->nodeName;
foreach ($el->attributes as $attr) {
if (empty($originPath)){
echo '<option value="@' . esc_attr($attr->nodeName).'">@' . esc_html($attr->nodeName) . '</option>';
}
else{
echo '<option value="'. esc_attr($path) .'['. esc_attr(self::$option_paths[$path]) .']'. '/@' . esc_attr($attr->nodeName).'">'. esc_html($path) .'['. esc_html(self::$option_paths[$path]) .']'. '@' . esc_html($attr->nodeName) . '</option>';
}
}
if ($el->hasChildNodes()) {
foreach ($el->childNodes as $child) {
if ($child instanceof DOMElement)
self::render_xml_elements_for_filtring($child, $path, $lvl + 1);
}
}
}
public static function render_xml_element(DOMElement $el, $shorten = false, $path = '/', $ind = 1, $lvl = 0)
{
$render_whole_tree = apply_filters('wp_all_import_is_render_whole_xml_tree', true);
$path .= $el->nodeName;
$alternativePath = $path;
if ( ! $el->parentNode instanceof DOMDocument and $ind > 0) {
$path .= "[$ind]";
}
echo '<div class="xml-element lvl-' . esc_attr($lvl) . ' lvl-mod4-' . esc_attr($lvl % 4) . '" title="' . esc_attr($path) . '">';
//if ($el->hasAttributes()){
echo '<div class="xml-element-xpaths">'; self::render_element_xpaths($el, $alternativePath, $ind, $lvl); echo '</div>';
//}
if ($el->hasChildNodes()) {
$is_render_collapsed = $ind > 1;
if ($el->childNodes->length > 1 or ! $el->childNodes->item(0) instanceof DOMText or strlen(trim($el->childNodes->item(0)->wholeText)) > 40) {
echo '<div class="xml-expander">' . ($is_render_collapsed ? '+' : '-') . '</div>';
}
echo '<div class="xml-tag opening"><<span class="xml-tag-name">' . esc_html($el->nodeName) . '</span>'; self::render_xml_attributes($el, $path . '/'); echo '></div>';
if (1 == $el->childNodes->length and $el->childNodes->item(0) instanceof DOMText) {
$item = $el->childNodes->item(0);
if (!empty($item->wholeText)){
self::render_xml_text(trim($item->wholeText), $shorten, $is_render_collapsed);
}
else{
self::render_xml_text(trim($item->nodeValue), $shorten, $is_render_collapsed);
}
} else {
echo '<div class="xml-content' . ($is_render_collapsed ? ' collapsed' : '') . '">';
$indexes = array();
foreach ($el->childNodes as $eli => $child) {
if ($child instanceof DOMElement) {
empty($indexes[$child->nodeName]) and $indexes[$child->nodeName] = 0; $indexes[$child->nodeName]++;
if ( $render_whole_tree || $indexes[$child->nodeName] === 1){
self::render_xml_element($child, $shorten, $path . '/', $indexes[$child->nodeName], $lvl + 1);
}
} elseif ($child instanceof DOMCdataSection) {
self::render_xml_text(trim($child->wholeText), $shorten, false, true);
} elseif ($child instanceof DOMText) {
if ( $el->childNodes->item($eli - 1) and ($el->childNodes->item($eli - 1) instanceof DOMCdataSection) ){
}
elseif( $el->childNodes->item($eli + 1) and ($el->childNodes->item($eli + 1) instanceof DOMCdataSection) ){
}
else{
self::render_xml_text(trim($child->wholeText), $shorten);
}
} elseif ($child instanceof DOMComment) {
if (preg_match('%\[pmxi_more:(\d+)\]%', $child->nodeValue, $mtch)) {
$no = intval($mtch[1]);
echo '<div class="xml-more">[ ⇓ ' . sprintf(__('<strong>%s</strong> %s more', 'wp_all_import_plugin'), $no, _n('element', 'elements', $no, 'wp_all_import_plugin')) . ' ⇓ ]</div>';
}
}
}
echo '</div>';
}
echo '<div class="xml-tag closing"></<span class="xml-tag-name">' . esc_html($el->nodeName) . '</span>></div>';
} else {
echo '<div class="xml-tag opening empty"><<span class="xml-tag-name">' . esc_html($el->nodeName) . '</span>'; self::render_xml_attributes($el); echo '/></div>';
}
echo '</div>';
}
protected static function render_xml_text($text, $shorten = false, $is_render_collapsed = false, $is_cdata = false)
{
if (empty($text) and 0 !== (int)$text) {
return; // do not display empty text nodes
}
if (preg_match('%\[more:(\d+)\]%', $text, $mtch)) {
$no = intval($mtch[1]);
echo '<div class="xml-more">[ ⇓ ' . sprintf(__('<strong>%s</strong> %s more', 'wp_all_import_plugin'), $no, _n('element', 'elements', $no, 'wp_all_import_plugin')) . ' ⇓ ]</div>';
return;
}
$more = '';
if ($shorten and preg_match('%^(.*?\s+){20}(?=\S)%', $text, $mtch)) {
$text = $mtch[0];
$more = '<span class="xml-more">[' . __('more', 'wp_all_import_plugin') . ']</span>';
}
$is_short = strlen($text) <= 40;
$text = htmlspecialchars($text);
if ($is_cdata){
$text = "<span class='wpallimport-cdata'>" . htmlspecialchars("<![CDATA[") . "</span> " . $text . " <span class='wpallimport-cdata'>" . htmlspecialchars("]]>") . "</span>";
}
//$text = preg_replace('%(?<!\s)\b(?!\s|\W[\w\s])|\w{20}%', '$0​', $text); // put explicit breaks for xml content to wrap
echo '<div class="xml-content textonly' . ($is_short ? ' short' : '') . ($is_render_collapsed ? ' collapsed' : '') . '">' . esc_html($text . $more) . '</div>';
}
public static function get_xml_path(DOMElement $el, DOMXPath $xpath)
{
for($p = '', $doc = $el; $doc and ! $doc instanceof DOMDocument; $doc = $doc->parentNode) {
if (($ind = $xpath->query('preceding-sibling::' . $doc->nodeName, $doc)->length)) {
$p = '[' . ++$ind . ']' . $p;
} elseif ( ! $doc->parentNode instanceof DOMDocument) {
$p = '[' . ($ind = 1) . ']' . $p;
}
$p = '/' . $doc->nodeName . $p;
}
return $p;
}
protected static function render_xml_attributes(DOMElement $el, $path = '/')
{
foreach ($el->attributes as $attr) {
echo ' <span class="xml-attr" title="' . esc_attr($path) . '@' . esc_attr($attr->nodeName) . '"><span class="xml-attr-name">' . esc_html($attr->nodeName) . '</span>=<span class="xml-attr-value">"' . esc_attr($attr->value) . '"</span></span>';
}
}
protected static function render_element_xpaths(DOMElement $el, $path = '/', $ind = 1, $lvl = 0){
?>
<ul id="menu-<?php echo str_replace('/', '-', esc_attr($path)); ?>" class="ui-helper-hidden">
<?php foreach ($el->attributes as $attr) : if ( empty($attr->value) ) continue; ?>
<li data-command="action1" title="<?php echo esc_attr($path . '[@'. $attr->nodeName .' = "' . $attr->value . '"]'); ?>">
<a href="#"><?php echo wp_kses_post($path . '[@'. $attr->nodeName .' = "' . $attr->value) . '"]'; ?></a>
</li>
<li data-command="action2" title="<?php echo esc_attr($path . '[@'. $attr->nodeName .'[contains(.,"' . $attr->value . '")]]'); ?>">
<a href="#"><?php echo wp_kses_post($path . '[@'. $attr->nodeName .'[contains(.,"' . $attr->value) . '")]]'; ?></a>
</li>
<?php endforeach; ?>
<?php
$altNode = null;
$altNodeText = null;
$parentNode = $el->parentNode;
$grandNode = $parentNode->parentNode;
if ( ! $grandNode instanceof DOMDocument and $grandNode instanceof DOMElement ){
$equalsElements = 0;
foreach ($grandNode->childNodes as $child) {
if ($child instanceof DOMElement) {
if ($child->nodeName == $parentNode->nodeName){
$equalsElements++;
if ($equalsElements > 1)
break;
}
}
}
if ($equalsElements > 1){
if ($parentNode->hasChildNodes()) {
foreach ($parentNode->childNodes as $i => $child) {
if ($child instanceof DOMElement) {
if ($child->nodeName != $el->nodeName){
$altNode = $child;
if ($child->hasChildNodes()){
foreach ($child->childNodes as $i => $txtChild) {
if ($txtChild instanceof DOMText) {
$altNodeText = $txtChild;
break;
}
}
}
break;
}
}
}
}
if ( ! empty($altNode) and !empty($altNodeText) ){
$pathArgs = explode('/', $path);
array_pop($pathArgs);
array_pop($pathArgs);
$vpath = esc_attr(implode('/', $pathArgs) . '/' . $parentNode->nodeName . '[contains('. $altNode->nodeName .',"' . esc_attr($altNodeText->wholeText) . '")]/' . $el->nodeName);
?>
<li data-command="action3" title="<?php echo esc_attr($vpath); ?>">
<a href="#"><?php echo esc_html($vpath); ?></a>
</li>
<?php
}
}
}
?>
</ul>
<?php
}
}
}