How to replace custom tag with span containing textual representation of tag - javascript

I'm trying make a visual representation of xml code in HTML.
A simple case is this:
Original source:
<g id="1">some content</g> other content <s/>
Desired output:
<span data-id="1"><g id="1"></span>some content<span data-closingof="1"></g></span> other content <span><s/></span>
I tried much with regex having great results, but in case of nested elements it fails.
Is there any other way? (for example some XML parser that will allow such transformations)
Thank you.

Unusual for me to suggest regex for XML processing, but this may be more appropriate.
$input = '<g id="1">some content</g> other content <s/>';
echo preg_replace_callback("/(<.*?>)/", function($tag) {
return "<span>".htmlentities($tag[1])."</span>";
},
$input);
This will look for any content in < and > and encode it - whilst enclosing it in <span> tags.
Outputs...
<span><g id="1"></span>some content<span></g></span> other content <span><s/></span>
As this is only a limited example, this may not fit all sizes, but may be worth a go.
Update:
With the update for adding the data-id I've updated the code, it keeps a stack of the levels of tags and adds in when a matching close tag is found (although it doesn't check the type of tag), it will ignore and self closed tags as these don't have any other content.
$input = '<g id="1">some <g>2</g>content</g> other content <s/>';
$tagID = [];
echo preg_replace_callback("/(<.*?>)/", function($tag) use (&$tagID) {
if ( substr($tag[1], -2) == "/>" ) {
$out = "<span>".htmlentities($tag[1])."</span>";
}
else {
$add = "";
if ( substr($tag[1],0,2) == "</" ) {
$id = array_pop($tagID);
if ( !empty($id) ) {
$add = ' data-closingof="'.$id.'"';
}
}
else {
if (preg_match('/id="(.*?)"/', $tag[1], $match)) {
$id = $match[1];
$add = ' data-id="'.$id.'"';
}
else {
$id = "";
}
array_push($tagID, $id);
}
$out = "<span{$add}>".htmlentities($tag[1])."</span>";
}
return $out;
},
$input);

I ended up with something like this.
class TagsConverter {
private $parser;
private $nestedIDs = [];
private $output = '';
function __construct() {
$this->parser = xml_parser_create();
xml_set_object($this->parser, $this);
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false);
xml_set_element_handler($this->parser, "tagOpen", "tagClose");
xml_set_character_data_handler($this->parser, "tagData");
}
function __destruct() {
xml_parser_free($this->parser);
unset($this->parser);
}
function reset() {
$this->output = '';
$this->nestedAttribs = [];
}
function transform($xml) {
$xml = '<root>' . $xml . '</root>';
xml_parse($this->parser, $xml, true);
$finalOutput = $this->output;
$this->reset();
return $finalOutput;
}
function tagOpen($parser, $tag, $attributes) {
if (isset($attributes["id"]))
$this->nestedIDs[] = $attributes["id"];
switch($tag) {
case "bx":
$this->output .= '<span>' . htmlentities('<bx />') . "</span>";
break;
case "g":
$id = $attributes["id"];
$this->output .= '<span data-id="' . $id .'">' . htmlentities('<g id="'.$id.'">') . "</span>";
break;
default:
break;
}
}
function tagData($parser, $cdata) {
$this->output .= $cdata;
}
function tagClose($parser, $tag) {
switch($tag) {
case "g":
$id = array_pop($this->nestedIDs);
$this->output .= '<span data-closingof="' . $id .'">' . htmlentities('</g>') . "</span>";
break;
default:
break;
}
}
}
Example run:
$p = new TagsConverter();
echo $p->transform('<g id="1">test g <g id="2">222</g></g> <g id="3">3333</g> other <x/> content <g id="4">444</g> <bx/>');
<span data-id="1"><g id="1"></span>test g <span data-id="2"><g id="2"></span>222<span data-closingof="2"></g></span><span data-closingof="1"></g></span> <span data-id="3"><g id="3"></span>3333<span data-closingof="3"></g></span> other content <span data-id="4"><g id="4"></span>444<span data-closingof="4"></g></span> <span><bx /></span>
I wonder if there is a way to do in JS.

