I'm a beginner in coding and I'm trying to parse an XML file, hosted on GitHub, using JavaScript, to extract, for instance, the information contained in the <author> node nested in the <book id="bk102"> node.
I'm aware there are several similar questions in Stackoverflow, I read many of them but what I am trying to do is to extract data from the above-mentioned XML file, using only built-in JavaScript functions.
Honestly, I don't know if it is even possible but I'll explain a bit more in details what I tried to do in order to give you the whole picture.
Why I can use only JS built-in functions?
I'm developing a dynamic survey form using a data collection platform called Fulcrum.
Fulcrum allows to write JavaScript code (with some custom functions) in its 'Data events' module in order to interact with the fields and calculations contained in the survey form itself.
The 'Data events' module in Fulcrum doesn't allow me to install additional packages. For this reason, I cannot install, for example, xml-js library, as suggested here, to use the built-in JavaScript JSON functions or I cannot use DOMParser() interface, among others, since Fulcrum wouldn't recognize it.
From where I started?
Reading Fulcrum documentation, I found out I can use a custom function called REQUEST and I referred to the following example. The Fulcrum custom functions are identified with CAPITAL LETTERS.
// This example looks up the place name from OpenStreetMap when the location changes and fills in a text
// field with the place name. Replace 'place_name' below with a text field on your form.
ON('change-geometry', function(event) {
var options = {
url: 'https://nominatim.openstreetmap.org/search/' + LATITUDE() + ',' + LONGITUDE(),
qs: {
format: 'json',
polygon: 1,
addressdetails: 1
}
};
REQUEST(options, function(error, response, body) {
if (error) {
ALERT('Error with request: ' + INSPECT(error));
} else {
var data = JSON.parse(body);
if (data.length) {
SETVALUE('place_name', data[0].display_name);
}
}
});
});
The only issue here is that this example reads form a JSON file, while I need to read from a XML file.
What I tried?
I tried to edit the function in the example to make it work with an XML file. This is how I modified it.
ON('click', 'import_xml', function(event) {
var options = {
url: 'https://gist.githubusercontent.com/Ram-N/5189462/raw/46db0b43ad7bf9cbd32a8932f3ab981bd4b4da7c/books.xml',
qs: {
format: 'xml'
}
};
REQUEST(options, function(error, response, body) {
if (error) {
ALERT('Error with request: ' + INSPECT(error));
} else {
var data = body;
if (data.length) {
SETVALUE('test_field_xml', data);
}
}
});
});
And it works! Partially... When I click the import_xml hyperlink (refer to 1 below), I'm able to import the whole body of the XML file in the test_field_xml field (refer to 2 below) but I dont' really know how to extract only the information contained in the <author> node nested in the <book id="bk102"> node.
Any advice on how to proceed would be extremely helpful. Thank you, Stefano.
EDIT1:
I think I found a very "homemade" and partial solution, also not very practical or nice but it works. I edited the code above as shown below:
ON('click', 'import_xml', function(event) {
var options = {
url: 'https://gist.githubusercontent.com/Ram-N/5189462/raw/46db0b43ad7bf9cbd32a8932f3ab981bd4b4da7c/books.xml',
qs: {
format: 'xml'
}
};
REQUEST(options, function(error, response, body) {
if (error) {
ALERT('Error with request: ' + INSPECT(error));
} else {
var data = body;
var test1 = body.substring(
body.lastIndexOf('<book id="bk102">') + 24,
body.lastIndexOf('<book id="bk103">') - 15
);
var test2 = test1.substring(
test1.lastIndexOf('<author>') + 8,
test1.lastIndexOf('</author>') - 0
);
if (data.length) {
SETVALUE('test_field_xml', test2);
}
}
});
});
In your opinion, could this be done in a better and more efficient way?
You have said you are allowed to write Javascript code, but that you can't install additional Javascript packages. So the answer is to download an open-source XML parser written in Javascript and add it to your code as if it was part of the code you had written yourself.
Related
I was stuck on a problem which probably plenty of new SuiteScript hackers will.
As writted on the official doc of SuiteScript p. 243, there's this JS for retrieve a record with GET method.
// Get a standard NetSuite record
function getRecord(datain) {
return nlapiLoadRecord(datain.recordtype, datain.id); // e.g recordtype="customer", id="769"
}
// http://rest.na1.netsuite.com/app/site/hosting/restlet.nl?script=22&deploy=1&recordtype=customer&id=769
But, when I was trying the EXACT snippet on NetSuite side, datain.recordtypewas undefined. (and return should only return text, BTW.)
Fortunately, I've found the solution by myself. Check my answer below.
In this snippet (the same as above) ...
function getRecord(datain) {
return nlapiLoadRecord(datain.recordtype, datain.id); // e.g recordtype="customer", id="769"
}
// http://rest.na1.netsuite.com/app/site/hosting/restlet.nl?script=22&deploy=1&recordtype=customer&id=769
—
SuiteScript was filling datain not as an object nor JSON but as a string (for reason I still ignore.)
What you have to do so is just parse it before, then access the JSON with dot notation.
function getRecord(datain) {
var data = JSON.parse(datain); // <- this
return "This record is a " + data.recordtype + " and the ID is " + data.id;
}
// http://rest.na1.netsuite.com/app/site/hosting/restlet.nl?script=22&deploy=1&recordtype=customer&id=769
I've changed the return statement in the solution because SuiteScript gives me error when I try to return something what isn't a text.
OR
As egrubaugh360 said, specify the Content-Type is application/json on your query script (the one who make call to your SuiteScript script)
So it'll give something like this if you're dealing with Node.js like me :
var options = {
headers: {
'Authorization': "<insert your NLAuth Authentification method here>",
"Content-Type" : "application/json" // <- this
}
}
https.request(options, function(results) {
// do something with results.
}
Hope this will help someone.
I have a server side function which returns content of HTML page:
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
Meteor.methods({
sayHello: function() {
var response = Meteor.http.call("GET", "http://google.com");
return response;
}
});
});
And I have client code where I am trying to get title from this HTML page:
'click .add_tag' : function(e,t) {
//Session.set('editing_tag_id', e.target.id);
Meteor.call("sayHello", function(err, response) {
var title = $(response.content).find("title").text();
var title2 = $(response).find("title").text();
var title3 = response.content.match(/<title[^>]*>([^<]+)<\/title>/)[1];
alert(title3);
});
I would like to get jQuery version ('title' or 'title2'), but it doesn't works. It returns empty string.
'Title3' - version works fine, but I don't like regexps. :)
Is there any way to make 'jQuery'-versions works ?
As requested, I will reiterate my comment as an answer...
I would stick with the regex, even though you don't like it. There is a huge overhead of constructing a DOM element that is essentially an entire page, purely for the purpose of parsing a small amount of text. The regex is more lightweight and will perform adequately in slower browsers or on slower machines.
Wrap response.content in a <div> and then do a selection off of that. This way you have a proper structure to start from rather than an array that you might actually be getting.
var $wrap = $("<div></div>").html(response.content);
$wrap.find("title").text();
An example of what is probably going on: http://jsfiddle.net/UFtJV/
Don't forget one thing : you should never return HTML to client. You should return Json (or even Xml) that your client will transform into Html using Template.
You are doing like a lot of dev doing Bad Ajax.
Don't forget : "only data on wire, not display".
So there should not be any problem coz, on response you just have to take data from Json formatted response and inject it inside your Template.
i am a Java Developer and i need to create a SIMPLE app, as i need this to run into ios & Android i decided to try it using lungoJS, my main problem is that i dont know much JavaScript.. :(
well i have created the prototipe of the app using lungo, but now i need to fill a list with the response (on Json) from my server. I saw in lungos api the function that is used to get a Json request. looks like this:
var url = "http://localhos:8080/myService";
var data = {id: 25, length: 50};
var parseResponse = function(result){
//Do something
};
Lungo.Service.json(url, data, parseResponse, "json");
//Another example
var result = Lungo.Service.json(url, "id=25&len=50", null, "json");
my http request is indexed from 1 to 4 so for each element would be "www.myapp.com/api/1" "www.myapp.com/api/2"
....
my question is, hoy could i get the answer (json) of my request and how do i select items for example if i only want the "name" or "surname"...
thanks, hope some1 could help me :)
I solved my problem long time ago, i will share it:
function some_function(callback) {
var my_number = $$.get('http://app.com/applications/3.json',{ }, function(api) {
obj=api;
template="{{#name}}\
\
{{/name}}";
html=Mustache.render(template,obj);
$$('section#main article#main-article').html(html); //Painting Json obtained on my HTML
}
);
;
callback(my_number);
}
// call the function
some_function(function(num) {
// this anonymous function will run when the
// callback is called
console.log("callback called! " + num);
});
This code uses the obtained Json to Prototype HTML, useful to load images or data from server and not stored on local.
BR, Kike
I've started using Newtonsoft.Json.Schema.JsonSchemaGenerator along with various property attributes over in my C# code to help keep my client script DRY. What I'd like to do is create a default initialized object client-side based on the schema from the server. This would be useful for, say, when the user clicks 'New Foo' to add a new entry into a table.
Obviously I can just code it up to iterate the .Properties and build up the new object, which is what I'm doing at the moment. However I'd prefer to avoid reinventing any wheels.
Are there any JS libraries for working with JSON schema that will do this, among other nifty things I've yet to realize I need?
1/29/2013 UPDATE
Some people have attempted to answer my question and have been off base, and as a result have received some negative feedback from the SO community. So let me attempt to clarify things. Here is the challenge:
In JS client script, you have an object that represents the JSON Schema of another object. Let's say, this came from the server via JSON.NET and is the representation of a C# class.
Now, in the JS client script, create one of these objects based upon the JSON Schema. Each field/property in the object must be default initialized according to the schema, including all contained objects!
BONUS: Bind this new object to the UI using MVVM (eg Knockout). Change some of the fields in response to user input.
Send this new object to the server. The server-side code will add it to a collection, database table, whatever. (Yes, the object will be sent as JSON using Ajax -- we can assume that)
No duplication! The only place where the class is defined is in the server-side code (C# in my example). This includes all metadata such as default values, description text, valid ranges, etc.
Yes there is (I tried it with NodeJS):
JSON Schema defaults
Link updated.
i think...you have to use two way binding with your HTML code...so, once your client side change you will get on your costume js file.
check here for knockout js.
Knock Out JS Link
and on C# code use : $("#urlhidden").val() OR Document.GetElemenyByID("#urlhidden").val().
here you will get array/list or textbox value
Use json with Ko
create new viewmodel for knockout js which you will get the idea about on above link.
and create a json call
like:
self.LoadMAS_Client = function () {
try {
var params = { "clientID": ClientId };
$.ajax({
type: "POST",
url: "http://" + ServerString + "/Services/LogisticsAppSuite-Services-Web-Services-MasClientService.svc/Json/GetAllLevelSubClients",
contentType: 'application/json',
data: JSON.stringify(params),
dataType: 'json',
async: false,
cache: false,
success: function (response) {
// in response u will get the data.and use as per your requirement.
eg. self.SelectedClient(response.your value);
},
error: function (ErrorResponse) {
}
});
}
catch (error) {
}
};
================================New Update ==========================================
i think..one way you can do...get data on xml format at C# code and covert into json string...check below code // To convert an XML node contained in string xml into a JSON string
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
// To convert JSON text contained in string json into an XML node
XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(json);
Anyone can tell me what I'm doing wrong?
I am creating a simple system to get people in and out of user groups and for that purpose I am using Dojo and Perl. (If I could have it my way it would be PHP but I am not the boss.)
At the moment I only use three files, one for Perl, one for JavaScript and one for CSS styles.
The start of the CGI script routes to different functions as follows:
if ($search = $cgi->param('psearch')) {
dbConnect();
jsonSearchPersons($search);
dbDisconnect();
} elsif ($user_id = $cgi->param('person')){
dbConnect();
create_form($user_id);
dbDisconnect();
} elsif ($user_id = $cgi->param('saveuser')) {
save_user();
} else {
mainPage();
};
...
sub save_user {
print $cgi->header(-type=>'text/plain',-charset=>'utf-8');
print("success");
}
The problem I have now is when I want to save the new groups for the user though an Ajax call (a call to this URL: users.cgi?saveuser=xx). This should (in my point of view) be a POST call, so I made this and tried to append the resulting HTML/text in a <div> but it didn't work:
dojo.xhr.post({
url: "/cgi-bin/users.cgi?saveuser="+user_id,
content: {
new_groups: group_ids.toString()
},
load: function(html_content){
var element = document.getElementById("test_area");
element.innerHTML = html_content;
},
error: function(){
alert("An error has occured during the save of new user groups.");
}
});
When I do it with dojo.xhr.get(); it works fine, but when I do it with the POST it's like it jumps over that part of the if statement and just appends the mainPage() function. Is there something basic I don't understand between Dojo and Perl? Do I have to set up the pages so it will accept a POST call? Or what am I doing wrong?
NOTE: This is the first "system" I have made though Dojo and Perl. (I'm normally a PHP/jQuery kind of guy who makes everything UI by hand, so I'm kinda new to it.)
Try adding the saveuser-parameter to the content-object of dojo.xhrPost instead of passing it in the url.
You're trying to pass the saveuser-parameter as GET and the other as POST, maybe that confuses your serverside part.
Try it like that:
dojo.xhr.post({
url: "/cgi-bin/users.cgi",
content: {
new_groups: group_ids.toString(),
saveuser: user_id
},
load: function(html_content){
var element = document.getElementById("test_area");
element.innerHTML = html_content;
},
error: function(){
alert("An error has occured during the save of new user groups.");
}
});
Found a solution.
The problem was my javascript. When posting to a perl script you use $cgi=new CGI; and all that. This takes both GET and POST variables and validates them. In my javascript/dojo code, i then used an url with GET vars and then made a POST as well. This meant perl could not find out (or was mixing) the two variable types. So when i changed my ajax code (as below) it worked, since $cgi->param('saveuser') both fetches GET and POST of "saveuser" (no change to the perl was needed):
dojo.xhr.post({
url: "/cgi-bin/users.cgi",
content: {
saveuser: user_id,
new_groups: group_ids.toString()
},
load: function(html_content){
var element = document.getElementById("test_area");
element.innerHTML = html_content;
},
error: function(){
alert("An error has occured during the save of new user groups.");
}
});
Kinda wack bug, but im glad since it works great now :D
Line 675 of CGI.pm :
# Some people want to have their cake and eat it too!
# Uncomment this line to have the contents of the query string
# APPENDED to the POST data.
# $query_string .= (length($query_string) ? '&' : '') . $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'};
Made me laugh !