Delete using XPath Expression OSB - oracle

I am in a For Each loop in OSB.
The loop is indexed by variable .
I would like to delete node from other xml using the index variable in specific XPath Expression-
./GetListResult/SearchList/Item['{$index}']
It seems that the XPath does not recognize the index variable. How can I use it to specify which node I want to delete?
I google it and found this -
http://blog.darwin-it.nl/2015/06/index-variables-in-replaceinsertdelete.html
There is solution to this problem?

Why not delete using xquery instead?
let $old_items := $body/GetListResult/SearchList/Item
let $new_items := remove($old_items, $index)

Related

How to extract items inside a table using scrapy

I want to extract all the functions listed inside the table in the below link : python functions list
I have tried using the chrome developers console to get the exact xpath to be used in the file spider.py as below:
$x('//*[#id="built-in-functions"]/table[1]/tbody//a/#href')
but this returns a list of all href's ( which I think what the xpath expression refers to).
I need to extract the text from here I believe but appending /text() to the above xpath return nothing. Can someone please help me to extract the function names from the table.
I think this should do the trick
response.css('.docutils .reference .pre::text').extract()
a non-exact xpath equivalent of it (but that also works in this case) would be:
response.xpath('//table[contains(#class, "docutils")]//*[contains(#class, "reference")]//*[contains(#class, "pre")]/text()').extract()
Try this:
for td in response.css("#built-in-functions > table:nth-child(4) td"):
td.css("span.pre::text").extract_first()

xpath query url with one folder depth only

I am using this XPath query succesfully:
//div[(#class="result")]//a[contains(#href,"pinterest.com")]/#href
The URL I am using the XPath query (with simple_html_dom.php) is this one here.
Now, I would like to find results for pinterest.com/one-folder-deep-only and exclude all URLs deeper than one directory, like pinterest.com/one-folder-deep-only/this or pinterest.com/one-folder-deep-only/this/this. I have no idea if there is a way to achieve that. Have googled a lot, but not found anything. Maybe my search terms weren't the best.
Do you have any ideas? Thanks for helping me here.
I am testing the query using the Chrome XPath Helper.
"//" is to evaluate all levels/depths. Instead use only one "/" for the "a" query to only evaluate immediate children
//div[(#id="first-result")]/a[contains(#href,"url.com")]/#href
Note use of / instead of // before the "a" tag.
Try below XPath to select #href from required anchors only:
//a[contains(#href, "url.com") and not(contains(substring-after(./#href, 'url.com/'), "/"))]/#href
Solution for XPath 2.0:
//a[contains(#href, "url.com") and count(tokenize(#href, "/"))=2]/#href
Note that if in real HTML source href starts-with "http://url.com" you should specify =4 instead of =2

Marklogic - how to execute insert and node replace in single xquery

I have provided sample Xquery for insert and node replace Query.
My problem is If I am going to Execute the Query , its only insert the XML first.
even though i am going to execute second time the node will be replaced.
But I want the single execution it will be processed insert and update as well.
sample query :
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
let $a := xdmp:document-insert("/fo.xml", <a>1</a>)
let $b := xdmp:node-replace(fn:doc("/fo.xml")/a, <b>1</b>)
return ($a,$b)
You cannot do that in a single statement. You either need to:
use a multi-statement call (main statements separated by a semi-colon)
do the update in-memory, and passing the updated content to the insert
Regarding 1:
The Application Developers Guide has a section about Semi-Colon as a Statement Separator, but in short it comes down to writing your query as follows:
xquery version "1.0-ml";
xdmp:document-insert("/fo.xml", <a>1</a>)
;
xquery version "1.0-ml";
xdmp:node-replace(fn:doc("/fo.xml")/a, <b>1</b>)
Regarding 2:
There are libraries that provide methods that operate very similar to the xdmp:node-* ones, but operate on content that has not yet been persisted to the database instead. You will need to download those first, and upload them to your modules database in order to use them. The best version I am aware of is https://github.com/ryanjdew/XQuery-XML-Memory-Operations. You can download and install that using MLPM. With that library you could write something like:
import module namespace mem = "http://maxdewpoint.blogspot.com/memory-operations" at "/ext/mlpm_modules/XQuery-XML-Memory-Operations/memory-operations.xqy";
let $a := <a>1</a>
let $b := <b>1</b>
let $updated-a := mem:copy($a) ! (
mem:replace(., $a, $b),
mem:execute(.)
)
return xdmp:document-insert("/foo.xml", $updated-a)
HTH!
Based on grtjn's answer you can do the following:
xdmp:document-insert("/fo.xml", <a>1</a>);
xdmp:node-replace(fn:doc("/fo.xml")/a, <b>1</b>);
Notice the semi-colon at the end of the lines. Those are statement separators. To understand more about statement separators (and transcations in general) you can refer to the following resource: https://docs.marklogic.com/guide/app-dev/transactions#id_11899.