you can use this, but I dont know how your xml file looks like so I cant give you an example with your code.
this will make the xml in an array so you can easily get it out
$getXml = file_get_contents('xml.xml');
$xml = simplexml_load_string($getXml) or die("Error: Cannot create object");
this will loop trough the array
foreach($xml->channel->item as $item) {
//here you could do something like this
echo "<h1>";
print_r($item->title);
echo "</h1>";
echo "<br>";
}
you can also do this, this will print all elements from the xml
print_r($xml);
documentation about simplexml_load_string:
https://www.w3schools.com/php/func_simplexml_load_string.asp
if you dont understand plz comment

Related

I'm trying to use some data i pulled from a php database as information in a clickable SVG picture (javascript)

<?php
require_once('dbconn.php');
$arm = "SELECT problem, description, reason, reg_date FROM body_arm";
$result = $conn->query($arm);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
echo " " . $row["problem"].
" - " . $row["description"].
" - reason: " . $row["reason"].
" - TIMESTAMP:" . $row["reg_date"].
"<br/>";
}
} else {
echo "0 results";
}
$conn->close();
?>
<!--
Here I have some code for the SVG
-->
<script>
window.onload = function () {
const pieces = document.getElementsByTagName('svg');
for (var i = 0; pieces.length; i++) {
let _piece = pieces[i];
_piece.onclick = function(t) {
if (t.target.getAttribute('data-position') != null)
document.getElementById('data').innerHTML = t.target.getAttribute('data-position');
if (t.target.parentElement.getAttribute('data-position') != null)
document.getElementById('data').innerHTML = t.target.parentElement.getAttribute('data-position');
}
}
}
</script>
I have tried to use the function ob_get_contents, couldn't really get it working.
I have tried to echo the php variable to javascript like: var val = "";
As I'm starting to understand I can't really find the php variable in javascript and need to find a way around that or maybe use something like node.js to open a connection to the server with something closer to javascript? I'm a beginner by the way!
For me the solution I found was json_encode!
$example_array_variable = json_encode($example);
//Doing this in the PHP.
//Then later in the JavaScript decode it.
echo json_encode($example_array_variable);
Eureka!!

PHP 5.4.16 DOMDocument removes parts of Javascript

