Python etree lxml moving a child from parent - lxml

I have xml of the form:
<b>
<a>
<c>some stuff</c>
<d> some more stuff</d>
</a>
</b>
which I want to reformat as:
<b>
<c>some stuff</c>
<a>
<d> some more stuff</d>
</a>
</b>
any ideas on how to do this using Python lxml?

So I finally solved it using dummy tags and the addnext argument:
def new_a(xml):
node_b=xml.xpath('/b')[0]
node_d=xml.xpath('/b/a/d')
node_d[0].addnext(etree.Element('dummy_tag'))
node_dummy=xml.xpath('/b/a/dummy_tag')
node_dummy[0].append(node_d[0])
etree.strip_tags(node_b,'a')
dummies=node_b.findall('dummy_tag')
for node in dummies:
node.tag='a'
return xml
So if:
xml_ini="<b><a><c>some stuff</c><d>some other stuff</d><e>even more stuff</e></a></b>"
xml=etree.fromstring(xml_ini)
xml_new=new_a(xml)
Then we go from this:
<b>
<a>
<c>some stuff</c>
<d>some other stuff</d>
<e>even more stuff</e>
</a>
</b>
To this:
<b>
<c>some stuff</c>
<a>
<d>some other stuff</d>
</a>
<e>even more stuff</e>
</b>

Related

create xml snippet using dataweave (i.e. remove root element)

desiring an output like this
</b>
<c>
<value1 />
</c>
<c>
<value2 />
</c>
<c>
<value3/>
</c>
instead of this
<a>
</b>
<c>
<value1 />
</c>
<c>
<value2 />
</c>
<c>
<value3/>
</c>
</a>
via dataweave. i understand the output wont necessarily be completely valid xml
any help appreciated thanks
Because it is going to miss a single root element it is not going to be valid XML. So DataWeave is not going to be able to read or write it directly. You can generate an XML for each element and concatenate them as a string to avoid having an XML parsing error.
The input is not valid, I fixed it as this:
<a>
<b/>
<c>
<value1 />
</c>
<c>
<value2 />
</c>
<c>
<value3/>
</c>
</a>
Script:
%dw 2.0
output application/java
---
(payload[0] pluck (value,key,index) -> {(key):value} )
reduce ((item, acc="") -> acc ++ write(item, "application/xml", {"writeDeclaration":false}) ++ "\n" )
Output:
<b/>
<c>
<value1/>
</c>
<c>
<value2/>
</c>
<c>
<value3/>
</c>
Note that I added a newline at the end of each string ("\n") for clarity. You can remove it if you want.

selenium find element xpath

I have a question related to Selenium.
I want to get the text "DISSMISSED" from a webpage. however I tried the following codes and it doesn't work or cannot locate the element.
text7 = driver.find_element_by_xpath("//span/#class='icon-check']").text
or
text7 = driver.find_element_by_xpath("//div[strong[text()='Case Status']]").text
Here is the html code:
<p>
<strong>Case Status: </strong>
<span class="icon-check" aria-hidden="true"></span>
DISMISSED
<span> </span>
The text you want to get is in between the <p></p> tag, then
//span[#class='icon-check']/parent::p
with this simple xpath you can get the DISMISSED text.
If HTML is as below:
<HTML>
<Body>
<p>
<strong>Case Status: </strong>
<span class="icon-check" aria-hidden="true"></span>
DISMISSED
<span> </span>
</p>
</Body>
</HTML>
That means text DISMISSED belongs to p tag
So try that
//p/strong[contains(.,'Case Status')]/following-sibling::span/..
OR
//p[contains(.,'DISMISSED')]/strong[contains(.,'Case Status')]/following-sibling::span/..

Transform XML with default values in Mulesoft

