How to convert HTML to JSON using PHP? - javascript

I can convert JSON to HTML using JsontoHtml library. Now,I need to convert present HTML to JSON as shown in this site. When looked into the code I found the following script:
<script>
$(function(){
//HTML to JSON
$('#btn-render-json').click(function() {
//Set html output
$('#html-output').html( $('#html-input').val() );
//Process to JSON and format it for consumption
$('#html-json').html( FormatJSON(toTransform($('#html-output').children())) );
});
});
//Convert obj or array to transform
function toTransform(obj) {
var json;
if( obj.length > 1 )
{
json = [];
for(var i = 0; i < obj.length; i++)
json[json.length++] = ObjToTransform(obj[i]);
} else
json = ObjToTransform(obj);
return(json);
}
//Convert obj to transform
function ObjToTransform(obj)
{
//Get the DOM element
var el = $(obj).get(0);
//Add the tag element
var json = {'tag':el.nodeName.toLowerCase()};
for (var attr, i=0, attrs=el.attributes, l=attrs.length; i<l; i++){
attr = attrs[i];
json[attr.nodeName] = attr.value;
}
var children = $(obj).children();
if( children.length > 0 ) json['children'] = [];
else json['html'] = $(obj).text();
//Add the children
for(var c = 0; c < children.length; c++)
json['children'][json['children'].length++] = toTransform(children[c]);
return(json);
}
//Format JSON (with indents)
function FormatJSON(oData, sIndent) {
if (arguments.length < 2) {
var sIndent = "";
}
var sIndentStyle = " ";
var sDataType = RealTypeOf(oData);
// open object
if (sDataType == "array") {
if (oData.length == 0) {
return "[]";
}
var sHTML = "[";
} else {
var iCount = 0;
$.each(oData, function() {
iCount++;
return;
});
if (iCount == 0) { // object is empty
return "{}";
}
var sHTML = "{";
}
// loop through items
var iCount = 0;
$.each(oData, function(sKey, vValue) {
if (iCount > 0) {
sHTML += ",";
}
if (sDataType == "array") {
sHTML += ("\n" + sIndent + sIndentStyle);
} else {
sHTML += ("\"" + sKey + "\"" + ":");
}
// display relevant data type
switch (RealTypeOf(vValue)) {
case "array":
case "object":
sHTML += FormatJSON(vValue, (sIndent + sIndentStyle));
break;
case "boolean":
case "number":
sHTML += vValue.toString();
break;
case "null":
sHTML += "null";
break;
case "string":
sHTML += ("\"" + vValue + "\"");
break;
default:
sHTML += ("TYPEOF: " + typeof(vValue));
}
// loop
iCount++;
});
// close object
if (sDataType == "array") {
sHTML += ("\n" + sIndent + "]");
} else {
sHTML += ("}");
}
// return
return sHTML;
}
//Get the type of the obj (can replace by jquery type)
function RealTypeOf(v) {
if (typeof(v) == "object") {
if (v === null) return "null";
if (v.constructor == (new Array).constructor) return "array";
if (v.constructor == (new Date).constructor) return "date";
if (v.constructor == (new RegExp).constructor) return "regex";
return "object";
}
return typeof(v);
}
</script>
Now, I am in need of using the following function in PHP. I can get the HTML data. All what I needed now is to convert the JavaScript function to PHP function. Is this possible? My major doubts are as follows:
The primary input for the Javascript function toTransform() is an object. Is it possible to convert HTML to object via PHP?
Are all the functions present in this particular JavaScript available in PHP?
Please suggest me the idea.
When I tried to convert script tag to json as per the answer given, I get errors. When I tried it in json2html site, it showed like this: .. How to achieve the same solution?