I try to load an HTML page from a remote server into a PHP script, which should manipulate the HTML with the DOMDocument class. But I have seen, that the DOMDocument class removes some parts of the Javascript, which comes with the HTML page. There are some things like:
<script type="text/javascript">
//...
function printJSPage() {
var printwin=window.open('','haha','top=100,left=100,width=800,height=600');
printwin.document.writeln(' <table border="0" cellspacing="5" cellpadding="0" width="100%">');
printwin.document.writeln(' <tr>');
printwin.document.writeln(' <td align="left" valign="bottom">');
//...
printwin.document.writeln('</td>');
//...
}
</script>
But the DOMDocument changes i.e. the line
printwin.document.writeln('</td>');
to
printwin.document.writeln(' ');
and also a lot of others things (i.e. the last script tag is no longer there. As the result I get a complete destroyed page, which I cannot send further.
So I think, DOMDocument has problems with the HTML tags within the Javascript code and tries to correct the code, to produce a well-formed document. Can I prevent the Javascript parsing within DOMDocument?
The PHP code fragment is:
$stdin = file_get_contents('php://stdin');
$dom = new \DOMDocument();
#$dom->loadHTML($stdin);
return $dom->saveHTML(); // will produce wrong HTML
//return $stdin; // will produce correct HTML
I have stored both HTML versions and have compared both with Meld.
I also have tested
#$dom->loadXML($stdin);
return $dom->saveHTML();
but I don't get any things back from the object.
Here's a hack that might be helpful. The idea is to replace the script contents with a string that's guaranteed to be valid HTML and unique then replace it back.
It replaces all contents inside script tags with the MD5 of those contents and then replaces them back.
$scriptContainer = [];
$str = preg_replace_callback ("#<script([^>]*)>(.*?)</script>#s", function ($matches) use (&$scriptContainer) {
$scriptContainer[md5($matches[2])] = $matches[2];
return "<script".$matches[1].">".md5($matches[2])."</script>";
}, $str);
$dom = new \DOMDocument();
#$dom->loadHTML($str);
$final = strtr($dom->saveHTML(), $scriptContainer);
Here strtr is just convenient due to the way the array is formatted, using str_replace(array_keys($scriptContainer), $scriptContainer, $dom->saveHTML()) would also work.
I find it very suprising that PHP does not properly parse HTML content. It seems to instead be parsing XML content (wrongly so as well because CDATA content is parsed instead of being treated literally). However it is what it is and if you want a real document parser then you should probably look into a Node.js solution with jsdom
If you have a <script> within a <script>, the following (not so smart) solution will handle that. There is still a problem: if the <script> tags are not balanced, the solution will not work. This could occur, if your Javascript uses String.fromCharCode to print the String </script>.
$scriptContainer = array();
function getPosition($tag) {
return $tag[0][1];
}
function getContent($tag) {
return $tag[0][0];
}
function isStart($tag) {
$x = getContent($tag);
return ($x[0].$x[1] === "<s");
}
function isEnd($tag) {
$x = getContent($tag);
return ($x[0].$x[1] === "</");
}
function mask($str, $scripts) {
global $scriptContainer;
$res = "";
$start = null;
$stop = null;
$idx = 0;
$count = 0;
foreach ($scripts as $tag) {
if (isStart($tag)) {
$count++;
$start = ($start === null) ? $tag : $start;
}
if (isEnd($tag)) {
$count--;
$stop = ($count == 0) ? $tag : $stop;
}
if ($start !== null && $stop !== null) {
$res .= substr($str, $idx, getPosition($start) - $idx);
$res .= getContent($start);
$code = substr($str, getPosition($start) + strlen(getContent($start)), getPosition($stop) - getPosition($start) - strlen(getContent($start)));
$hash = md5($code);
$res .= $hash;
$res .= getContent($stop);
$scriptContainer[$hash] = $code;
$idx = getPosition($stop) + strlen(getContent($stop));
$start = null;
$stop = null;
}
}
$res .= substr($str, $idx);
return $res;
}
preg_match_all("#\<script[^\>]*\>|\<\/script\>#s", $html, $scripts, PREG_OFFSET_CAPTURE|PREG_SET_ORDER);
$html = mask($html, $scripts);
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML($html);
libxml_use_internal_errors(false);
// handle some things within DOM
echo strtr($dom->saveHTML(), $scriptContainer);
If you replace the "script" String within the preg_match_all with "style" you can also mask the CSS styles, which can contain tag names too (i.e. within comments).

How to use javascript and HTML to add a sql and button?

I have an application where I want to ADD an AND button that, than creates the option to add an AND statement to the query. This is the php and html code I have to do this at the moment. The problem is I don't know how to connect the php part to the javascript part to create a button that adds exacte the same code?
This the html code:
This is the php code:
<?php
include "connect.php";
$table = $_POST['tableSelected'];
$field = $_POST['fieldSelected'];
$attribute = $_POST['attributeSelected'];
$operator = $_POST['operatorSelected'];
$fieldList = $_POST['fieldList'];
if (!empty($table)){
if (!empty($fieldList)){
$fieldstr = $fieldList . ",ST_AsGeoJSON(ST_Transform(l.geom,4326),6)";
} else {
$fieldstr = "";
}
$pairs = [];
foreach ($_POST['fieldSelected'] as $key => $field) {
if (!empty($field) && !empty($_POST['operatorSelected'][$key]) && !empty($_POST['attributeSelected'][$key])) {
$pairs[] = $field . " " . $_POST['operatorSelected'][$key] . " '" . $_POST['attributeSelected'][$key] . "'";
}
}
if (count($pairs) > 0) {
$sql .= ' WHERE ' . implode(' AND ', $pairs);
}
//echo ($sql);
?>
And this my html at the moment:
<select name="field[]">...</select>
<select name="operator[]">...</select>
<select name="value[]">...</select>
This is what I want:
Button click should produce something like it Javascript (jQuery):
newElement = $("#someSelector").clone(false);
// Some modification of new element. Change id for example
$(newElement).attr("id",newIdValue);
newElement.appendTo("#parentElement");

PHP: Detect url in text, check if url is image or website and then echo image

So I'm working on a project, and what I need to do is I have some text, and in that text it has lots of words and then a url which is an image. What I need to do it first, detect if that url is a website or an image, and then if it is an image I need to display the image with the <img> tags, and if it's a website echo the url with the <a href> tags. So far I have a script to detect if it's a url or image, but I still need to echo the image or url in the text. Here is the script:
<?php
function detectImage($url) {
$url_headers=get_headers($url, 1);
if(isset($url_headers['Content-Type'])){
$type=strtolower($url_headers['Content-Type']);
$valid_image_type=array();
$valid_image_type['image/png']='';
$valid_image_type['image/jpg']='';
$valid_image_type['image/jpeg']='';
$valid_image_type['image/jpe']='';
$valid_image_type['image/gif']='';
$valid_image_type['image/tif']='';
$valid_image_type['image/tiff']='';
$valid_image_type['image/svg']='';
$valid_image_type['image/ico']='';
$valid_image_type['image/icon']='';
$valid_image_type['image/x-icon']='';
if(isset($valid_image_type[$type])){
echo "url is image";
} else {
echo "url is website";
}
}
}
?>
A function is a routine that returns a value that can be used in your program.
Don't use functions to output stuf. Rewrite your function to :
<?php
function isValidImage($url) {
$url_headers=get_headers($url, 1);
if(isset($url_headers['Content-Type'])){
$type=strtolower($url_headers['Content-Type']);
$valid_image_type=array();
$valid_image_type['image/png']='';
$valid_image_type['image/jpg']='';
$valid_image_type['image/jpeg']='';
$valid_image_type['image/jpe']='';
$valid_image_type['image/gif']='';
$valid_image_type['image/tif']='';
$valid_image_type['image/tiff']='';
$valid_image_type['image/svg']='';
$valid_image_type['image/ico']='';
$valid_image_type['image/icon']='';
$valid_image_type['image/x-icon']='';
if(isset($valid_image_type[$type])){
return true; // Its an image
}
return false;// Its an URL
}
}
Then use the function in your logic :
<?php
$urls = [
'http://www.google.be',
'http://hearstcommerce.ca/customcontent/members/premium/sample.jpg',
];
foreach($urls as $url) {
if (isValidImage($url) {
echo '<img src="'.$url.'" />';
}else{
echo ''.$url.'';
}
}
Easy as pie
if(isset($valid_image_type[$type])){
$ech = '<img src="'.$url.'"/>';
} else {
$ech = '<a href=".'$url'.">".'$url'."<a>';
}
echo $ech;
Ok so I managed to solve it, my solution was
?>
function detectImage($url) {
$url_headers=get_headers($url, 1);
if(isset($url_headers['Content-Type'])){
$type=strtolower($url_headers['Content-Type']);
$valid_image_type=array();
$valid_image_type['image/png']='';
$valid_image_type['image/jpg']='';
$valid_image_type['image/jpeg']='';
$valid_image_type['image/jpe']='';
$valid_image_type['image/gif']='';
$valid_image_type['image/tif']='';
$valid_image_type['image/tiff']='';
$valid_image_type['image/svg']='';
$valid_image_type['image/ico']='';
$valid_image_type['image/icon']='';
$valid_image_type['image/x-icon']='';
if(isset($valid_image_type[$type])){
return true;
} else {
return false;
}
}
}
function detectLink($string) {
$content_array = explode(" ", $string);
$output = '';
foreach($content_array as $content) {
if(substr($content, 0, 7) == "http://" || substr($content, 0, 4) == "www.") {
if (detectImage($content)===true) {
$content = '<img src="'.$content.'">';
} else {
$content = ''.$content.'';
}
}
$output .= " " . $content;
}
$output = trim($output);
return $output;
}
?>
Feel free to use this anyone!

Could someone clarify this code snippet for me?

This piece should create a csv file. The method that is calling to the nonAjaxPost is:
function exportCSV()
{
nonAjaxPost('getExport', 'post', {action: '/getView', 'view': current_pi, 'parameters': encodeURIComponent(JSON.stringify(current_parameters))});
}
function nonAjaxPost(action, method, input) {
"use strict";
var form;
form = $('<form />', {
action: action,
method: method,
style: 'display: none;'
});
if (typeof input !== 'undefined') {
$.each(input, function (name, value) {
$('<input />', {
type: 'hidden',
name: name,
value: value
}).appendTo(form);
});
}
form.appendTo('body').submit();
}
My problem is that i just can't seem to understand how this is going to create a csv file for me. I'm probaly missing out on something that i just can't see.
I really hope someone could help me out.
Update:
This is the getExport function:
$databundle = $this->_getData();
$data = $databundle['rows'];
$columns_all = $databundle['columns'];
$columns = array("Id");
foreach($data[0] as $key => $column) {
$column = "";
$found = false;
foreach($columns_all as $col_search) {
if($col_search['key'] == #$key) {
$found = true;
$column = $col_search['title'];
break;
}
}
if($found) {
//echo $key . ",";
$columns[] = $column;
}
}
$contents = putcsv($columns, ';', '"');
foreach($data as $key => $vals) {
if(isset($vals['expand'])) {
unset($vals['expand']);
}
array_walk($vals, '__decode');
$contents .= putcsv($vals,';', '"');
}
$response = Response::make($contents, 200);
$response->header("Last-Modified",gmdate("D, d M Y H:i:s") . " GMT");
$response->header("Content-type","text/x-csv");
$response->header("Content-Disposition","attachment; filename=".str_replace(" ","_",$databundle['title'])."_".date("Y-m-d_H:i").".csv");
return $response;
It also calls the getData function which is this:
$viewClass = str_replace('/', '', (isset($_POST['view']) ? $_POST['view'] : $_GET['view']));
$fileView = '../app/classes/view.'.$viewClass.'.php';
if(file_exists($fileView))
{
require_once($fileView);
$className = 'view_'.$viewClass;
if(class_exists($className))
{
$view = new $className();
//Seek for parameters
if(isset($_REQUEST['parameters']))
{
//Decode parameters into array
$parameters = json_decode(urldecode((isset($_POST['parameters']) ? $_POST['parameters'] : $_GET['parameters'])),true);
//Get supported parameters
$parameterTypes = $view->getVars();
$vars = array();
foreach($parameterTypes as $key => $type)
{
//If a value is found for a supported parameter in $_GET
if(isset($parameters[$key]))
{
switch($type)
{
case 'int':
$vars[$key] = intval($parameters[$key]);
break;
case 'float':
$vars[$key] = floatval($parameters[$key]);
break;
case 'filterdata':
// todo: date validation
$vars[$key] = $parameters[$key];
break;
}
}
}
$view->setVars($vars);
}
return $view->getData();
}
else {
/*
header('HTTP/1.1 500 Internal Server Error');
echo 'Class ' . $className . ' does not exist.';
*/
return false;
}
}
else {
/*
header('HTTP/1.0 404 Not Found');
die('Cannot locate view (' . $fileView . ').');
*/
return false;
I hope this is sufficient.
In short what i am trying to find out is that the csv that it produces has more columns than columns headers and where the difference comes from
My guess would be that the page you are calling (on the server) is generating the CSV file.
You would need to write code on the server to do the conversion.
This method is making a post request to getView page. Your csv create code would be present on getView page.
This is the front end code that creates an invisible form with your data: current_parameters.
See the content of current_parameters in the the current file.
Review back-end code and look for the "getExport" function (it should be the current php file loaded)
If you just copied this function from some example... you have to add also the back-end code on your own.
Update:
look at the getExport code:
$contents = putcsv($columns, ';', '"');
$contents .= putcsv($vals,';', '"');;
First row insert the titles , and the second loops the data and insert the other rows.
Print the content of $columns and $vals and see what is happening.
There are some strange conditions for filtering the columns... but can help you if you don't show the data you try to parse.

Categories