Is there any way to generate where condition based on user input dynamically.I have a select box with the option '>','<','equals','starts with','ends with'.Based on this condition where clause should be generated and query should be executed.Please help me.i need examples.
since i have around 80 columns in my table i cant use if else loop.
function querymap()
{
var querypass=document.getElementById('query-pass').value.replace(/'/g, "\\'");
if(querypass=='hhSanitHouseType')
{
var operator=document.getElementById('operatorstring').value.replace(/'/g, "\\'");
if(operator=='>')
{
var textvalue=document.getElementById("text-value").value.replace(/'/g, "\\'");
layer.setQuery("SELECT 'geometry',hhSanitHouseType FROM " + tableid + " WHERE 'hhSanitHouseType' > '" + textvalue + "'");
}
}
else
{
alert("false");
}
}
Maybe you can check this example, especially the function generateWhere(columnName, low, high).
You don't have to use if/else for your operator, just check for a valid input (i.e. that the operator is one of '>','<','equals','starts with','ends with') and then pass it directly to your query, something like that
var operator = ...;
var textvalue = ...;
layer.setQuery("SELECT 'geometry',hhSanitHouseType FROM " + tableid + " WHERE 'hhSanitHouseType'" + operator + " '" + textvalue + "'");
Related
i want to fetch the text from shadow element of Dom
http://prntscr.com/e9smzg
I have tried below code but its not working..
public String ShadowRootElement(String str) {
WebElement ele = (WebElement) ((JavascriptExecutor) driver).executeScript("return arguments[0].shadowRoot",getElementByXpath(str));
return ele.findElement(By.xpath("//div[#id='inner-editor']")).getText().toString();
}
Please refer attached screenshot link for html code.
public String getEmailId(String str){
return ShadowRootElement(Repo.get("ipEmailId"));
}
First of all, the way you call ele.findElement(By.xpath("//div[#id='inner-editor']")).getText().toString(); is troublesome.
To locate elements under shadow root node,By.xpath() won't work. Only By.id() & By.cssSelector() will work as valid locators. Please refer to this post for more details.
Secondly (and unfortunately), I found even if you can locate the node under shadow root, element.getText() method would return an empty string.. Simply put it doesn't work for me either :-(
you will not be able to use xpath with shadowroots, since xpath is applied to DOM
Here, you can pull back all the elements, then use css or other to check if text exists, eg (use driver instead of session, since I wrap my driver):
public static String getAllShadowRootsText(DriverSessions session, String rootNode)
{
String elsText = "";
try {
List<SearchContext> sroots = getAllShadowRoots(session, rootNode);
for(SearchContext sroot : sroots){
// we have to specify the elements with shadowroot children, we cant just get all *
List<WebElement> els = sroot.findElements(By.cssSelector(validDomTypes));
for(WebElement el : els) {
elsText = elsText + el.getText();
}
}
}
catch (Exception e) {} // we might want to loop this, pages change and shadow roots move / go stale
return elsText;
}
public static List<SearchContext> getAllShadowRoots(DriverSessions session, String rootNode)
{
String script = ""
+ "function getShadowRoots (node, sroots, func) { "
+ "var done = func(node); "
+ "if (done) {return true;} "
+ "if ('shadowRoot' in node && node.shadowRoot) { "
+ "sroots.push(node.shadowRoot); "
+ "var done = getShadowRoots(node.shadowRoot, sroots, func); "
+ "if (done) {return true;} "
+ "} "
+ "node = node.firstChild; "
+ "while (node) { "
+ "var done = getShadowRoots(node, sroots, func); "
+ "if (done) {return true;} "
+ "node = node.nextSibling; "
+ "} "
+ "} "
+ "try { "
+ "sroots = new Array(); "
+ "getShadowRoots("+rootNode+", sroots, function (node, sroots) {}); "
+ "return sroots;"
+ "} "
+ "catch(err){return null};";
JavascriptExecutor js = (JavascriptExecutor)session.getDriver();
#SuppressWarnings("unchecked")
List<SearchContext> els = (List<SearchContext>) js.executeScript(script);
return els;
}
I'm building a Flash AIR application that will be a kiosk installation for accepting visitor comments, and then displaying previous visitor's comments back. This needs to be highly graphically styled, so returning the query/SQL results back into a datagrid isn't a suitable end result. The database is simply the local one created by the Flash application since this is a non-networked kiosk installation.
I've seen many comments talking about datagrids, and I've seen code that will display all the query results back as a single string - but I'm hoping to populate (without clicking on a datagrid) a series of dynamic text fields with the results of my query.
The Insert statement is working great:
function addData(): void
{
insertStmt = new SQLStatement();
insertStmt.sqlConnection = conn;
var sqlAdd: String = "";
sqlAdd += "INSERT INTO comments (firstName, lastName, homeTown, comment, avatarID, tagID) ";
sqlAdd += "VALUES ('" + inputFirstName + "', ";
sqlAdd += "'" + inputLastName + "', ";
sqlAdd += "'" + inputHomeTown + "', ";
sqlAdd += "'" + inputComment + "', ";
sqlAdd += inputAvatarID + ", ";
sqlAdd += inputTagID;
sqlAdd += ")";
insertStmt.text = sqlAdd;
insertStmt.addEventListener(SQLEvent.RESULT, insertResult);
insertStmt.addEventListener(SQLErrorEvent.ERROR, insertError);
insertStmt.execute();
}
I'm also able to get my Select statement to work when I click a button:
function getData(event: MouseEvent): void
{
selectStmt = new SQLStatement();
selectStmt.sqlConnection = conn;
var sql: String = "SELECT firstName, lastName, comment FROM comments";
selectStmt.text = sql;
selectStmt.addEventListener(SQLEvent.RESULT, selectResult);
selectStmt.addEventListener(SQLEvent.RESULT, traceResult);
selectStmt.addEventListener(SQLErrorEvent.ERROR, selectError);
selectStmt.execute();
}
Where I'm getting completely stuck is extracting this information and either giving each thing a variable name so I can use it later, or at least put the data into a multidimensional array so I reference data with a syntax like
array[1][firstName]
This is the code I've got isn't quite working:
function selectResult(event: SQLEvent): void
{
selectStmt.removeEventListener(SQLEvent.RESULT, selectResult);
selectStmt.removeEventListener(SQLErrorEvent.ERROR, selectError);
var result: SQLResult = selectStmt.getResult();
// The results grid works so I know I'm getting the data back
resultsGrid.dataProvider = new DataProvider(result.data);
var resultsArray01: Array;
var newResultsRow: Array;
if (result != null)
{
// Iterate through each entry
for each(var entry: Object in result.data)
{
// Trace entry -- this works when I test it
trace(entry.firstName,entry.comment, entry.homeTown);
// Add entries to array -- where I get into troubles
// I get TypeError: Error #1009: Cannot access a property or method of a null object reference.
newResultsRow.push(entry.firstName, entry.comment, entry.homeTown);
resultsArray01.push(newResultsRow);
}
}
}
Sorry if this is longwinded. I'm pretty new to AS3, but fairly good with SQL. Any help is appreciated.
You don't need a multidimensional Array for this. You don't even need to create a loop. You can just store the Results as is.
//Declare variable to store the data
var resultsArray:Array;
var result: SQLResult = selectStmt.getResult();
if (result != null)
{
resultsArray = result.data;
}
Then you can just do this...
trace(resultsArray[1]["firstName"]);
Although it is better to use dot syntax
trace(resultsArray[1].firstName);
I use in a Windows 8 project (js/html) the SQLite3-WinRT library https://github.com/doo/SQLite3-WinRT.
I create a function that is called in a for loop.
I have this error:
SQLiteError: 0x800700aa: eachAsync("INSERT INTO home (id, url, cksum)VALUES (16, 'main_page_2.jpg', 'e0d046ca3421a3c2df328b293ad5981a');", ) database is locked
I think the error is because I create a new connection every iteration of loop, but I don't understand another method. Who can help me?
This is the function:
function insertInDB(dbPath, tbName, arrayCol, arrayVal) {
SQLite3JS.openAsync(dbPath).then(function (db) {
var query = "INSERT INTO " + tbName;
var column = " (";
var values = "VALUES (";
for (var i = 0; i < arrayCol.length; i++) {
if (i == arrayCol.length - 1) {
column = column + arrayCol[i] + ")";
} else {
column = column + arrayCol[i] + ", ";
}
}
for (var i = 0; i < arrayVal.length; i++) {
if (i == arrayCol.length - 1) {
values = values + arrayVal[i] + ");";
} else {
values = values + arrayVal[i] + ", ";
}
}
query = query + column + values;
return db.eachAsync(query).done(function () {
console.log("Ok");
db.close();
},
function (error) { console.log(error); },
function (progress) { });
});
}
and this is the loop that call a previous function:
listHome.forEach(function(value, index, array){
var valconfig = new Array(value.id, "'" + value.url + "'", "'" + value.cksum + "'");
console.log("id=" + value.id + " url=" + value.url + " ck=" + value.cksum);
insertInDB(sqlPath, "home", colconfig, valconfig);
})
If I'm reading this correctly, your calling code is iterating over a list of values synchronously. listHome.forEach will call insertInDB for each item in listHome ... but it doesn't wait for insertInDB to return before making the next call to insertInDB.
Inside insertInDB you have call to SQLite3JS.openAsync and db.eachAsync - both asynchronous methods. After perusing SQLite3JS a little bit (which looks pretty cool), both of those methods return promises, where internally they call into a WinRT component. Great design.
So this is what I suspect is happening: one of the asynchronous calls in insertInDB puts a lock on the database. However, insertInDB returns control back to the listHome.forEach loop as soon as it hits the first asynchronous method call. If the lock on the database remains once forEach gets to the next item in listHome, then the operation will attempt to write to a locked database. Hence the error.
I'll think about this a little bit and see if I can come up with a solution.
-- edit --
Okay, I have a solution that might work for you. You might want to create a "DataBaseHelper" class that will queue up the transactions that you need to make in the database.
Here's a rough prototype that I threw together:
[Replaces your foreach loop]
DBHelper.queueUpdates(listHome);
[DBHelper module definition]
(function () {
var _queue;
function queueUpdates(array) {
_queue = array;
scheduleUpdates();
}
function scheduleUpdates() {
if (_queue.length > 0) {
var transaction = _queue.pop();
insertInDB("path", "table", "column", transaction);
}
}
function insertInDB(dbPath, tbName, arrayCol, arrayVal) {
return SQLite3JS.openAsync(dbPath).then(function (db) {
// Construct your SQL query ...
return db.eachAsync(query).done(function () {
db.close();
scheduleUpdates();
},
function (error) { console.log(error); },
function (progress) { });
});
}
WinJS.Namespace.define("DBHelper", {
queueUpdates: queueUpdates
})
})();
Is it possible to return a WebElement's xpath?
Not directly from WebDriver, but you can fake it if you really need to:
public String getElementXPath(WebDriver driver, WebElement element) {
return (String)((JavascriptExecutor)driver).executeScript("gPt=function(c){if(c.id!==''){return'id(\"'+c.id+'\")'}if(c===document.body){return c.tagName}var a=0;var e=c.parentNode.childNodes;for(var b=0;b<e.length;b++){var d=e[b];if(d===c){return gPt(c.parentNode)+'/'+c.tagName+'['+(a+1)+']'}if(d.nodeType===1&&d.tagName===c.tagName){a++}}};return gPt(arguments[0]).toLowerCase();", element);
}
The Javascript is from this post, minified to fit on one line. It may not be perfect, but could give you an idea of where to go. Most drivers implement the JavascriptExecutor interface and have the capability of executing Javascript in the browser. executeScript can return any primitive JavaScript type, an HTML element, or non-nested list of any of the preceding.
Not all browsers support xpath the same way, so be careful if using these xpaths to select elements. Also, not all browsers have native xpath support (cough IE cough), so it was faked in that case.
If WebElement was found by By.xpath:
on Java:
public static String GetWebElementXpath(WebElement El) throws AssertionError{
if ((El instanceof WebElement)){
Object o = El;
String text = o.toString();
/* text is smth like this
[[FirefoxDriver: firefox on WINDOWS (9170d4a5-1554-4018-adac-f3f6385370c0)] -> xpath: //div[contains(#class,'forum-topic-preview')]//div[contains(#class,'small-human')]]
*/
text = text.substring( text.indexOf("xpath: ")+7,text.length()-1);
return text;
}else { Assert.fail("Argument is not an WebElement, his actual class is:"+El.getClass()); }
return "";
}
Both of the above answers suffer from the same problem. By returning the completed XPath with the .toLowerCase() function called, any XPath containing an id with a capital letter will not work.
Example: //div[#id="deviceblock-1111"] will not work on tag <div id="deviceBlock-1111">
You could however just remove the .toLowerCase() call off the return but you'll end up with XPath's looking like this: //DIV[#id="deviceBlock-1111"]/DIV[2]/SELECT[1]/OPTION[5]
To solve this use the function below.
public String GetElementXPath(WebElement element, WebDriver driver)
{
return (String) ((JavascriptExecutor) driver).executeScript(
"getXPath=function(node)" +
"{" +
"if (node.id !== '')" +
"{" +
"return '//' + node.tagName.toLowerCase() + '[#id=\"' + node.id + '\"]'" +
"}" +
"if (node === document.body)" +
"{" +
"return node.tagName.toLowerCase()" +
"}" +
"var nodeCount = 0;" +
"var childNodes = node.parentNode.childNodes;" +
"for (var i=0; i<childNodes.length; i++)" +
"{" +
"var currentNode = childNodes[i];" +
"if (currentNode === node)" +
"{" +
"return getXPath(node.parentNode) +
'/' + node.tagName.toLowerCase() +
'[' + (nodeCount+1) + ']'" +
"}" +
"if (currentNode.nodeType === 1 && " +
"currentNode.tagName.toLowerCase() === node.tagName.toLowerCase())" +
"{" +
"nodeCount++" +
"}" +
"}" +
"};" +
"return getXPath(arguments[0]);", element);
}
This will return a correctly formatted, unique XPath from your WebElement.
//div[#id="deviceBlock-1111"]/div[2]/select[1]/option[5]
I would comment directly on dflems' answer, but I do not have the reputation to do so.
Converting the entire xpath to lower case is fine unless the xpath contains an id value that is not all lower-case. Below is a modified version of dflems' Javascript, but in Python instead of Java:
def get_xpath_from_element(driver, element):
return driver.execute_script("gPt=function(c){if(c.id!==''){return'id(\"'+c.id+'\")'}if(c===document.body){return c.tagName}var a=0;var e=c.parentNode.childNodes;for(var b=0;b<e.length;b++){var d=e[b];if(d===c){return gPt(c.parentNode)+'/'+c.tagName.toLowerCase()+'['+(a+1)+']'}if(d.nodeType===1&&d.tagName===c.tagName){a++}}};return gPt(arguments[0]);", element)
xpath selenium python javascript
public String getElementXPath(WebDriver driver, WebElement element) {
String javaScript = "function getElementXPath(elt){" +
"var path = \"\";" +
"for (; elt && elt.nodeType == 1; elt = elt.parentNode){" +
"idx = getElementIdx(elt);" +
"xname = elt.tagName;" +
"if (idx > 1){" +
"xname += \"[\" + idx + \"]\";" +
"}" +
"path = \"/\" + xname + path;" +
"}" +
"return path;" +
"}" +
"function getElementIdx(elt){" +
"var count = 1;" +
"for (var sib = elt.previousSibling; sib ; sib = sib.previousSibling){" +
"if(sib.nodeType == 1 && sib.tagName == elt.tagName){" +
"count++;" +
"}" +
"}" +
"return count;" +
"}" +
"return getElementXPath(arguments[0]).toLowerCase();";
return (String)((JavascriptExecutor)driver).executeScript(javaScript, element);
}
There is a way to get the elements XPath without the use of JavaScript.
Define starting point of outer XPath, for example body tag.
Check all possible inward tags with selenium for NoSuchElementException.
Check getText for the lists of XPaths generated.
win
public static String getXPathFromElement(WebElement element) {
String elementDescription = element.toString();
return elementDescription.substring(elementDescription.lastIndexOf("-> ") + 3, elementDescription.lastIndexOf("]"));
}
Web element toString() looks like this:
'[[FirefoxDriver: firefox on WINDOWS (ceb69f9f-bef4-455d-b626-ab439f195be6)] -> id: pageBeanfundDescription]'
I just extract the id/xpath.
/**
* This method return By reference for the WebElement passed to it as a parameter.
* #param element
* #return
*/
public static By convertWebElementToByReference(WebElement element)
{
By byLocator = null;
String elementDescription = element.toString();
String elementTypeAndValue[] = (elementDescription.substring(elementDescription.lastIndexOf("-> ") + 3, elementDescription.lastIndexOf("]"))).split(":");
switch (elementTypeAndValue[0].trim())
{
case "id": byLocator = By.id(elementTypeAndValue[1].trim());
break;
case "xpath": byLocator = By.xpath(elementTypeAndValue[1].trim());
break;
case "link text": byLocator = By.linkText(elementTypeAndValue[1].trim());
break;
case "tag name": byLocator = By.tagName(elementTypeAndValue[1].trim());
break;
case "class name": byLocator = By.className(elementTypeAndValue[1].trim());
break;
case "partial link text": byLocator = By.partialLinkText(elementTypeAndValue[1].trim());
break;
case "name": byLocator = By.name(elementTypeAndValue[1].trim());
break;
case "css selector": byLocator = By.cssSelector(elementTypeAndValue[1].trim());
break;
default:
throw new RuntimeException("Invalid locator type: " + elementTypeAndValue[0].trim());
}
return byLocator;
}
How can I keep the values of ;ctrlIDhdnImageSourceArrayJs,ctrlIDhdnElementsArayJsHidden during a web page life-cycle...
"<script language = javascript>
debugger;
var ctrlIDhdnImageSourceArrayJs = '" + this.hdnImageSourceArrayJs.ClientID + #"';
var ctrlIDhdnElementsArayJsHidden = '" + this.hdnElementsArayJsHidden.ClientID + #"';
var loaderF = function getImagesData()
{
var fieldNamesList=[" + fieldNames + #"];
return KrediKartUtils.LoadImagesData('0','" + KrediKartiRow.Row.SmartPenFormNo + #"',fieldNamesList,LoadImagesDataCallBack);
};
function LoadImagesDataCallBack()
{
if(images.length > 0)
{
var numImages = 10; /*10 ar 10 ar göster*/
while(images.length > 0 && numImages-- > 0)
{
document.getElementById(elements.shift()).src =images.shift();
}
/* setTimeout(fetchImages, 1000); *//*1sn de bir*/
LoadImagesDataCallBack();
}
}
if('False' == '" + Page.IsPostBack.ToString() + #"')
{
var images=[" + imageSourceArrayJs + #"];
var elements=[" + elementsArayJs + #"];
document.getElementById(ctrlIDhdnImageSourceArrayJs).value="""+imageSourceArrayJs+#""";
document.getElementById(ctrlIDhdnElementsArayJsHidden).value="""+elementsArayJs+#""";
window.onload = loaderF;
}else{
var images=[document.getElementById(ctrlIDhdnImageSourceArrayJs).value];
var elements=[document.getElementById(ctrlIDhdnElementsArayJsHidden).value];
LoadImagesDataCallBack();
}
</script>";
To keep any value or values during a new request, you will need to include those values with the request.
This means that for a GET, you need to include the values in the querystring
?myValue=1&myArray=1,2,3,4,5
And for a POST you need to append your values to the posted data (usually by placing them inside form fields during the "onsubmit" event.
You can then either process these server side and write out their value to the page or retrieve them from the document.location using JavaScript.