How to loop in a xml structure with xquery? - xpath

the xml is like this:
<persons>
<person>
<name/>
<surname/>
</person>
<person index=1>
<name/>
<surname/>
</person>
<person index=2>
<name/>
<surname/>
</person>
...
</persons>
I need to build a view that shows all data of all persons.
name surname
name1 surname1
How can i do this loop in a select statement? It needs to be a view.

Use:
string-join(/*/person/concat(name, ' ', surname), '
')
when this XPath expression is evaluated, against the following XML document:
<persons>
<person index="1">
<name>Alex</name>
<surname>Brown</surname>
</person>
<person index="2">
<name>Katie</name>
<surname>Smith</surname>
</person>
<person index="3">
<name>Julius</name>
<surname>Caesar</surname>
</person>
</persons>
the result is:
Alex Brown
Katie Smith
Julius Caesar

Have you considered using xslt if you need a transformation?
If you need to xquery, to select these nodes then,
doc("file.xml")/persons/person/name | /persons/person/name
OR
doc("file.xml")//name |// surname
i.e. Name, Surname occuring anywhere

Related

How to compare element position in xpath

I am trying to compare customer account values to display only different values and ignore duplicate in XPath:
XML code:
<info>
<Customer CustAccount="1"/>
<Customer CustAccount="2"/>
<Customer CustAccount="2"/>
<Customer CustAccount="3"/>
</info>
The result should compare customer 1/2/3 and display:
customer 1
customer 2
customer 3
You can achieve this with the XPath-2.0 expression
for $c in distinct-values(/info/Customer/#CustAccount) return concat('customer ',$c,'
')
Output is:
customer 1
customer 2
customer 3
If you do not like the newlines, remove the
from the expression.
There is no pure XPath-1.0 expression achieving this; you could only do this with XSLT-1.0 if XPath-2.0 is unavailable.
Here is the pure xpath 1.0 solution.
Sample xml:
<root >
<info>
<Customer CustAccount="1"/>
<Customer CustAccount="2"/>
<Customer CustAccount="2"/>
<Customer CustAccount="3"/>
</info>
</root>
xpath 1.0:
/root/info/Customer[not(./#CustAccount=preceding::Customer/#CustAccount)]
Evidence:

JMeter - How to Extract and Verify specific element and contents from Response Data

From my Response Data:
<?xml version="1.0"?>
<PERSON>
<NAME>Harry</NAME>
<AGE>24</AGE>
<REMARKS></REMARKS>
<DETAILS>
<GENDER>MALE</GENDER>
<EYE_COLOR>BLUE</EYE_COLOR>
</DETAILS>
</PERSON>
<?xml version="1.0"?>
<PERSON>
<NAME>Andrew</NAME>
<AGE>4</AGE>
<REMARKS></REMARKS>
<DETAILS>
<GENDER>MALE</GENDER>
<EYE_COLOR>GREEN</EYE_COLOR>
</DETAILS>
<DETAILS>
<WEIGHT>85KG</WEIGHT>
<HEIGHT>173CM</HEIGHT>
</DETAILS>
</PERSON>
..... and so on
I wish to Extract the whole of the 2nd Sequence and Verify its contents
<?xml version="1.0"?>
<PERSON>
<NAME>Andrew</NAME>
<AGE>4</AGE>
<REMARKS></REMARKS>
<DETAILS>
<GENDER>MALE</GENDER>
<EYE_COLOR>GREEN</COLOR>
</DETAILS>
<DETAILS>
<WEIGHT>85KG</WEIGHT>
<HEIGHT>173CM</HEIGHT>
</DETAILS>
</PERSON>
This Response can be very large, any help would be most appreciated.
You can use any one of the available post processor like "CSS/JQuery Extractor",Boundary Extractor,Regular Expression Extractor or JSR223 etc. All of them will help you to get the required data in a variable/s
But, if you need to just validate the response then you can use "Assertion" to check the response contains the required values or not.
I have used your example and getting the response and only validating the 2nd sequence as shown below:-
I have just copied your second sequence code and used "Add from Clipboard" option to put assertion. You can modify this as per your need.
Assertion consumes a lot of memory and should be avoided in load test.
Hope it help
Add a Regular Expression Extractor as a child of the request which returns the above response
Configure it as follows:
Name of created variable: anything meaningful, i.e. 2ndPerson
Regular Expression: <PERSON>[\s\S]*?<\/PERSON>
Template: $1$
Match No: 2
Add a Response Assertion as a child of the request
Configure it as follows:
Apply to: JMeter Variable -> 2ndPerson_g0
Pattern Matching Rules: Equals
Pattern:
<PERSON>
<NAME>Andrew</NAME>
<AGE>4</AGE>
<REMARKS></REMARKS>
<DETAILS>
<GENDER>MALE</GENDER>
<EYE_COLOR>GREEN</EYE_COLOR>
</DETAILS>
<DETAILS>
<WEIGHT>85KG</WEIGHT>
<HEIGHT>173CM</HEIGHT>
</DETAILS>
</PERSON>
Demo of Regular Expression:

Xquery 1.0 - query to get the average of some elements, and put that average back in the same place

So I have an XML file like this:
<data>
<person name="john" lastname="doe" >
<grades>
<math>90</math>
<biology>23</biology>
</grades>
</person>
.
.
I know how to query this to get the average of all the grades, but I want to take that average and put it in the exact same place that grades are in for the original xml file, replacing grades. So I would have something like:
<data>
<person name="john" lastname="doe" >
<average>56.5</average>
</person>
.
.
edit: I actually figured out a way to get the needed results internally, thanks for the suggestion to this problem though, it may help me in the future.
As mentioned in the comment, XQuery can't literally returns modified XML. You will have to recreate the XML, and this get overly complicated given a complex XML document to start.
For this fairly simple XML structure though, you can use the following XQuery to return the expected XML :
<data>
{
for $p in /data/person
let $g := $p/grades/*
return
<person>
{
$p/#*,
<average>{sum($g) div count($g)}</average>
}
</person>
}
</data>
xpathtester demo

How can I concatenate two XML tags using Ruby/Nokogiri?

I am using Ruby to retrieve an XML document with the following format:
<project>
<users>
<person>
<name>LUIS</name>
</person>
<person>
<name>JOHN</name>
</person>
</users>
</project>
I want to know how to produce the following result, with the tags concatenated:
<project>
<users>
<person>
<name>LUIS JOHN</name>
</person>
</users>
</project>
Here is the code I am using:
file = File.new( "proyectos.xml" )
doc3 = Nokogiri::XML(file)
a=0
#participa = doc3.search("person")
#participa.each do |i|
#par = #participa.search("name").map { |node| node.children.text }
#par.each do |i|
puts #par[a]
puts '--'
a = a + 1
end
end
Rather than supply code, here's how to fish:
To parse your XML into Nokogiri, which I recommend highly:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<project>
<users>
<person>
<name>LUIS</name>
</person>
<person>
<name>JOHN</name>
</person>
</users>
</project>
EOT
That gives you a doc variable which is the DOM as a Nokogiri::XML::Document. From that you can search, either for matching nodes or a particular node. search allows you to pass an XPath or CSS accessor to locate what you are looking for. I recommend CSS for most things because it is more readable, but XPath has some great tools to dig into the structure of your XML, so often I end up with both in my code.
So, doc.at('users') is the CSS accessor to find the first users node. doc.search('person') will return all nodes matching the person tag as a NodeSet, which is basically an array which you can enumerate or loop over.
Nokogiri has a text method for a node that lets you get the text content of that node, including all the carriage-returns between nodes that would normally be considered formatting in the XML as it flows down the document. When you have the text of the node, you can apply the normal Ruby string processing commands, such as strip, squish, chomp, etc., to massage the text into a more usable format.
Nokogiri also has a children= method which lets you redefine the child nodes of a node. You can pass in a node you've created, a NodeSet, or even the text you want rendered into the XML at that point.
In a quick experiment, I have code that does what you want in basically four lines. But, I want to see your work before I share what I wrote.
Finally, puts doc.to_xml will let you easily see if your changes to the document were successful.
Here's how I'd do it:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<project>
<users>
<person>
<name>LUIS</name>
</person>
<person>
<name>JOHN</name>
</person>
</users>
</project>
EOT
The XML is parsed into a DOM now. Search for the users tags, then locate the embedded name tags and extract the text from them. Join the results into a single space-delimited string. Then replace the children of the users tag with the desired results:
doc.search('users').each do |users|
user_names = users.search('name').map(&:text).join(' ')
users.children = "<person><name>#{ user_names }</name></person>"
end
If you output the resulting XML you'll get:
puts doc.to_xml
<?xml version="1.0"?>
<project>
<users><person><name>LUIS JOHN</name></person></users>
</project>

XPath Search relating to Attributes

I want to create an XPath query that returns cast members whose "job" is "Actor" and whose "order" is between "0" and "4" from the following XML. I'm finding it hard to create a query that does both.
<cast>
<person name="David Silverman" character="" job="Director" order="0"/>
<person name="James L. Brooks" character="" job="Author" order="0"/>
<person name="Dan Castellaneta" character="Homer J. Simpson" job="Actor" order="0"/>
<person name="Julie Kavner" character="Marge Simpson" job="Actor" order="1"/>
<person name="Nancy Cartwright" character="Bart Simpson" job="Actor" order="2"/>
<person name="Yeardley Smith" character="Lisa Simpson" job="Actor" order="3"/>
<person name="Dan Castellaneta" character="Krusty the Clown" job="Actor" order="4"/>
<person name="Hank Azaria" character="Moe Szyslak" job="Actor" order="5"/>
<person name="Dan Castellaneta" character="Apu Nahasapeemapetilon" job="Actor" order="6"/>
</cast>
cast/person[#job="Actor" and #order >= 0 and #order <= 3]
returns the four Simpsons you want.
You could use //cast/person[#job='Actor' and position()<3].
You should be able to combine your predicates //cast/person[#job='Actor' and #order>=0 and #order<=3]

Resources