Handling Dynamic Xpath

Am automating things using Selenium. Need your help to handle Dynamic Xpath as below:
Driver.findElement(By.xpath("//[#id='INQ_2985']/div[2]/tr/td/div/div[3]/div")).click();
As above INQ_2985 changes to 2986,2987,2988 etc during each run
HTML CODE:
< div> class="context-menu-item-inner" style="background-image:url(../images/productSmall.png);">Tender Assignment < /div>
Tried different combinations as below but with no success:
// Driver.findElement(By.name("//input[#name='Tender Assignment']")).click();
// Driver.findElement(By.className("context-menu-item-inner")).click();`
Can you help me on this.
you can try using contains() or starts-with() in xpath,
above xpath can be rewritten as follows,
Driver.findElement(By.xpath("//*[starts-with(#id,'INQ')]/div[2]/tr/td/div/div[3]/div")).click();
if you can post more of your html, we can help improve your xpath..
moreover using such long xpath's is not recommended, this may cause your test to fail more often
for example,if a "new table data or div" is added to the UI, above xpath will no longer be valid
you should try and use id, class or other attributes to get closer to the element your trying to find
i personally recommend using cssSelectors over xpath
you can use many methods,
use implicity wait;
driver.findElement(By.xpath("//*[contains(#id,'select2-result-label-535')]").click();
driver.findElement(By.xpath("//*[contains(text(), 'select2-result-label-535')]").click();
Good to use Regular expression
driver.findElement(By.xpath("//*[contains(#id,'INQ_')]")
Note: If you have single ID with name starts from INQ_ then you can take action on the element . If a bunch of ID then you can extract as a List<WebElements> and then match with the specific text of the element ( element.getText().trim() =="Linked Text" and if it matched then take action. You can follow other logic to traverse and match.
you can use css -
div.context-menu-item-inner
Use this xpath:
driver.findElement(By.cssSelector("div.context-menu-item-inner").click();
The best choice is using full xpath instead of id which you can get easily via firebug.
e.g.
/html/body/div[3]/div[3]/div[2]/div/div[2]/div[1]/div/div[1]
if your xpath is varying
Ex: "//*[#id='msg500']" , "//*[#id='msg501']", "//*[#id='msg502']" and so on...
Then use this code in script:
for (int i=0;i<=9;i++) {
String mpath= "//*[#id='msg50"+i+"']";
driver.findElement(By.xpath(mpath)).click();
}

Writing XPath expressions matching a prefix

I am fairly new to XPath.
The requirement is to create a XPath expression which returns a list of elements, rather than a single element. After that we apply custom logic to locate the required element in the list.
The individual element can be accessed using the below XPaths:
.//*[#id='reportListItemID0']/td[12]/a
.//*[#id='reportListItemID1']/td[12]/a
.//*[#id='reportListItemID2']/td[12]/a
.
.
.
.//*[#id='reportListItemID20']/td[12]/a
.//*[#id='reportListItemID21']/td[12]/a
Please let me know, how to write a XPath expression which would returns all the above elements.
I tried the below and they did not work:
.//*[#id='reportListItemID.']/td[12]/a
.//*[#id='reportListItemID..']/td[12]/a
.//*[#id='reportListItemID*']/td[12]/a
.//*[#id='reportListItemID**']/td[12]/a
Please let me know what I am missing.
You should use the starts-with() function:
.//*[starts-with(#id,'reportListItemID')]/td[12]/a
You can also use contains:
//*[contains(#id, 'reportListItemID')]/td[12]/a

Resources