Assuming I have XMLs like
<a>
<b>Some Value</b>
</a>
...or...
<a>
<b type=1 />
</a>
...or...
<a/>
and want to have some values and attributes defined in output like
<a>
<b type=0>Some Value</b>
</a>
...or...
<a>
<b type=1>Empty</b>
</a>
...or...
<a>
<b type=0>Empty</b>
</a>
what would be best way to do so in Mulesoft?
Using script with lines like
if (payload.a == null ) payload.a={}
if (payload['a']['b']) payload['a']['b']={}
if (payload.a.b.type == null) payload.a.b.type=0;
or dataweave
%dw 1.0
%output application/xml
---
{
a: payload.a default { {b:{ b#type=0 }} }
}
I'm confused about syntax here.
If I understand correctly what you're asking, the following seems to work:
input:
<?xml version='1.0' encoding='UTF-8'?>
<root>
<a>
<b>Some Value</b>
</a>
<a>
<b type="1" />
</a>
<a/>
</root>
Dataweave:
%dw 1.0
%output application/xml
---
root: payload.root.*a mapObject (
a: {
b #(type: $.b.#type default "0"):
$.b when $.b != null and $.b != "" otherwise "Empty"
}
)
output:
<?xml version='1.0' encoding='UTF-8'?>
<root>
<a>
<b type="0">Some Value</b>
</a>
<a>
<b type="1">Empty</b>
</a>
<a>
<b type="0">Empty</b>
</a>
</root>

How to Click on a Text in Selenium Webdriver 2.x

I am not able to click on the below HTML values through selenium webdriver click command through Java.
Here's my HTML...I have to click on PAAcctAcctRels, PAAcctActivityData, etc. as in the HTML.
I tried with LinkText (driver.findElement(By.linkText("PAAcctAcctRels")).click();) and xpath (driver.findElement(By.xpath(".//[#id='primaryNavLevel2Z6_G868H4S0K881F0AAEO37LG28N0']/div[1]/a")).click();)
<div id="primaryNavLevel2Z6_0G5A11K0KGF200AIUB98T20G52" class="dropdown_1columns">
<div class="col_1">
<a class="" href="?uri=nm:oid:Z6_0G5A11K0KGF200AIUB98T20G53">
<strong>
<span lang="en" dir="ltr">
PAAcctAcctRels
<span class="wpthemeAccess"> currently selected</span>
</span>
</strong>
</a>
</div>
<div class="col_1">
<a class="" href="?uri=nm:oid:Z6_0G5A11K0KGF200AIUB98T20GD4">
<span lang="en" dir="ltr">PAAcctActivityData</span>
</a>
</div>
<div class="col_1">
<a class="" href="?uri=nm:oid:Z6_0G5A11K0KGF200AIUB98T20GT1">
<span lang="en" dir="ltr">PAAcctAddrEmail</span>
</a>
</div>
Is there any other way to do this..please let me know.
1- For Clicking on text 'PAAcctActivityData', you can use the below code:
driver.findElement(By.xpath("//span[.='PAAcctActivityData']")).click();
2- For Clicking on text 'PAAcctAddrEmail', you can use the below code:
driver.findElement(By.xpath("//span[.='PAAcctAddrEmail']")).click();
NOTE:- The above xpaths will locate thespan elements with exact innerHTML/text as 'PAAcctActivityData' or 'PAAcctAddrEmail', respectively.
By.linkText("PAAcctAcctRels") won't work because that link has more text (ie ' currently selected'), and the problem with your xpath is that is starts with .//
The following should work (I have avoided using * for performance)
By.xpath("//div[#id='primaryNavLevel2Z6_G868H4S0K881F0AAEO37LG28N0']/div[1]/a")
Try using //[#id='primaryNavLevel2Z6_G868H4S0K881F0AAEO37LG28N0']/div[1]/a/span
as xpath. Remove the initial '.' and add '/span' at the end.

Understanding WebElement.findElement() and XPATH

I want to use the WebElement.findElement() API to locate a node inside the parent node using XPATH //span[#class='child-class']. I thought this would return me the <div> that is inside the parent. However, it is returning me the first one it found in the entire DOM tree. Did I use the wrong XPATH?
I have also tried using .//span[#class='child-class'] as the XPATH, but that does return anything.
Thank you.
UPDATE:
given the HTML below, I want to define a locator for the child-title <span> and child-date <span> and locate them using WebElement.findElement() API regardless of the parent being "//a/li[1]" or "//a/li[2]"
<a>
<li> parent 1
<div>
<span class="child-title child-style">title 1</span>
<span class="child-date child-style"> date 1</span>
<span class="child-author">author 1</span>
</div>
</li>
</a>
<a>
<li> parent 2
<div>
<span class="child-title child-style">title 2</span>
<span class="child-date child-style"> date 2</span>
<span class="child-author">author 3</span>
</div>
</li>
</a>
<a>
<li> parent 3
<div>
<span class="child-title child-style">title 3</span>
<span class="child-date child-style"> date 3</span>
<span class="child-author">author 3</span>
</div>
</li>
</a>
I have a WebElement parent2 initialized and located using "//a/li[2]",
WebElement child = parent2.findElement(By.xpath("//span[#class='child-author']")); would give me "author 1"
WebElement child = parent2.findElement(By.xpath("span[#class='child-author']")); would give me NoSuchElementException
There are my 2 comments with your sample code
1 - With your posted HTML, the xpath //a/li[2] is not found (we only have 3 elements with //a/li[1])
2 - Assume that we do have right code, you need to understand the differences between single slash and double slash in Xpath
a/b (single slash): select element that has "tag b" and "stands right after" an element that has "a tag"
E.g.:
<a>
<b>
<d>
<c>
</c>
</d>
</b>
</a>
AND
a//b (double slash): select element that has "tag b" and is n-level-child an element that has "a tag"
E.g.:
<a>
<c>
<d>
<b>
</b>
</d>
</c>
</a>
So, with your code
<a>
<li> parent 1
<div>
<span class="child-title child-style">title 1</span>
<span class="child-date child-style"> date 1</span>
<span class="child-author">author 1</span>
</div>
</li>
</a>
If you want to get Date Info, you should use
WebElement parent = driver.findElement(By.xpath("//a/li"));
WebElement date = parent.findElement(By.xpath("div/span[contains(#class, 'child-date')]"));
WebElement date = parent.findElement(By.xpath("//span[contains(#class, 'child-date')]"));
The code
WebElement date = parent.findElement(By.xpath("span[contains(#class, 'child-date')]"));
Will bring out NoSuchElementException because there is no [span] tag right after [li] tag
Hope help
Try something like:
Use dot(.) before double slash(//)
It looks for child under the given parent element.
Completely new question ... completely new answer. :(
Try something like:
WebElement parent1 = driver.findElement(By.xpath("//a[1]/li")); // use a[2] for parent2
WebElement author = parent1.findElement(By.xpath("span[#class='child-author']"));
WebElement date = parent1.findElement(By.xpath("span[contains(#class, 'child-date')]"));
WebElement title = parent1.findElement(By.xpath("span[contains(#class, 'child-title')]"));
Try something like :
//a/li[contains(text(), 'parent 1')]/div
It requests for "the <div> inside a <li> whose text contains 'parent 1' and who is inside a <a>.
It might not work if you have more parents because it works with a contains() (this xpath would also select <li> parent 10 ... </li>). It would be better if "parent x" were an attribute of the <li> instead of its text.