If you are able to obtain a DOMDocument object representing your HTML, then you just need to traverse it recursively and construct the data structure that you want.
Converting your HTML document into a DOMDocument should be as simple as this:
function html_to_obj($html) {
$dom = new DOMDocument();
$dom->loadHTML($html);
return element_to_obj($dom->documentElement);
}
Then, a simple traversal of $dom->documentElement which gives the kind of structure you described could look like this:
function element_to_obj($element) {
$obj = array( "tag" => $element->tagName );
foreach ($element->attributes as $attribute) {
$obj[$attribute->name] = $attribute->value;
}
foreach ($element->childNodes as $subElement) {
if ($subElement->nodeType == XML_TEXT_NODE) {
$obj["html"] = $subElement->wholeText;
}
else {
$obj["children"][] = element_to_obj($subElement);
}
}
return $obj;
}
Test case
$html = <<<EOF
<!DOCTYPE html>
<html lang="en">
<head>
<title> This is a test </title>
</head>
<body>
<h1> Is this working? </h1>
<ul>
<li> Yes </li>
<li> No </li>
</ul>
</body>
</html>
EOF;
header("Content-Type: text/plain");
echo json_encode(html_to_obj($html), JSON_PRETTY_PRINT);
Output
{
"tag": "html",
"lang": "en",
"children": [
{
"tag": "head",
"children": [
{
"tag": "title",
"html": " This is a test "
}
]
},
{
"tag": "body",
"html": " \n ",
"children": [
{
"tag": "h1",
"html": " Is this working? "
},
{
"tag": "ul",
"children": [
{
"tag": "li",
"html": " Yes "
},
{
"tag": "li",
"html": " No "
}
],
"html": "\n "
}
]
}
]
}
Answer to updated question
The solution proposed above does not work with the <script> element, because it is parsed not as a DOMText, but as a DOMCharacterData object. This is because the DOM extension in PHP is based on libxml2, which parses your HTML as HTML 4.0, and in HTML 4.0 the content of <script> is of type CDATA and not #PCDATA.
You have two solutions for this problem.
The simple but not very robust solution would be to add the LIBXML_NOCDATA flag to DOMDocument::loadHTML. (I am not actually 100% sure whether this works for the HTML parser.)
The more difficult but, in my opinion, better solution, is to add an additonal test when you are testing $subElement->nodeType before the recursion. The recursive function would become:
function element_to_obj($element) {
echo $element->tagName, "\n";
$obj = array( "tag" => $element->tagName );
foreach ($element->attributes as $attribute) {
$obj[$attribute->name] = $attribute->value;
}
foreach ($element->childNodes as $subElement) {
if ($subElement->nodeType == XML_TEXT_NODE) {
$obj["html"] = $subElement->wholeText;
}
elseif ($subElement->nodeType == XML_CDATA_SECTION_NODE) {
$obj["html"] = $subElement->data;
}
else {
$obj["children"][] = element_to_obj($subElement);
}
}
return $obj;
}
If you hit on another bug of this type, the first thing you should do is check the type of node $subElement is, because there exists many other possibilities my short example function did not deal with.
Additionally, you will notice that libxml2 has to fix mistakes in your HTML in order to be able to build a DOM for it. This is why an <html> and a <head> elements will appear even if you don't specify them. You can avoid this by using the LIBXML_HTML_NOIMPLIED flag.
Test case with script
$html = <<<EOF
<script type="text/javascript">
alert('hi');
</script>
EOF;
header("Content-Type: text/plain");
echo json_encode(html_to_obj($html), JSON_PRETTY_PRINT);
Output
{
"tag": "html",
"children": [
{
"tag": "head",
"children": [
{
"tag": "script",
"type": "text\/javascript",
"html": "\n alert('hi');\n "
}
]
}
]
}

I assume that your html string is stored in $html variable. So you should do:
$dom = new DOMDocument();
$dom->loadHTML($html);
foreach($dom->getElementsByTagName('*') as $el){
$result[] = ["type" => $el->tagName, "value" => $el->nodeValue];
}
$json = json_encode($result, JSON_UNESCAPED_UNICODE);
Note: This algorithm doesn't support parent-child tags and fetch all tags as parent elements and parses all of them in a sorted queue. Of course, you can implement this feature by studying the DOMDocument classes features.

I wrote this to convert HTML Form tags to a JSON object. You may be able to build off of this.
class HtmlToJson {
public $html;
public $filter;
function __construct($html, $filter) {
$this->dom = new DOMDocument();
$this->dom->loadHTML( $html );
$this->jsonObj = array('form_tag_attrs'=>array(), 'form_values'=>array());
$this->filter = $filter;
}
function recursivePair($element, $tagName) {
if ( isset( $element->attributes ) ) {
$nameAttr = $element->getAttribute('name');
if ($nameAttr) {
$this->jsonObj['form_values'][$nameAttr] = $element->getAttribute('value');
}
if ($element->nodeName === $tagName) {
foreach ( $element->attributes as $attribute ) {
$this->jsonObj['form_tag_attrs'][ $attribute->name ] = $attribute->value;
}
}
}
if ( isset( $element->childNodes ) ) {
foreach ( $element->childNodes as $subElement ) {
$this->recursivePair( $subElement, $tagName );
}
}
}
function json() {
$element = ($this->filter ? $this->dom->getElementsByTagName($this->filter)->item(0) : $this->dom->documentElement);
$this->recursivePair($element, $this->filter);
return $this->jsonObj;
}
}
$formJson = new HtmlToJson($curlResult, 'form');
echo json_encode($formJson->json());

