ECMA in Datapower - javascript

anybody know how to access XML data using xpath expression in ECMA Script(datapower)?
IBM infocenter doesn't have this information on how to access XML data
Please provide if you have any sample script for accessing XML data
Thanks

GatewayScript doesn't support any XML Dom in the ECMA (Node.js) implemented.
I have however used the modules XPATH and DOM with great success.
Download XMLDom (https://github.com/jindw/xmldom) and Xpath (https://github.com/goto100/xpath) Node.js modules and add the following scripts to your DP directory:
dom-parser.js
dom.js
sax.js
xpath.js
To use it in DataPower GWS you first need to get the XML data from INPUT:
// This is where we start, grab the INPUT as a buffer
session.input.readAsBuffers(function(readAsBuffersError, data) {
if (readAsBuffersError) {
console.error('Error on readAsBuffers: ' + readAsBuffersError);
session.reject('Error on readAsBuffers: ' + readAsBuffersError);
} else {
if (data.slice(0,5).toString() === '<?xml') {
console.log('It is XML!');
parseXML(data);
}
} //end read as buffers error
}); //end read as buffer function
function parseXML(xml) {
// Load XML Dom and XPath modules
var select = require('local:///xpath.js');
var dom = require('local:///dom-parser.js');
var doc = new dom.DOMParser().parseFromString(xml.toString(), 'text/xml');
// Get attribute
var nodes = select(doc, "//root/element1/#protocol");
try {
var val = nodes[0].value.toString();
console.log('found xml attribute as ['+val+']');
} catch(e) {
// throw error here
}
// Get an element
nodes = select(doc, "//root/element1/child1");
try {
var val = nodes[0].firstChild.data;
console.log('elemnt found as ['+val+']');
} catch(e) {
//throw error here
}
}
That should be a working sample... You need to change the path for the modules if you move them.
I have a directory in store:/// where I add my GWS modules.
Hope you'll get it to fly!

At least from 7.0.0 firmware version Gatewayscript is able to work with XPATH and DOM easily. Snippet from the DP store:
//reading body from the rule input
session.input.readAsXML(function (error, nodeList) {
if (error) {
//error behaviour
} else {
var domTree;
try {
domTree = XML.parse(nodeList);
} catch (error) {
//error behaviour
}
var transform = require('transform'); //native gatewayscript module
transform.xpath('/someNode/anotherNode/text()', domTree, function(error, result){
if(error){
//error behaviour
}
//some use of result, for example putting it to output
session.output.write(result);
}
});
});

Related

selectNodes function of ActiveXObject does not work in IE 11

I am trying to get this piece of code written in Javascript to work in IE 11. But when I try to access the length of the node it gives me 0. I am not sure why the below code is not able to find out the <somenode> node in XML. Does anyone have any idea?
try {
doc = new ActiveXObject("Msxml2.DOMDocument.6.0");
var xml_string = '<somenode><child>Hello</child></somenode>
<somenode><child>good bye</child></somenode>';
doc.loadXML(xml_string);
doc.setProperty("SelectionLanguage", "XPath");
var node = doc.selectNodes("/somenode");
console.log("node is "+node.length);
}
catch (e)
{
console.log("inside catch"+e);
}
NOTE: Your XML doesn't have a root element. I've added <xml> as the root.
try {
doc = new ActiveXObject("Msxml2.DOMDocument.6.0");
var xml_string = '<xml><somenode><child>Hello</child></somenode>
<somenode><child>good bye</child></somenode></xml>';
doc.loadXML(xml_string);
doc.setProperty("SelectionLanguage", "XPath");
var node = doc.selectNodes("/xml/somenode");
console.log("node is "+node.length);
}
catch (e)
{
console.log("inside catch"+e);
}

Office js conditional formatting

I am currently trying to implement conditional formatting in Excel using Office JS API 1.6 .I have written the following code to implement text comparison formatting.
function textComparisonFormatting() {
// Run a batch operation against the Excel object model
Excel.run(function (ctx) {
// Create a proxy object for the active worksheet
var sheet = ctx.workbook.worksheets.getActiveWorksheet();
//Queue a command to write the sample data to the specified range
//in the worksheet and bold the header row
var range = sheet.getRange("A2:E8");
var conditionalFormat = range.conditionalFormats.add(Excel.ConditionalFormatType.textComparison);
conditionalFormat.textComparison.load(["rule","format/*","format/fill"]);
//Run the queued commands, and return a promise to indicate task completion
return ctx.sync(conditionalFormat).then(function(conditionalFormat){
conditionalFormat.textComparison.rule.text = "Qtr";
conditionalFormat.textComparison.rule.operator = "BeginsWith";
conditionalFormat.textComparisonformat.fill.color = "red";
});
})
.then(function () {
app.showNotification("Success");
console.log("Success!");
})
.catch(function (error) {
// Always be sure to catch any accumulated errors that bubble up from the Excel.run execution
app.showNotification("Error: " + error);
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
}
The code is throwing InvalidObjectPath error while i am trying to set the color. If i try to set the colors inside Excel.Run(), then it won't work as i am unable to access the object properties. Is there any way by which I can resolve these issues?
Some changes you should make to your code:
You don't need to load anything and sync, because you are writing to the properties, not reading them.
There is no ConditionalFormatType.textComparison. You need ConditionalFormatType.containsText.
Operators are camel-cased: beginsWith, not BeginsWith.
There should be a "." between textComparison and format.
This snippet works:
function applyTextFormat() {
Excel.run(function (context) {
var sheet = ctx.workbook.worksheets.getActiveWorksheet();
var range = sheet.getRange("A2:E8");
var conditionalFormat = range.conditionalFormats
.add(Excel.ConditionalFormatType.containsText);
conditionalFormat.textComparison.format.fill.color = "red";
conditionalFormat.textComparison.rule = { operator: Excel.ConditionalTextOperator.beginsWith, text: "Qtr" };
return context.sync();
});
}
UPDATE: As the OP requested:
The documentation is not yet published on dev.office.com. You need to go to a special branch of the office-js-docs repo on GitHub. Open this page and see all the files of the form conditional*.md:
ExcelJs_OpenSpec/reference/excel

Update HTML object with node.js and javascript

I'm new to nodejs and jquery, and I'm trying to update one single html object using a script.
I am using a Raspberry pi 2 and a ultrasonic sensor, to measure distance. I want to measure continuous, and update the html document at the same time with the real time values.
When I try to run my code it behaves like a server and not a client. Everything that i console.log() prints in the cmd and not in the browesers' console. When I run my code now i do it with "sudo node surveyor.js", but nothing happens in the html-document. I have linked it properly to the script. I have also tried document.getElementsByTagName("h6").innerHTML = distance.toFixed(2), but the error is "document is not defiend".
Is there any easy way to fix this?
My code this far is:
var statistics = require('math-statistics');
var usonic = require('r-pi-usonic');
var fs = require("fs");
var path = require("path");
var jsdom = require("jsdom");
var htmlSource = fs.readFileSync("../index.html", "utf8");
var init = function(config) {
usonic.init(function (error) {
if (error) {
console.log('error');
} else {
var sensor = usonic.createSensor(config.echoPin, config.triggerPin, config.timeout);
//console.log(config);
var distances;
(function measure() {
if (!distances || distances.length === config.rate) {
if (distances) {
print(distances);
}
distances = [];
}
setTimeout(function() {
distances.push(sensor());
measure();
}, config.delay);
}());
}
});
};
var print = function(distances) {
var distance = statistics.median(distances);
process.stdout.clearLine();
process.stdout.cursorTo(0);
if (distance < 0) {
process.stdout.write('Error: Measurement timeout.\n');
} else {
process.stdout.write('Distance: ' + distance.toFixed(2) + ' cm');
call_jsdom(htmlSource, function (window) {
var $ = window.$;
$("h6").replaceWith(distance.toFixed(2));
console.log(documentToSource(window.document));
});
}
};
function documentToSource(doc) {
// The non-standard window.document.outerHTML also exists,
// but currently does not preserve source code structure as well
// The following two operations are non-standard
return doc.doctype.toString()+doc.innerHTML;
}
function call_jsdom(source, callback) {
jsdom.env(
source,
[ 'jquery-1.7.1.min.js' ],
function(errors, window) {
process.nextTick(
function () {
if (errors) {
throw new Error("There were errors: "+errors);
}
callback(window);
}
);
}
);
}
init({
echoPin: 15, //Echo pin
triggerPin: 14, //Trigger pin
timeout: 1000, //Measurement timeout in µs
delay: 60, //Measurement delay in ms
rate: 5 //Measurements per sample
});
Node.js is a server-side implementation of JavaScript. It's ok to do all the sensors operations and calculations on server-side, but you need some mechanism to provide the results to your clients. If they are going to use your application by using a web browser, you must run a HTTP server, like Express.js, and create a route (something like http://localhost/surveyor or just http://localhost/) that calls a method you have implemented on server-side and do something with the result. One possible way to return this resulting data to the clients is by rendering an HTML page that shows them. For that you should use a Template Engine.
Any DOM manipulation should be done on client-side (you could, for example, include a <script> tag inside your template HTML just to try and understand how it works, but it is not recommended to do this in production environments).
Try searching google for Node.js examples and tutorials and you will get it :)

Catch all JavaScript client-side errors on the server-side

How can I catch any exception that occurs in the client side code like "Pause On Caught Exceptions" on chrome developer tools?
I found the solution!
I have used the C# and MVC.
Add a new class to customize your js files bundle like this:
public class CustomScriptBundle : ScriptBundle
{
public CustomScriptBundle(string virtualPath) : base(virtualPath)
{
Builder = new CustomScriptBundleBuilder();
}
public CustomScriptBundle(string virtualPath, string cdnPath)
: base(virtualPath, cdnPath)
{
Builder = new CustomScriptBundleBuilder();
}
}
And, create another class to change the content of the js files as follows::
class CustomScriptBundleBuilder : IBundleBuilder
{
private string Read(BundleFile file)
{
//read file
FileInfo fileInfo = new FileInfo(HttpContext.Current.Server.MapPath(#file.IncludedVirtualPath));
using (var reader = fileInfo.OpenText())
{
return reader.ReadToEnd();
}
}
public string BuildBundleContent(Bundle bundle, BundleContext context, IEnumerable<BundleFile> files)
{
var content = new StringBuilder();
foreach (var fileInfo in files)
{
var contents = new StringBuilder(Read(fileInfo));
//a regular expersion to get catch blocks
const string pattern = #"\bcatch\b(\s*)*\((?<errVariable>([^)])*)\)(\s*)*\{(?<blockContent>([^{}])*(\{([^}])*\})*([^}])*)\}";
var regex = new Regex(pattern);
var matches = regex.Matches(contents.ToString());
for (var i = matches.Count - 1; i >= 0; i--) //from end to start! (to avoid loss index)
{
var match = matches[i];
//catch( errVariable )
var errVariable = match.Groups["errVariable"].ToString();
//start index of catch block
var blockContentIndex = match.Groups["blockContent"].Index;
var hasContent = match.Groups["blockContent"].Length > 2;
contents.Insert(blockContentIndex,
string.Format("if(customErrorLogging)customErrorLogging({0}){1}", errVariable, hasContent ? ";" : ""));
}
var parser = new JSParser(contents.ToString());
var bundleValue = parser.Parse(parser.Settings).ToCode();
content.Append(bundleValue);
content.AppendLine(";");
}
return content.ToString();
}
}
Now, include your js files in application Bundles with your class:
BundleTable.Bundles.Add(new CustomScriptBundle("~/scripts/vendor").Include("~/scripts/any.js"));
Finally, in a new js file write customErrorLogging function as described below, and add it to your project's main html form:
"use strict";
var customErrorLogging = function (ex) {
//do something
};
window.onerror = function (message, file, line, col, error) {
customErrorLogging({
message: message,
file: file,
line: line,
col: col,
error: error
}, this);
return true;
};
Now, you can catch all exceptions in your application and manage them :)
You can use try/catch blocks:
try {
myUnsafeFunction(); // this may cause an error which we want to handle
}
catch (e) {
logMyErrors(e); // here the variable e holds information about the error; do any post-processing you wish with it
}
As the name indicates, you try to execute some code in the "try" block. If an error is thrown, you can perform specific tasks (such as, say, logging the error in a specific way) in the "catch" block.
Many more options are available: you can have multiple "catch" blocks depending on the type of error that was thrown, etc.
More information here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
see a small example how you can catch an Exception:
try {
alert("proper alert!");
aert("error this is not a function!");
}
catch(err) {
document.getElementById("demo").innerHTML = err.message;
}
<body>
<p id="demo"></p>
</body>
put you code in try Block and try to catch error in catch Block.

requireJS and LESS

I'm using the client-side javascript version of LESS to compile out less code, and would like to continue using this even on the final live site (I know... bad form, but it gives me the ability to allow users to customize a few less variables and have that "theme" their whole app on the fly, seeing as it's a webapp that once loaded never refreshes, I'm thinking the additional second of load time to compile the less is acceptable).
I'm also using requireJS.
The question is:
A) How do I get requireJS to load less code?
B) Does less dispatch any events when compilation is complete? and
C) Is there a way to trigger less to re-compile on command?
Thanks.
I have used the text loader plugin for RequireJS to load the .less file as text, then create a new less.Parser instance to parse the text, then add the style text myself:
(new less.Parser()).parse(lessText, function (err, css) {
if (err) {
if (typeof console !== 'undefined' && console.error) {
console.error(err);
}
} else {
var style = document.createElement('style');
style.type = 'text/css';
style.textContent = css.toCSS();
}
});
You could take a similar approach, but give the style node an ID and remove that ID and then add back another reparsed LESS text when you want on demand.
A caveat: the text plugin can only load text files on demand when the text file is on the same domain as the web page. If you use the RequireJS optimizer, you can inline the text into a built, optimized JS file.
#jrburke: I've put together a quick requirejs plugin based on your code:
define({
version: '0.1',
load: function(name, req, onLoad, config) {
req(['text!' + name, 'base/less'], function(lessText) {
var styleElem;
(new less.Parser()).parse(lessText, function (err, css) {
if (err) {
if (typeof console !== 'undefined' && console.error) {
console.error(err);
}
} else {
styleElem = document.createElement('style');
styleElem.type = 'text/css';
if (styleElem.styleSheet)
styleElem.styleSheet.cssText = css.toCSS();
else
styleElem.appendChild( document.createTextNode( css.toCSS() ) );
document.getElementsByTagName("head")[0].appendChild( styleElem );
}
onLoad(styleElem);
});
});
}
});
"base/less" points to the less source. You could also load this ahead of time, and assume the global less object exists. Ideally, I'd like to pull the less Parser object into this plugin itself so it doesn't create a global at all.
Using this I can do stuff like:
require(['less!global.less'], function(elem) {
});
At which point, global.less has been parsed and added to the page and gives back elem pointing to the style element in case I need to remove or modify it for some reason.
Does anyone have any input or know a better way of doing this?
Cheers
I was having trouble with #nicholas plugin with imports. I fixed it by adding the path of the file to the search path, and set filename for better error messages:
// http://stackoverflow.com/questions/5889901/requirejs-and-less
// enables require(['share/less!whatever.less'], function(elem) {});
define({
version: '0.1',
load: function(name, req, onLoad, config) {
req(['share/text!' + name, 'share/less-1.3.0'], function(lessText) {
var styleElem;
var parser = new(less.Parser)({
filename: name,
paths: [name.split('/').slice(0,-1).join('/') + '/'],
});
parser.parse(lessText, function (err, css) {
if (err) {
if (typeof console !== 'undefined' && console.error) {
console.error(err);
}
} else {
styleElem = document.createElement('style');
styleElem.type = 'text/css';
if (styleElem.styleSheet)
styleElem.styleSheet.cssText = css.toCSS();
else
styleElem.appendChild( document.createTextNode( css.toCSS() ) );
document.getElementsByTagName("head")[0].appendChild( styleElem );
}
onLoad(styleElem);
});
});
}
});

Categories

Resources