We need to write a script to create a JSON-LD script for structured Data for a Component in JSP let say FAQ component, we have written script to generate JSON LD for Structured data,
faq.jsp :
<script type="application/ld+json">
{
"#context": "https://schema.org",
"type": "FAQPage",
"mainEntity": [
<c:forEach var='questionItem' items='${faq.faqQuestionList}' varStatus='itemsLoopSchema'>
{
<c:set var="trimmedAnswer" value="${fn:trim(questionItem.answer)}" />
"#type": "Question",
"name": "${questionItem.question}",
"acceptedAnswer": {
"#type": "Answer",
"text": "${fn:escapeXml(trimmedAnswer)}"
}
<c:choose>
<c:when test="${itemsLoopSchema.last}">
}
</c:when>
<c:otherwise>
},
</c:otherwise>
</c:choose>
</c:forEach>
]
}
</script>
Now when this JSP Component included Multiple time the script will run multiple time and create multiple JSON
Instead I want to load all the multiple FAQ component and then create JSON (or run script only once).
A single JSON LD where all the details will be there for multiple faq.jsp
*Restricting Script to run once and get the data of all the page DOM in JSON for SEO purpose in JSP
I know this may not be the answer you’re looking for but having multiple json+ld blocks on the same page is perfectly valid, even if they’re of the same type.
Additionally, I would recommend inlining the structured data into the FAQ markup you’re outputting using microformats (using itemscope, itemprop, and itemtype attributes).
Some ideas:
Add a Sling Model in the head of your page. query all FAQ components and generate the JSON+LD data. Sling Model just outputs the string
Create a FAQ Container where you drop each FAQ component. FAQWrapper Sling Model generates the JSON+LD just as above
Also, some recommendations:
Do the JSON generation in java, not in the JSP itself.
Look for a java library that generates the schema for you, otherwise is easy to make mistakes and generating invalid data. We implemented our own solution based on Lombok SuperBuilder, Delegate, and Jackson and it was a lot of work
Although google recommends using JSON+LD, I've seen websites using microformats and it works just fine, so consider Raphael's suggestion.
Related
I have this JSON file I generate in the server I want to make accessible on the client as the page is viewable. Basically what I want to achieve is:
I have the following tag declared in my html document:
<script id="test" type="application/json" src="http://myresources/stuf.json">
The file referred in its source has JSON data. As I've seen, data has been downloaded, just like it happens with the scripts.
Now, how do I access it in Javascript? I've tried accessing the script tag, with and without jQuery, using a multitude of methods to try to get my JSON data, but somehow this doesn't work. Getting its innerHTML would have worked had the json data been written inline in the script. Which it wasn't and isn't what I'm trying to achieve.
Remote JSON Request after page loads is also not an option, in case you want to suggest that.
You can't load JSON like that, sorry.
I know you're thinking "why I can't I just use src here? I've seen stuff like this...":
<script id="myJson" type="application/json">
{
name: 'Foo'
}
</script>
<script type="text/javascript">
$(function() {
var x = JSON.parse($('#myJson').html());
alert(x.name); //Foo
});
</script>
... well to put it simply, that was just the script tag being "abused" as a data holder. You can do that with all sorts of data. For example, a lot of templating engines leverage script tags to hold templates.
You have a short list of options to load your JSON from a remote file:
Use $.get('your.json') or some other such AJAX method.
Write a file that sets a global variable to your json. (seems hokey).
Pull it into an invisible iframe, then scrape the contents of that after it's loaded (I call this "1997 mode")
Consult a voodoo priest.
Final point:
Remote JSON Request after page loads is also not an option, in case you want to suggest that.
... that doesn't make sense. The difference between an AJAX request and a request sent by the browser while processing your <script src=""> is essentially nothing. They'll both be doing a GET on the resource. HTTP doesn't care if it's done because of a script tag or an AJAX call, and neither will your server.
Another solution would be to make use of a server-side scripting language and to simply include json-data inline. Here's an example that uses PHP:
<script id="data" type="application/json"><?php include('stuff.json'); ?></script>
<script>
var jsonData = JSON.parse(document.getElementById('data').textContent)
</script>
The above example uses an extra script tag with type application/json. An even simpler solution is to include the JSON directly into the JavaScript:
<script>var jsonData = <?php include('stuff.json');?>;</script>
The advantage of the solution with the extra tag is that JavaScript code and JSON data are kept separated from each other.
It would appear this is not possible, or at least not supported.
From the HTML5 specification:
When used to include data blocks (as opposed to scripts), the data must be embedded inline, the format of the data must be given using the type attribute, the src attribute must not be specified, and the contents of the script element must conform to the requirements defined for the format used.
While it's not currently possible with the script tag, it is possible with an iframe if it's from the same domain.
<iframe
id="mySpecialId"
src="/my/link/to/some.json"
onload="(()=>{if(!window.jsonData){window.jsonData={}}try{window.jsonData[this.id]=JSON.parse(this.contentWindow.document.body.textContent.trim())}catch(e){console.warn(e)}this.remove();})();"
onerror="((err)=>console.warn(err))();"
style="display: none;"
></iframe>
To use the above, simply replace the id and src attribute with what you need. The id (which we'll assume in this situation is equal to mySpecialId) will be used to store the data in window.jsonData["mySpecialId"].
In other words, for every iframe that has an id and uses the onload script will have that data synchronously loaded into the window.jsonData object under the id specified.
I did this for fun and to show that it's "possible' but I do not recommend that it be used.
Here is an alternative that uses a callback instead.
<script>
function someCallback(data){
/** do something with data */
console.log(data);
}
function jsonOnLoad(callback){
const raw = this.contentWindow.document.body.textContent.trim();
try {
const data = JSON.parse(raw);
/** do something with data */
callback(data);
}catch(e){
console.warn(e.message);
}
this.remove();
}
</script>
<!-- I frame with src pointing to json file on server, onload we apply "this" to have the iframe context, display none as we don't want to show the iframe -->
<iframe src="your/link/to/some.json" onload="jsonOnLoad.apply(this, someCallback)" style="display: none;"></iframe>
Tested in chrome and should work in firefox. Unsure about IE or Safari.
I agree with Ben. You cannot load/import the simple JSON file.
But if you absolutely want to do that and have flexibility to update json file, you can
my-json.js
var myJSON = {
id: "12ws",
name: "smith"
}
index.html
<head>
<script src="my-json.js"></script>
</head>
<body onload="document.getElementById('json-holder').innerHTML = JSON.stringify(myJSON);">
<div id="json-holder"></div>
</body>
place something like this in your script file json-content.js
var mainjson = { your json data}
then call it from script tag
<script src="json-content.js"></script>
then you can use it in next script
<script>
console.log(mainjson)
</script>
Check this answer: https://stackoverflow.com/a/7346598/1764509
$.getJSON("test.json", function(json) {
console.log(json); // this will show the info it in firebug console
});
If you need to load JSON from another domain:
http://en.wikipedia.org/wiki/JSONP
However be aware of potential XSSI attacks:
https://www.scip.ch/en/?labs.20160414
If it's the same domain so just use Ajax.
Another alternative to use the exact json within javascript. As it is Javascript Object Notation you can just create your object directly with the json notation. If you store this in a .js file you can use the object in your application. This was a useful option for me when I had some static json data that I wanted to cache in a file separately from the rest of my app.
//Just hard code json directly within JS
//here I create an object CLC that represents the json!
$scope.CLC = {
"ContentLayouts": [
{
"ContentLayoutID": 1,
"ContentLayoutTitle": "Right",
"ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/right.png",
"ContentLayoutIndex": 0,
"IsDefault": true
},
{
"ContentLayoutID": 2,
"ContentLayoutTitle": "Bottom",
"ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/bottom.png",
"ContentLayoutIndex": 1,
"IsDefault": false
},
{
"ContentLayoutID": 3,
"ContentLayoutTitle": "Top",
"ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/top.png",
"ContentLayoutIndex": 2,
"IsDefault": false
}
]
};
While not being supported, there is an common alternative to get json into javascript. You state that "remote json request" it is not an option but you may want to consider it since it may be the best solution there is.
If the src attribute was supported, it would be doing a remote json request, so I don't see why you would want to avoid that while actively seeking to do it in an almost same fashion.
Solution :
<script>
async function loadJson(){
const res = await fetch('content.json');
const json = await res.json();
}
loadJson();
</script>
Advantages
allows caching, make sure your hosting/server sets that up properly
on chrome, after profiling using the performance tab, I noticed that it has the smallest CPU footprint compared to : inline JS, inline JSON, external JS.
I want to have my initialization code import a JSON file, I don't know if I'm not looking up my question properly but I can't find a solution. Ideally, it would run completely offline. Right now I don't have any additional JavaScript library, so keeping it vanilla would be a plus.
Full context: I'm trying to make a game that runs on JavaScript (using an HTML to display everything), using nothing but local files so it can run offline. The JSON files would be used to import data like maps, characters, equipment, skills, and maybe plain text to make translating easier. It's for the latter purpose that I want to import the JSON files using JavaScript, so I can import the right file based on the language picked.
I'm fairly new to JavaScript.
Two options you have:
Include the JSON within your javascript code itself.
Request the file via an AJAX call.
According to this gist on Github, you can just import the json file just like a .js file.
The JSON needs to be an object as shown in the example below.
This is the example code I just tried:
HTML / JS:
<script type="text/javascript" src="file.json"></script>
<script>
console.log(data);
</script>
JSON:
data = {
"id": 5,
"name": "Marconymous",
"origin": "Switzerland"
}
Easy as using type="module" for script, which allows the use of import.
index.html
<script src="script.js" type="module"></script>
script.js
import jsonData from './json-file.json' assert {type : 'json'};
console.log(jsonData);
json-file.json
{
"name" : "John",
"age" : 26,
"height" : 1.78
}
I'm currently working on a project where I'm creating a playable ad I'd like to upload to Facebook.
According to Facebook's ad specifications: (https://www.facebook.com/business/help/412951382532338?helpref=faq_content)
They only accept a single HTML file of size less than 2mb for uploading. This means I need to inline all external references to a single HTML file. Which brings me to my problem:
In order to speed up development I use game engines like PlayCanvas and Phaser Editor. The issue I'm facing with most game engines is that they always have data stored in a JSON file that makes it difficult to reference into an HTML file. Is there any way I can inline this data into my file as well?
JSON data containing a base64 encoded image:
"section": [{
"type": "image",
"key": "logo",
"url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEn.........",
"overwrite": false
}],
"meta": {
"generated": "1543491968969",
"app": "Phaser Editor",
"url": "http://phasereditor.boniatillo.com",
"version": "1.0",
"copyright": "Arian Fornaris (c) 2015,2016"
}
}
Function that references this data in my HTML file:
Level.prototype.preload = function ()
{
this.load.pack('section', 'assets/pack.json');
};
Is there a way I can load the referenced data from the JSON file into this function? I've tried using
<script id="data" type="application/json">
{
JSON data here
}
</script>
and then inlining code inside the braces. Replacing 'assets/pack.json' with this code. I've also tried replacing 'section' with it's respective JSON data but I've not been successful. I hope there's someone out there who can understand how this function works and how it would be possible to inline this data there.
I'm also curious if there are any game engines or softwares that would output a single HTML file that I could use in my development.
I'd like to thank everyone in advance and I appreciate any help in solving this.
I think you can achieve this by creating a HTML field which is hidden and setting it's data- to be an object like this.
<div data-foobar='{"foo":"bar"}'></div>
Check out this link :
http://jsfiddle.net/GlauberRocha/Q6kKU/
I have a project using Spring MVC + AngularJS. All the data is dynamic.
Have some big database of locations in this app.
For SEO purposes, need to generate a static page for each location and put them on SEO-friendly URLs (ex. /localhost/path1/path2/here-is-very-friendly-name)
What is the best way to make it?
Should i just generate a pages separately and put them to some separate folder from the main app (if it is, whats the best way to make it?), or i can use Spring/Angular for that?
(for additional info)
each location's object contains id,name, latitude, longtitude, address, district, city, country.
Actually it's my Angular/SEO experience.
You have to made lots of changes!!
1) Removing # from url
app.config(['$locationProvider', function ($locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
}]);
2) Review your MVC Routing
Till now maybe you had one HomeController for returning index.cshtml and booting up your Angular App.
After removing # from Angular routing, you have to set MapRoute for all of your routes.
Because in this situation the first time you try to visit routes like www.site.com/any_route Angular App not loaded yet so it tries to get page from MVC Routing. But after that $routeProvider do its duties.
3) Use MVC variables for meta tags
For better indexing and being friend with crawlers and bots we have to use MVC variables for initializing website meta tags.
If you set your page title by Angular bindings like <title>{{title}}</title> whenever you want to share your page through social networks you will see {{title}} because social networks can't render sites.
<title>#ViewBag.title</title>
<meta name="Description" content="#ViewBag.description">
<meta name="Keywords" content="#ViewBag.keywords">
<meta property="og:title" content="#ViewBag.title" />
<meta property="og:description" content="#ViewBag.description" />
4) Replace Angular binding for meta tags
Our app is SPA, so after loading Angular we are out of MVC playground.
We have to replace Angular variables with MVC variables.
angular.element('title').remove();
angular.element('meta[name="Description"]').remove();
angular.element('meta[name="Keywords"]').remove();
angular.element('meta[property="og:title"]').remove();
angular.element('meta[property="og:description"]').remove();
var description = angular.element('<meta name="Description" content="{{meta.description}}">');
angular.element('head').prepend(description);
var keyword = angular.element('<meta name="Keywords" content="{{meta.keywords}}">');
angular.element('head').prepend(keyword);
var titleOg = angular.element('<meta property="og:title" content="{{meta.title}}" />');
angular.element('head').prepend(titleOg);
var descriptionOg = angular.element('<meta property="og:description" content="{{meta.description}}" />');
angular.element('head').prepend(descriptionOg);
var title = angular.element('<title ng-bind="meta.title"></title>');
angular.element('head').prepend(title);
$rootScope.$applyAsync(function () {
$compile(title)($rootScope);
$compile(description)($rootScope);
$compile(keyword)($rootScope);
$compile(titleOg)($rootScope);
$compile(descriptionOg)($rootScope);
});
5) use JSON-lD for dynamic contents
If you are familiar with SCHEMA.org you better to use JSON-LD instead of others, because search engines bots can catch and analyse <script type="application/ld+json"></script>s that inserted dynamically after page loaded.
You have to check Schema Dictionary to find the type that is most closer to your data structure.
For example it's my company json-ld:
<script type="application/ld+json">
{
"#context" : "http://schema.org",
"#type" : "Organization",
"name" : "داده کاوان امیرکبیر",
"alternateName" : "ADM | Amirkabir Data Miners",
"description": "شرکت داده کاوان امیرکبیر | تولید کننده نرم افزارهای تحت وب، از قبیل حسابداری آنلاین 'کاج سیستم' ، سیستم مدیریت پروژه 'تسک من' و ...",
"url" : "https://adm-co.net",
"email": "info#adm-co.net",
"logo": {
"#type": "ImageObject",
"url": "http://khoonamon.com/images/ADM_Logo.png",
"caption": "لوگو داده کاوان امیرکبیر",
"width": "2480px",
"height": "1459px"
},
"telephone": "+98-21-44002963",
"address": "تهران، خیابان آیت ا... کاشانی، نبش خیابان عقیل، پلاک 380، طبقه دوم",
"contactPoint" : [{
"#type" : "ContactPoint",
"telephone" : "+98-21-44002963",
"contactType" : "customer service",
"contactOption" : "TollFree",
"areaServed" : "IR",
"availableLanguage" : "Persian"
}],
"sameAs" : [
"https://google.com/+ADMcoNet-GPlus",
"https://www.linkedin.com/company/adm-amirkabir-data-miners-?trk=biz-companies-cym",
"https://instagram.com/AmirkabirDataMiners/",
"https://www.facebook.com/AmirkabirDataMiners",
"http://www.pinterest.com/AmirkabirDM/",
"https://twitter.com/AmirkabirDM",
"https://www.youtube.com/channel/UCQxP0vZA05Pl9GlyXXQt14A/about"
]
}
</script>
Have you tried tools like SEO.js (http://getseojs.com/) and prerender.io (https://prerender.io/). Have you tried those?
I haven't tried it myself but PhantomJs would likely be the best option to be able to do this.
You'll need a dictionary of the endpoints your want to render and their corresponding static filepath names. You'd then iterate over each endpoint, rendering the given path with PhantomJS and then saving the output into the static file.
From what I gather from your question, you haven't actually used these paths on the front-end in your angular app as yet? If this is the case then I'd say that the other option is to actually render them server side via just Spring.
The issue here is that angular is not made with isomorphism (client and server side rendering) in mind. Any proper rendering you want done on the server side that hasn't been built yet, the best option is to use Spring to render it.
Another option is updating to Angular2 which is isomorphic with the help of angular universal. If Spring is not used for rendering and only serves as an API for your app this option will work well.
i didn't done this in java but C#, please notify me if you make it work in java:
i found that piece of code about phantomJs, and:
as our friend said, we enabled html5 mode, we rewrite all the url in C# using write engine which is new to IIS, i keep one specific rule for google request which came with specific query parameter (couldn't find it over net and not much time until work). so i redirect them to this specific page, i read the redirected url, passed it and run it on phantomJS, and wait for result to come back (need to know about running a process and take back the console result of it), then, we removed the ng-app attribute from the application, and pass the raw page to google crawler (we have two kind of redirect code, only one of them worked, at last till that time, one is permanent and other i temporary). the page for your self is so rude to look at, but google only look at your schema and structure, so everything is find with it.
It's long i didn't been around Java, so i can't implement it, i only regain little knowledge on spring, so i'll appreciate if you notify me on any update.
I have a list of specific states I want to load into a dropdown list on page load. Because of this I don't have the need for AJAX and thus want to avoid it. How can I access the json file within my page load?
This is what I have.
My JSON file contains:
[{"States":{"AL" : "Alabama", "AK" : "Alaska", "WI" : "Wisconsin", "WY" : "Wyoming" }}]
How I load it onto my HTML header.
<script type="application/json" src="mystates.json"></script>
How can I access the above with Javascript?
I'll put my comments as answer here.
Using AJAX is the easiest way in case like these, esp. using $.getJSON(..) as #mavili suggested.
If you are unwilling to have an async request, you have two options(in my opinion, YMMV :) )
Have a Javascript function, which takes in one parameter like:
function saveStates(statesObject) {
/* store states here */
}
and then have your states JSON file modified to look like this:
saveStates([{"States":{"AL" : "Alabama", "AK" : "Alaska", ..}..}])
Now, simply include this file as you'd usually do in your HTML.
Or the other option is have your server side script read the the file contents and inject the contents into the HTML (javascript <script> area).
In both of the approaches your JSON file can be separately changed.