Related

Why is this JSON file reading strangly

I have a JSON document here. I have validated it with JSlint.
The JSON is of this format:
[{
"date": "2017-02-10",
" action": "Do a thing",
"state": "closed",
"url": "https:someurl.com"
},
....
I have some HTML here, which exists only to read and output the JSON.
The HTML looks like this:
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
</head>
<body>
<script>
deadlines = []
start();
function start() {
var req = new XMLHttpRequest();
req.open("GET", "http://joereddington.com/deadlines.json");
req.overrideMimeType("application/json");
req.send(null);
req.onreadystatechange = function() {
if (req.readyState == 4 && req.status == 200) {
var obj = JSON.parse(req.responseText);
deadlines = obj
for (deadline in deadlines) {
var output = '';
for (var property in deadline) {
console.log(property)
output += property + ': ' + deadline[property] + '; ';
}
console.log(output);
console.log(deadline.date)
console.log(deadline.action)
}
}
};
}
</script>
</body>
However, when I try and list the properties of each object, I get very strange results:
rather than the names and values I'm looking for. Can someone tell me what I'm doing wrong?
$.each(JSON.parse(deadlines), function (index, deadline) {
var output = '';
for (var property in deadline) {
console.log(property)
output += property + ': ' + deadline[property] + '; ';
}
console.log(output);
console.log(deadline.date);
console.log(deadline.action);
});
Your JSON string contains extra space. It should be "action" not " action".
for...in loops over the keys (since it's an array: "0", "1" ...). Use for...of or forEach or a basic for loop.
I recommend forEach like this:
deadlines.forEach(function(deadline) {
// ...
});

Parsing json array to array javascript

I have an array with json data:
var jsonString=[
{
"url": "http://www.anurl.com",
"tags": {
"Event": 6,
"Event1": 2
}
}
]
Now i want to build the next structure:
var data= [ {"text":"Event", "weight" : "6", "link" :"www.anurl.com"} //etc ];
Now i looked into the var array = $.parseJSON(JSON.stringify(jsonString));
and on the result i try to build my data array with .push();
But how can i insert the Event: 6 part? i cannot do array.tags[0] as array.tags will give me both of them.
So how can i solve this problem?
You are using object literals in javascript, the example you provided:
var jsonString=[{
"url": "http://www.anurl.com",
"tags": {
"Event": 6,
"Event1": 2
}
}];
jsonString is an array, and the element tags is an object NOT an array so you can access it like this:
var event = jsonString[0].tags.Event;
You can read the attributes of the tags object like the example below :
function loadArray(urls){
xhrDoc= new XMLHttpRequest();
if (xhrDoc.overrideMimeType)
xhrDoc.overrideMimeType('text/plain; charset=x-user-defined');
xhrDoc.onreadystatechange =function()
{
if (this.readyState == 4)
{
if (this.status == 200)
{
var data= this.response; //Here is a string of the text data
printUrls(data);
}
}
};
xhrDoc.open('GET', urls , true);
xhrDoc.send();
}
function printUrls(response) {
var arr = JSON.parse(response);
var i;
var out = "";
for(i = 0; i < arr.length; i++) {
console.log(arr[i].url);
console.log(arr[i].tags['Event']); // Read Event
console.log(arr[i].tags['Event1']); //// Read Event1
out = "URL : "+ arr[i].url + " Event : "+ arr[i].tags['Event']+ " Event1 : " + arr[i].tags['Event1'] + "\n";
}
document.getElementById("id01").innerHTML = out;
}
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="parseJsonFile.js"></script>
</head>
<body onload="loadArray('parseJson.json')">
<div id="id01"></div>
</body>
</html>
i solved it with
this code
var array =$.parseJSON(JSON.stringify(jsonString));
for (var i = 0; i < array.length; i++) {
var keys =array[i].tags;
var tags = Object.keys(keys);
for(var j = 0 ; j<tags.length; j++){
var obj = {text : tags[j], weight : keys[tags[j]] , link : array[i].url};
Jarray.push(obj);
}
}
The data is provided by an API, so the tag Event : 6 might be the next time Tomorrlowland : 3 the name of event and the weight are given by the API. That's why i can't use jsonString[0].tags.Event because the name event will be different every time.
Thanks all for helping me !

Any JavaScript parser for .lrc?

I was using the code from Kejun's Blog .
I want to parse a .lrc (which is basically a lyrics file) so as to get the time variable as well as the string(read lyrics) . I tried out this code and could not seem to get the output .
<html>
<head>
<script src="jquery-1.7.1.js"></script>
<script>
$(document).ready(function () {
$.ajax({
type: "GET",
url: "a.txt",
dataType: "text",
success: function (data) {
parseLyric(data);
}
});
});
var _current_lyric = new Array();
function convertLRCLyric(inf) {
inf += "n";
var lyric = inf.match(/([(d{2}:d{2}(.d{1,2}){0,1})]){1,}W*n|([(d{2}:d{2}:d{2}(.d{1,2}){0,1})]){1,}W*n/ig);
var l_s = '',
l_tt, l_ww, l_i, l_ii;
if (!lyric || !lyric.length) {
return;
}
for (l_i = 0; l_i < lyric.length; l_i++) {
l_tt = lyric[l_i].match(/([d{2}:d{2}(.d{1,2}){0,1}])|([d{2}:d{2}:d{2}(.d{1,2}){0,1}])/ig);
l_ww = lyric[l_i].replace(/[S+]/ig, '').replace(/n{1,}/ig, '');
for (l_ii = 0; l_ii < l_tt.length; l_ii++) {
l_tt[l_ii] = l_tt[l_ii].replace(/[/,'').replace(/]/, '');
if (l_tt[l_ii].search(/d{2}:d{2}:d{2}.d{2}/g) >= 0) {
_current_lyric[l_tt[l_ii].substring(0, l_tt[l_ii].length - 1)] = l_ww;
} else if (l_tt[l_ii].search(/d{2}:d{2}:d{2}.d{1}/g) >= 0) {
_current_lyric[l_tt[l_ii]] = l_ww;
} else if (l_tt[l_ii].search(/d{2}:d{2}:d{2}/g) >= 0) {
_current_lyric[l_tt[l_ii] + ".0"] = l_ww;
} else if (l_tt[l_ii].search(/d{2}:d{2}.d{2}/g) >= 0) {
_current_lyric["00:" + l_tt[l_ii].substring(0, l_tt[l_ii].length - 1)] = l_ww;
} else if (l_tt[l_ii].search(/d{2}:d{2}.d{1}/g) >= 0) {
_current_lyric["00:" + l_tt[l_ii]] = l_ww;
} else if (l_tt[l_ii].search(/d{2}:d{2}/g) >= 0) {
_current_lyric["00:" + l_tt[l_ii] + ".0"] = l_ww;
}
}
}
}
function parseLyric(allText) {
_current_lyric = [];
convertLRCLyric(allText);
var ly = "";
for (var time in _current_lyric) {
ly += time + "--" + _current_lyric[time] + "n";
}
alert(ly);
}
</script>
</head>
<body>
</body>
</html>
But i keep getting a blank alert . Any help would be great . Thanks in advance .
Answer :
Ok so i built my own parser ,Here is the code
var contents = " " ;
function readMultipleFiles(evt) {
//Retrieve all the files from the FileList object
var files = evt.target.files;
if (files) {
for (var i = 0, f; f = files[i]; i++) {
var r = new FileReader();
r.onload = (function (f) {
return function (e) {
contents = e.target.result;
processData(contents);
};
})(f);
r.readAsText(f);
}
} else {
alert("Failed to load files");
}
}
document.getElementById('fileinput').addEventListener('change', readMultipleFiles, false);
var allTextLines = " ";
var lyrics = [];
var tim = [] ;
var line = " ";
// parsing the Lyrics
function processData(allText) { // This will only divide with respect to new lines
allTextLines = allText.split(/\r\n|\n/);
next();
}
function next()
{
for (i=0;i<allTextLines.length;i++)
{
if (allTextLines[i].search(/^(\[)(\d*)(:)(.*)(\])(.*)/i)>=0 )// any line without the prescribed format wont enter this loop
{
line = allTextLines[i].match(/^(\[)(\d*)(:)(.*)(\])(.*)/i);
tim[i] = (parseInt(line[2])*60)+ parseInt(line[4]); // will give seconds
lyrics[i]= line[6] ;//will give lyrics
}
}
}
Code php : with format
public function get_lrc_song($song) {
$lyrics_file = $song ['lyrics_file'];
$json = curlClass::getInstance ( true )->fetchURL ( $lyrics_file );
$content = explode ( "\n", $json );
$regix = "$\][^>]+$";
$result = "";
foreach ( $content as $item ) {
$isHas = preg_match ( $regix, $item, $data );
$dt = str_replace ( "]", "", $data[0] );
if ($dt != ""){
$result .= $dt . "\n";
}
}
echo $result;
}
I've made an plugin related to this which you can find here
There is an tutorial on how to use this and also i think this is most probably the simplest one I've seen while researching about this topic.
there is another lrc-parser for this purpose, I've tried it but, it lack some features like playing on command and other necessary features.
So i made them all
the code looks like this:
//view the tutorial of this usage on https://multimentality.000webhostapp.com/others
var lyricPlayer = {
"set_divval":function(){var all_lyrics = "";var mose;if(lyricPlayer.Mode=="Long"){mose="block"}else if(lyricPlayer.Mode=="Line"){mose="none"}else{alert("mode property: undefined value. lyricPlayer.Mode has two values 'Long' and 'Line'");mose="block"}for(let y=lyricPlayer.countt;y<lyricPlayer.lyrics.length;y++){all_lyrics+=`<span id='lyricsItem_${lyricPlayer.tim[y]}' class='lyricsItem_class' style='display:${mose};'>${lyricPlayer.lyrics[y]}</span>`;lyricPlayer.tmp_count=lyricPlayer.countt;lyricPlayer.main_dict[lyricPlayer.tim[y]]=lyricPlayer.tmp_count;lyricPlayer.tmp_count++;}document.getElementById('lyrics_playerMain').innerHTML=all_lyrics;},
"processData":function(allText){lyricPlayer.allTextLines = allText.split(/\r\n|\n/);lyricPlayer.next();},
"next":function()
{for (i=0;i<lyricPlayer.allTextLines.length;i++){if (lyricPlayer.allTextLines[i].search(/^(\[)(\d*)(:)(.*)(\])(.*)/i)>=0 ){lyricPlayer.line = lyricPlayer.allTextLines[i].match(/^(\[)(\d*)(:)(.*)(\])(.*)/i);lyricPlayer.tim[i] = (parseInt(lyricPlayer.line[2])*60)+ parseInt(lyricPlayer.line[4]);lyricPlayer.lyrics[i]= lyricPlayer.line[6] ;}else{lyricPlayer.countt++;}}lyricPlayer.set_divval();},
"set_scview":function(id){if(lyricPlayer.Mode=="Long"){var classes = document.getElementsByClassName("lyricsItem_class");for(let u=0;u<classes.length;u++){classes[u].style.color=lyricPlayer.Tcolor;}document.getElementById(`lyricsItem_${id}`).style.color=lyricPlayer.Scolor;var element = document.getElementById(`lyricsItem_${id}`);element.scrollIntoView({behavior: 'smooth',block: 'start'});}if(lyricPlayer.Mode=="Line"){var classes = document.getElementsByClassName("lyricsItem_class");
for(let u=0;u<classes.length;u++){
classes[u].style.display="none";
classes[u].style.color=lyricPlayer.Tcolor;}document.getElementById(`lyricsItem_${id}`).style.color=lyricPlayer.Scolor;document.getElementById(`lyricsItem_${id}`).style.display="block";}},
"change_lrc":function(elem){var time = parseInt(elem.currentTime);if(lyricPlayer.main_dict[time]!=undefined){lyricPlayer.set_scview(time)}},
"allTextLines":"",
"lyrics":[],
"tim":[],
"main_dict":{},
"h_lyrics":"",
"countt":0,
"Scolor":"white",
"line":"",
"tmp_count":0,
"Mode":"Long",
"Tcolor":document.getElementById("lyrics_playerMain").style.color,
"setLyrics":function(val){lyricPlayer.h_lyrics=val;lyricPlayer.main_dict={};lyricPlayer.countt=0;lyricPlayer.tim=[];lyricPlayer.lyrics=[];lyricPlayer.allTextLines="";lyricPlayer.processData(lyricPlayer.h_lyrics);lyricPlayer.tmp_count=lyricPlayer.countt;}
}
this works totally fine and perfect

Swapping out an array (nested?) for values from an XML doc (client side scripting only)

I'm an absolute newbie with javascript, but I'm just trying to tweak JPlayer to use an XML file for the playlist instead of the hard-coded playlist. So, here's the bit of code that creates the playlist:
//<![CDATA[
$(document).ready(function(){
var Playlist = function(instance, playlist, options) {
var self = this;
this.instance = instance; // String: To associate specific HTML with this playlist
this.playlist = playlist; // Array of Objects: The playlist
this.options = options; // Object: The jPlayer constructor options for this playlist
this.current = 0;
this.cssId = {
jPlayer: "jquery_jplayer_",
interface: "jp_interface_",
playlist: "jp_playlist_"
};
this.cssSelector = {};
$.each(this.cssId, function(entity, id) {
self.cssSelector[entity] = "#" + id + self.instance;
});
if(!this.options.cssSelectorAncestor) {
this.options.cssSelectorAncestor = this.cssSelector.interface;
}
$(this.cssSelector.jPlayer).jPlayer(this.options);
$(this.cssSelector.interface + " .jp-previous").click(function() {
self.playlistPrev();
$(this).blur();
return false;
});
$(this.cssSelector.interface + " .jp-next").click(function() {
self.playlistNext();
$(this).blur();
return false;
});
};
Playlist.prototype = {
displayPlaylist: function() {
var self = this;
$(this.cssSelector.playlist + " ul").empty();
for (i=0; i < this.playlist.length; i++) {
var listItem = (i === this.playlist.length-1) ? "<li class='jp-playlist-last'>" : "<li>";
listItem += "<a href='#' id='" + this.cssId.playlist + this.instance + "_item_" + i +"' tabindex='1'>"+ this.playlist[i].name +"</a>";
// Create links to free media
if(this.playlist[i].free) {
var first = true;
listItem += "<div class='jp-free-media'>(";
$.each(this.playlist[i], function(property,value) {
if($.jPlayer.prototype.format[property]) { // Check property is a media format.
if(first) {
first = false;
} else {
listItem += " | ";
}
listItem += "<a id='" + self.cssId.playlist + self.instance + "_item_" + i + "_" + property + "' href='" + value + "' tabindex='1'>" + property + "</a>";
}
});
listItem += ")</span>";
}
listItem += "</li>";
// Associate playlist items with their media
$(this.cssSelector.playlist + " ul").append(listItem);
$(this.cssSelector.playlist + "_item_" + i).data("index", i).click(function() {
var index = $(this).data("index");
if(self.current !== index) {
self.playlistChange(index);
} else {
$(self.cssSelector.jPlayer).jPlayer("play");
}
$(this).blur();
return false;
});
// Disable free media links to force access via right click
if(this.playlist[i].free) {
$.each(this.playlist[i], function(property,value) {
if($.jPlayer.prototype.format[property]) { // Check property is a media format.
$(self.cssSelector.playlist + "_item_" + i + "_" + property).data("index", i).click(function() {
var index = $(this).data("index");
$(self.cssSelector.playlist + "_item_" + index).click();
$(this).blur();
return false;
});
}
});
}
}
},
playlistInit: function(autoplay) {
if(autoplay) {
this.playlistChange(this.current);
} else {
this.playlistConfig(this.current);
}
},
playlistConfig: function(index) {
$(this.cssSelector.playlist + "_item_" + this.current).removeClass("jp-playlist-current").parent().removeClass("jp-playlist-current");
$(this.cssSelector.playlist + "_item_" + index).addClass("jp-playlist-current").parent().addClass("jp-playlist-current");
this.current = index;
$(this.cssSelector.jPlayer).jPlayer("setMedia", this.playlist[this.current]);
},
playlistChange: function(index) {
this.playlistConfig(index);
$(this.cssSelector.jPlayer).jPlayer("play");
},
playlistNext: function() {
var index = (this.current + 1 < this.playlist.length) ? this.current + 1 : 0;
this.playlistChange(index);
},
playlistPrev: function() {
var index = (this.current - 1 >= 0) ? this.current - 1 : this.playlist.length - 1;
this.playlistChange(index);
}
};
var mediaPlaylist = new Playlist("1", [
{
name:"song1",
mp3: "song1.mp3",
poster: "http://www.jplayer.org/video/poster/Incredibles_Teaser_640x272.png"
},
{
name:"song2",
mp3: "song2.mp3",
poster: "http://www.jplayer.org/video/poster/Incredibles_Teaser_640x272.png"
},
{
name:"song3",
mp3: "song3.mp3",
poster: "http://www.jplayer.org/video/poster/Incredibles_Teaser_640x272.png"**
}
], {
ready: function() {
mediaPlaylist.displayPlaylist();
mediaPlaylist.playlistInit(false); // Parameter is a boolean for autoplay.
},
ended: function() {
mediaPlaylist.playlistNext();
},
swfPath: "js",
supplied: "ogv, m4v, oga, mp3"
});
});
The part that starts with "var mediaPlaylist" is the only section i need to change. Instead of having the keys/values as name: songname, mp3: mp3, etc., I want it to pull these values from an XML file, or better yet, just push them into the array from an XML that looks like:
<song>songname</song>
<mp3>file.mp3</mp3>
The thing that's mostly confusing me here is how that function/array is set up...too many curly braces and brackets to wrap my head around. How do I get into this without breaking it?
If you have a server side XML playlist file in the form:
<?xml version="1.0" encoding="UTF-8"?>
<playlist>
<entry>
<song>songname</song>
<mp3>file.mp3</mp3>
</entry>
<entry>
<song>songname2</song>
<mp3>file2.mp3</mp3>
</entry>
</playlist>
then you can load this from the client via AJAX and create a JSON array from the XML. The following example uses the jQuery JavaScript framework and also the jquery-json plugin (only to format the Array nicely as JSON). You should be able to run this on Chrome or Firefox as both have a console (accessed by pressing F12 in the browser) in which I am outputting the JSON array.
Note: You could change console.log(...) to alert(...) if you don't use either of those browsers.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Title</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript" src="http://jquery-json.googlecode.com/files/jquery.json-2.2.min.js"></script>
<script type="text/javascript">
$(function() {
var Playlist = function(instance, playlist, options) {
var self = this;
this.instance = instance;
this.playlist = playlist;
this.options = options;
};
function getPlaylist(callback) {
var songs = new Array();
$.ajax({
dataType:'xml',
url:'songs.xml',
success : function (xml) {
$(xml).find('entry').each(function() {
songs.push({name: $(this).find('song').text(), mp3: $(this).find('mp3').text()});
});
callback(songs);
}
});
}
getPlaylist(function(songs) {
var playlistFromXML = jQuery.toJSON(songs);
var mediaPlaylist = new Playlist('1', playlistFromXML, null);
console.log(mediaPlaylist);
// etc...
});
});
</script>
</head><body></body></html>
Credit to How to return an array from jQuery ajax success function properly? answer as I used that approach to return a value from the jQuery $.ajax success method.
You will have to refactor the var mediaPlaylist = new Playlist() constructor into the callback function though as you cannot return the playlist value from the callback (see How can I catch the return value from the result() callback function that I'm using?)
Hope this helps :-)

How do I iterate over a JSON structure? [duplicate]

This question already has answers here:
Loop (for each) over an array in JavaScript
(40 answers)
Closed 5 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
I have the following JSON structure:
[{ "id":"10", "class": "child-of-9" }, { "id": "11", "classd": "child-of-10" }]
How do I iterate over it using JavaScript?
var arr = [ {"id":"10", "class": "child-of-9"}, {"id":"11", "class": "child-of-10"}];
for (var i = 0; i < arr.length; i++){
document.write("<br><br>array index: " + i);
var obj = arr[i];
for (var key in obj){
var value = obj[key];
document.write("<br> - " + key + ": " + value);
}
}
note: the for-in method is cool for simple objects. Not very smart to use with DOM object.
Taken from jQuery docs:
var arr = [ "one", "two", "three", "four", "five" ];
var obj = { one:1, two:2, three:3, four:4, five:5 };
jQuery.each(arr, function() {
$("#" + this).text("My id is " + this + ".");
return (this != "four"); // will stop running to skip "five"
});
jQuery.each(obj, function(i, val) {
$("#" + i).append(document.createTextNode(" - " + val));
});
Use for...of:
var mycars = [{name:'Susita'}, {name:'BMW'}];
for (var car of mycars)
{
document.write(car.name + "<br />");
}
Result:
Susita
BMW
Please let me know if it is not easy:
var jsonObject = {
name: 'Amit Kumar',
Age: '27'
};
for (var prop in jsonObject) {
alert("Key:" + prop);
alert("Value:" + jsonObject[prop]);
}
If this is your dataArray:
var dataArray = [{"id":28,"class":"Sweden"}, {"id":56,"class":"USA"}, {"id":89,"class":"England"}];
then:
$(jQuery.parseJSON(JSON.stringify(dataArray))).each(function() {
var ID = this.id;
var CLASS = this.class;
});
Copied and pasted from http://www.w3schools.com, there is no need for the JQuery overhead.
var person = {fname:"John", lname:"Doe", age:25};
var text = "";
var x;
for (x in person) {
text += person[x];
}
RESULT: John Doe 25
mootools example:
var ret = JSON.decode(jsonstr);
ret.each(function(item){
alert(item.id+'_'+item.classd);
});
You can use a mini library like objx - http://objx.googlecode.com/
You can write code like this:
var data = [ {"id":"10", "class": "child-of-9"},
{"id":"11", "class": "child-of-10"}];
// alert all IDs
objx(data).each(function(item) { alert(item.id) });
// get all IDs into a new array
var ids = objx(data).collect("id").obj();
// group by class
var grouped = objx(data).group(function(item){ return item.class; }).obj()
There are more 'plugins' available to let you handle data like this, see http://code.google.com/p/objx-plugins/wiki/PluginLibrary
With nested objects, it can be retrieve as by recursive function:
function inside(events)
{
for (i in events) {
if (typeof events[i] === 'object')
inside(events[i]);
else
alert(events[i]);
}
}
inside(events);
where as events is json object.
Marquis Wang's may well be the best answer when using jQuery.
Here is something quite similar in pure JavaScript, using JavaScript's forEach method. forEach takes a function as an argument. That function will then be called for each item in the array, with said item as the argument.
Short and easy:
var results = [ {"id":"10", "class": "child-of-9"}, {"id":"11", "classd": "child-of-10"} ];
results.forEach(function(item) {
console.log(item);
});
this is a pure commented JavaScript example.
<script language="JavaScript" type="text/javascript">
function iterate_json(){
// Create our XMLHttpRequest object
var hr = new XMLHttpRequest();
// Create some variables we need to send to our PHP file
hr.open("GET", "json-note.php", true);//this is your php file containing json
hr.setRequestHeader("Content-type", "application/json", true);
// Access the onreadystatechange event for the XMLHttpRequest object
hr.onreadystatechange = function() {
if(hr.readyState == 4 && hr.status == 200) {
var data = JSON.parse(hr.responseText);
var results = document.getElementById("myDiv");//myDiv is the div id
for (var obj in data){
results.innerHTML += data[obj].id+ "is"+data[obj].class + "<br/>";
}
}
}
hr.send(null);
}
</script>
<script language="JavaScript" type="text/javascript">iterate_json();</script>// call function here
var jsonString = `{
"schema": {
"title": "User Feedback",
"description": "so",
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
},
"options": {
"form": {
"attributes": {},
"buttons": {
"submit": {
"title": "It",
"click": "function(){alert('hello');}"
}
}
}
}
}`;
var jsonData = JSON.parse(jsonString);
function Iterate(data)
{
jQuery.each(data, function (index, value) {
if (typeof value == 'object') {
alert("Object " + index);
Iterate(value);
}
else {
alert(index + " : " + value);
}
});
}
Iterate(jsonData);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Another solution to navigate through the JSON document is JSONiq (implemented in the Zorba engine), where you can write something like this:
let $doc := [
{"id":"10", "class": "child-of-9"},
{"id":"11", "class": "child-of-10"}
]
for $entry in members($doc) (: binds $entry to each object in turn :)
return $entry.class (: gets the value associated with "class" :)
You can run it on http://public.rumbledb.org:9090/public.html

Categories