This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
JSON pretty print using JavaScript
I'd like to display my raw JSON data on a HTML page just as JSONview does. For example, my raw json data is:
{
"hey":"guy",
"anumber":243,
"anobject":{
"whoa":"nuts",
"anarray":[
1,
2,
"thr<h1>ee"
],
"more":"stuff"
},
"awesome":true,
"bogus":false,
"meaning":null,
"japanese":"明日がある。",
"link":"http://jsonview.com",
"notLink":"http://jsonview.com is great"
}
It comes from http://jsonview.com/, and what I want to achieve is like http://jsonview.com/example.json if you use Chrome and have installed the JSONView plugin.
I've tried but failed to understand how it works. I'd like to use a JS script (CSS to highlight) to custom format my raw JSON data which is retrieved by ajax and finally put it on a HTML page in any position like into a div element. Are there any existing JS libraries that can achieve this? Or how to do it?
I think all you need to display the data on an HTML page is JSON.stringify.
For example, if your JSON is stored like this:
var jsonVar = {
text: "example",
number: 1
};
Then you need only do this to convert it to a string:
var jsonStr = JSON.stringify(jsonVar);
And then you can insert into your HTML directly, for example:
document.body.innerHTML = jsonStr;
Of course you will probably want to replace body with some other element via getElementById.
As for the CSS part of your question, you could use RegExp to manipulate the stringified object before you put it into the DOM. For example, this code (also on JSFiddle for demonstration purposes) should take care of indenting of curly braces.
var jsonVar = {
text: "example",
number: 1,
obj: {
"more text": "another example"
},
obj2: {
"yet more text": "yet another example"
}
}, // THE RAW OBJECT
jsonStr = JSON.stringify(jsonVar), // THE OBJECT STRINGIFIED
regeStr = '', // A EMPTY STRING TO EVENTUALLY HOLD THE FORMATTED STRINGIFIED OBJECT
f = {
brace: 0
}; // AN OBJECT FOR TRACKING INCREMENTS/DECREMENTS,
// IN PARTICULAR CURLY BRACES (OTHER PROPERTIES COULD BE ADDED)
regeStr = jsonStr.replace(/({|}[,]*|[^{}:]+:[^{}:,]*[,{]*)/g, function (m, p1) {
var rtnFn = function() {
return '<div style="text-indent: ' + (f['brace'] * 20) + 'px;">' + p1 + '</div>';
},
rtnStr = 0;
if (p1.lastIndexOf('{') === (p1.length - 1)) {
rtnStr = rtnFn();
f['brace'] += 1;
} else if (p1.indexOf('}') === 0) {
f['brace'] -= 1;
rtnStr = rtnFn();
} else {
rtnStr = rtnFn();
}
return rtnStr;
});
document.body.innerHTML += regeStr; // appends the result to the body of the HTML document
This code simply looks for sections of the object within the string and separates them into divs (though you could change the HTML part of that). Every time it encounters a curly brace, however, it increments or decrements the indentation depending on whether it's an opening brace or a closing (behaviour similar to the space argument of 'JSON.stringify'). But you could this as a basis for different types of formatting.
Note that the link you provided does is not an HTML page, but rather a JSON document. The formatting is done by the browser.
You have to decide if:
You want to show the raw JSON (not an HTML page), as in your example
Show an HTML page with formatted JSON
If you want 1., just tell your application to render a response body with the JSON, set the MIME type (application/json), etc.
In this case, formatting is dealt by the browser (and/or browser plugins)
If 2., it's a matter of rendering a simple minimal HTML page with the JSON where you can highlight it in several ways:
server-side, depending on your stack. There are solutions for almost every language
client-side with Javascript highlight libraries.
If you give more details about your stack, it's easier to provide examples or resources.
EDIT: For client side JS highlighting you can try higlight.js, for instance.
JSON in any HTML tag except <script> tag would be a mere text. Thus it's like you add a story to your HTML page.
However, about formatting, that's another matter. I guess you should change the title of your question.
Take a look at this question. Also see this page.
Related
This is what I am doing: I am building a fun in house API Voting System. I am using a client side snippet insert onto page
Like this:
<script src="domain.com/api/scripts/main.js"></script>
<div id="content-wrap" id="ac1e435e-c564-48f8-9f45-338616e7a789"></div>
Now in my main .JS I do all ajax request and modify the #content-wrap with creating new elements and inserting additional JS required to run Voting System.
However big issue I am experiencing is when I write JavaScript that I need to insert into #content-wrap I am currently writing it like this:
script.innerHTML = "$(someting).on('click', funciton(){"
+ "$.ajax({type: 'post',"
+ " url: '" + base + "/api/request', data: $('form').serialize(), "
+ "success: function(response){";
As you can see that can cause lot of issues as I build on it.
What is better way to accomplish this or is there a way i can just write my script / code and do something like this.
script.innerHTML = ConvertToString(script.js) OR ConvertToString(function X);
ConvertToString is just an expression I am using to explain what I would like to do instead of what I am doing.
Thank you, I am open to any suggestions.
I also must do this in plain JavaScript or with jQuery library so any suggestions to use VueJs, AngularJS or React will be considered as future references.
Thank you again
Additional explanation:
I would like to insert into my script element JavaScript snippet. But my snippet is about 30 lines long currently and might get bigger with time so it is very difficult to code with all the + " code " on every line that I write so that it can be inserted with innerHTML into element and executed on Client end.
So I would instead like to do something like this
element.innerHTML = mysnippetcode // but with out using + "" on each line like shown above
OR
element.append(snippet)
I hope this makes it little more clear
Solution that worked for me was using back ticks to wrap my sinppet and insert it into innerHTML of the element..
Just use the function's name without the () to convert it to a string:
function foo() {
var a = 10;
var b = 20;
var c = a + b;
return c;
}
document.write(foo);
The document.write will result in this string:
function foo() { var a = 10; var b = 20; var c = a + b; return c; }
If you only want the function's body, then you could just normally remove the first and last characters of the string.
I am not entirely sure this is what you wanted, if not, please make yourself more clear.
Alternatively, you could do an eval([insert function code here]) and there would be no need to add the code to the innterHTML of the script, read up on that function if you haven't heard of it.
Or if you want to create a function from a string, you can use new Function([name] ,[function body string]) if you need arguments you have to sandwich them between the 2 parameters.
But my snippet is about 30 lines long currently and might get bigger with time > so it is very difficult to code with all the + " code " on every line that I
write
You can use template literals if you want multi-line strings in Javascript, you simply have to replace your quotes with backticks.
See this MDN page if you are interested, or even this StackOverflow answer.
I'm in the most interesting position where I would like to template my JavaScript files server-side to include and remove certain parts based on an object. Given an object like so:
var obj = {
"includeA": true,
"includeB": false,
"includeC": true
}
I would like the ability to include/exclude certain parts of said JS file. For example:
if (obj.includeA) {
// This is some code from A
}
if (obj.includeB) {
// This is some code from B
}
Would produce either a string or a file that looks like:
// This is some code from A
I've looked into some basic options, one of the foremost ideas that came to mind was to simply use if statements in JS. This code however looks rather terrible, and considering there will be upto 1,000 lines of this, not suitable at all:
var string = ""
if (obj.includeA) {
string += "This is one line \n"
string += "This is another line \n"
}
// etc.
This produces the right output, but the repetitiveness of the string += makes me detest it. I then decided to package it up into a function:
var string = ""
function call(line) {
string += line + "\n"
if (obj.includeA) {
call("This is one line")
call"This is another line)
}
// etc.
But that seems only slightly better. Is there any sort of templating engine (imagining something similar to Jade), that allows templating of text blocks like this?
I know that counting the number of tags in a document can be done with something like the following
var tableCount = $('body table tr').length;
Now I presume that this only counts the number of tags. What I want to know is that I have the same number of closing tags . So if the code above shows there are 72 tags, I now want something to tell me that there are 72 closing tr tags.
Is this possible?
Thanks
Ideally, you would use a function like this:
function checkTable(tableElement) {
// Get inner HTML
var html = tableElement.innerHTML;
// Count <tr>
var count1 = html.match(/<tr/g).length;
// Count </tr>
var count2 = html.match(/<\/tr/g).length;
// Equals?
return count1 === count2;
}
However, due to browser's mumbo-jumbo, the mismatched tags get auto-corrected (i.e. auto-closed). Therefore it is impossible for a running page to validate itself. Here is a proof of concept: JS Bin.
Explanation: The second table has a typo (opening tag instead of a closing tag), but the function returns true in both cases. If one inspects the generated HTML (the one that is accessible through DOM), one can see that the browser auto-corrected the mismatched tags (there is an additional empty table row).
Luckily, there is another way. To obtain the pure (i.e. not modified by the browser) HTML code, you can make an AJAX request to the current page URL. Yes, you read correctly - the page loads itself again. But no worries, there is no recursion and possible stackoverflow here, since you do not process the fetched page.
The JS code for the following is:
var selfUrl = document.location.href;
function checkHTML(html) {
// Count <tr>
var count1 = html.match(/<tr/g).length;
console.log(count1);
// Count </tr>
var count2 = html.match(/<\/tr/g).length; // </tr (do not remove this comment!)
console.log(count2);
// Equals?
return count1 === count2;
}
$.get(selfUrl, function(html) {
console.log(checkHTML(html));
});
But beware of one pitfall. If you include this code in the HTML itself (usually discouraged), then you must not remove that one comment. The reason is the following: one regex contains <tr, while the other has the forward slash escaped and does therefore not contain a </tr. And since you fetch the whole HTML code (including the JS code), the count is mismatched. To even this, I have added an additional </tr inside a comment.
Your question reminds me the idea of the SAX Parser, as the HTML code obviously is the kind of XML. SAX Parser is commonly looking at the start and end tags, as long as element attributes and content.
Some time ago, I have used the simple SAX Parser library from: http://ejohn.org/blog/pure-javascript-html-parser/
Available at: http://ejohn.org/files/htmlparser.js
Using this library you can do the following:
$(document).ready(function(){
var htmlString = $('#myTable').html(),
countStart = 0,
countEnd = 0;
HTMLParser(htmlString, {
start: function(tag, attrs, unary) {
countStart += 1; // you may add the if tag === 'tr' or else
console.log("start: " + tag);
},
end: function(tag) {
countEnd += 1; // you may add the if tag === 'tr' or else
console.log("end: " + tag);
},
chars: function(text) {},
comment: function(text) {}
});
});
There are also modern Node-based approaches like: https://github.com/isaacs/sax-js/blob/master/examples/example.js which can be used for the same task.
I have a common function to display errors as a result of an AJAX call. Some of those messages are HTML strings, which I want to convert to a DOM object then search for elements inside it using .find(). Others will be just strings (not HTML). In this case, I don't know how to handle this...it is generating exceptions.
var messageTest = "" + this;
if ($(messageTest).length == 0) {
message += this;
} else {
message += $(messageTest).find('.message-error').html();
}
FYI, "this" in this case seems to be a String object with an array in which each item is a character, so in the inspector, it isn't showing "my message here" but:
[0]: "m"
[1]: "y"
etc
When it is just a string, which is not HTML, I get an error at the if statement line:
Uncaught Error: Syntax error, unrecognized expression:<The contents of messageText>
So how to I gracefully handle this when the input could be an HTML string or just a string?
Note...in the end, I just want the string, as I am going to wrap it in it's own HTML.
If it's either a string or HTML, it can always be appended to an element, and then sorted out:
var msg = $('<div />').append(this),
err = msg.find('.message-error'),
txt = err.length ? err.text() : msg.text();
message += txt;
append the string or HTML to an empty div, if the div contains a .message-error element, get the text of that element, otherwise get the text of the div, which would equal the original string etc.
One way, very close to what you have, is to catch the exception, and in this case consider it's a string (assuming this contains the response string):
var messageString = this;
var messageDOM;
try {
messageDOM = $(messageString);
} catch(ex) {
// If we got here, messageString is not HTML
messageDOM = $('<div/>').text(messageString);
}
I know this doesn't answer your question, but I feel like what you're wanting can be better accomplished by a slight change in methodology.
If you have control of the server sending these responses, i would recommend sending them back as JSON objects, if you make every result a JSON object then you can set an error property to true/false in the object that comes back along with a message value with your HTML or error message.
This is faster on the client system as well since its a native object to javascript and jquery has excellent JSON support using $.getJSON.
I would like to pretty print JSON on a web page and highlight some text / lines in it.
Ideally I am searching for a IFRAME - service to which I can link and URL where the JSON get's donwloaded and displayed as HTML, but I would like to specify an search string, which should be highlighted or the whole line containing the search string should be highlighted. The JSON is public so there is no privacy issue.
If there is no such service, is there a Javscript library which supports highlighting?
Focusing in more on your question about iframes - it's an issue in itself. It's not possible to do what you want in an iframe if the domain names aren't the same. However there are some workarounds for the same-origin policy that could help you in this situation.
Ideally the service you're pulling from supports jsonp so you don't have to deal with iframes and can do what you like with the json response without worrying about the same-origin policy.
As mentioned in a previous answer of mine you can use Prettify to apply syntax highlighting, though you can't highlight a specific line (from what I've found so far). For this example I'll be using the GitHub API.
For the HTML, you would have:
<pre id="jsonCode" class="prettyprint lang-json"></pre>
And the JavaScript to fetch and pretty print the JSON response (switch out jquery if you'd like):
$.getJSON('https://api.github.com/users/trevorsenior?callback=?',
function(data) {
var jsonString = JSON.stringify(data, null, 4);
$('#jsonCode').text(jsonString);
prettyPrint(); //apply syntax highlighting to to JSON
});
You can look at a working demonstration here: http://plnkr.co/edit/RiDtloVflmfuOrAokNXE?p=preview
If you do decide to use Prettify take a look at their getting started guide.
Update
To fully answer your question, it is easy enough to add in highlighting to some text by wrapping the text in <span> tags with a specified class. I've thrown together another example of this that builds off of the previous one: http://plnkr.co/edit/FM6Ua4pOvMW7nFFggdBy?p=preview
In a nutshell:
.highlighted {
background-color: #ff0;
}
$('#search').keyup(function() {
var search = $('#search').val();
if(jsonString.match(search)) {
var regex = new RegExp(search, 'g');
var highlighted = '<span class="highlighted">' + search + '</span>';
var newJsonString = jsonString.replace(regex, highlighted);
$('#jsonCode').html(prettyPrintOne(newJsonString));
} else {
$('#jsonCode').html(prettyPrintOne(jsonString));
}
});
If you want to remove the dynamic functionality & highlight on load simply move the logic out from the event listener:
var highlight = function(jsonString, searchFor) {
var regex = new RegExp(searchFor, 'g');
var highlighted = '<span class="highlighted">' + searchFor + '</span>';
var newJsonString = jsonString.replace(regex, highlighted);
return prettyPrintOne(newJsonString);
};
And call it just before you populate the area with the code
$('#jsonCode').html(highlight(jsonString, 'X-RateLimit'));
Demonstration: http://plnkr.co/edit/be3SNq1TzeiPKXohXOk9?p=preview