Posts PDF and Downloads Page
Quite a while back (well over a year ago) I had a request from a reader to put my posts into a downloadable format. I've finally gotten around to doing that; a PDF of almost all the posts published so far is now available on the new Downloads page (a link to the page is also available to the right). I've re-ordered and grouped the posts in a way that I hope presents the information in a gradual, logical way. Even so, it's difficult to translate blog posts to an offline format (obviously, they rely heavily on links). I still hope some of you find it useful. The sample projects referenced in many of the posts are also available for download on the same page.
XQuery in soapUI Part 2: Where and Order By Clauses
In the last post we took a look at the basic syntax of XQuery expressions in soapUI, including for and return clauses. In this post we'll look at the optional where and order by clauses, which can add more complexity to expressions.
The XQuery where clause is very similar to the SQL where clause; it allows you to provide an additional filter on the base data set selected in your for clause. In the last post we created an XQuery example using the Euro 2012 web service that retrieved data for each player returned in the AllPlayersNames test request. Let's say we wanted to narrow down the list of players to include only members of the German national team. We could adjust the query by adding a where clause just after the for clause:
In this case the where clause (
Many of the same functions available in XPath expressions can also be used in XQuery expressions; the following is a valid where clause, for example:
The starts-with function takes two arguments and returns true if the first argument (in this case, the value of the sName element) begins with the second argument ("M").
In many cases, the choice to use a where clause may come down to preference; it's possible to achieve the same end result by using predicates with your for clause XPath expression. This XPath expression in the for clause returns only German players (equivalent to the first where clause example):
Likewise, the following is equivalent to the second example, returning only those players with names starting with "M":
For readability, however, you may find using where clauses preferable to the extended for clauses.
If a web service returns data in an arbitrary order (i.e., changing with each request), it presents a problem for XQuery assertions, which check for an exact match-- order absolutely matters. For situations like these, an XQuery order by clause is necessary. As you might expect, the order by clause is used to sort XQuery results by some node's value, ensuring results are always in the same order for evaluation by the assertion. The order by clause is added before the return clause; here's an example of a complete XQuery expression including a for, where, order by, and return clause:
This example selects tPlayerNames elements from the response (the for clause), filters out only those elements with sName child element values that start with "M" (the where clause), orders the results by the value of the sName child element (the order by clause), and finally returns the values of the sName and sCountryName child elements for each tPlayerNames element, formatted within identifying tags (the return clause).
It's also possible to specify multiple values for the order by clause, establishing primary, secondary, etc. sort criteria. For example, you can change the order by clause in the example above to the following to use sCountryName as the primary sort value and sName as the secondary sort value:
The beginning of the results from this modified XQuery expression look like this:
As expected, results are sorted by country first, with players from the same country further sorted by name.
As usual when discussing XML-related topics, I highly recommend checking out W3Schools.com (available from the Useful Links section on the right) to find more information about using XQuery expressions.
The XQuery where clause is very similar to the SQL where clause; it allows you to provide an additional filter on the base data set selected in your for clause. In the last post we created an XQuery example using the Euro 2012 web service that retrieved data for each player returned in the AllPlayersNames test request. Let's say we wanted to narrow down the list of players to include only members of the German national team. We could adjust the query by adding a where clause just after the for clause:
In this case the where clause (
where $x/m:sCountryName = 'Germany'
) whittles down the full set of tPlayerNames elements returned by the for clause, keeping only those that satisfy the condition of the where clause (in this case, those where the sCountryName child element equals "Germany"). Many of the same functions available in XPath expressions can also be used in XQuery expressions; the following is a valid where clause, for example:
where starts-with($x/m:sName/text(),'M')
The starts-with function takes two arguments and returns true if the first argument (in this case, the value of the sName element) begins with the second argument ("M").
In many cases, the choice to use a where clause may come down to preference; it's possible to achieve the same end result by using predicates with your for clause XPath expression. This XPath expression in the for clause returns only German players (equivalent to the first where clause example):
for $x in //m:tPlayerNames[m:sCountryName='Germany']
Likewise, the following is equivalent to the second example, returning only those players with names starting with "M":
for $x in //m:tPlayerNames[starts-with(m:sName/text(),'M')]
For readability, however, you may find using where clauses preferable to the extended for clauses.
If a web service returns data in an arbitrary order (i.e., changing with each request), it presents a problem for XQuery assertions, which check for an exact match-- order absolutely matters. For situations like these, an XQuery order by clause is necessary. As you might expect, the order by clause is used to sort XQuery results by some node's value, ensuring results are always in the same order for evaluation by the assertion. The order by clause is added before the return clause; here's an example of a complete XQuery expression including a for, where, order by, and return clause:
This example selects tPlayerNames elements from the response (the for clause), filters out only those elements with sName child element values that start with "M" (the where clause), orders the results by the value of the sName child element (the order by clause), and finally returns the values of the sName and sCountryName child elements for each tPlayerNames element, formatted within identifying tags (the return clause).
It's also possible to specify multiple values for the order by clause, establishing primary, secondary, etc. sort criteria. For example, you can change the order by clause in the example above to the following to use sCountryName as the primary sort value and sName as the secondary sort value:
order by $x/m:sCountryName/text(), $x/m:sName/text()
The beginning of the results from this modified XQuery expression look like this:
As usual when discussing XML-related topics, I highly recommend checking out W3Schools.com (available from the Useful Links section on the right) to find more information about using XQuery expressions.
XQuery in soapUI Part 1: For and Return Clauses
A few weeks ago I spent a few posts looking at XPath assertions in soapUI; in this post I'll take a look at XQuery assertions. XQuery assertions can be used to retrieve data from XML using a SQL-like syntax. The advantage of XQuery over XPath is that it can be used to check multiple node values with a single expression. XPath expressions in soapUI must resolve to a single value (a count, a Boolean, a node, a node value, etc.); while you can use an XPath expression to validate some large chunk of static data, XQuery provides a little more flexibility, allowing you to pick and choose the nodes you'd like to have returned-- particularly useful in cases where there's a mix of static and dynamic data.
For an example, let's look at the Euro 2004 web service I introduced a few posts back and look at the AllPlayerNames request. You can download a stripped down "test suite" consisting of a single test case here. Import the project into soapUI and run the test request; it should return a list of participating players in the Euro 2012 tournament:
Let's say (strictly for the sake of this example) we're only interested in validating the iId, sName, and sCountryName values for each player, verifying they match their expected values. Expand the Assertions panel for the test request, click the icon to add a new assertion, and select the XQuery Match assertion type (part of the Property Content group in the Add Assertion dialog) to bring up the assertion editor.
As with XPath assertions, you'll need to make some namespace declarations; click the Declare button at the top of the editor to let soapUI do this for you. The XQuery expression below returns the iId, sName, and sCountryName values for all players; enter it beneath the namespace declarations as shown:
Click the "Select from current" button to evaluate the XQuery expression. Here's a snippet of the results:
The return clause does the heavy lifting, retrieving data associated with each element via XPath expressions. For example,
Tags are used to group and organize expression results. Experimenting a little bit with the expression, you'll see a couple of general rules. If the XPath expression in the for clause returns multiple nodes, the entire expression should be wrapped in tags (like the "playerList" tag above). Likewise, you'll receive an error if you try to alter the example expression by removing the "player" tag around the return XPath expressions-- because there are multiple XPath expressions applied to each element, a tag is needed to separate each element's returned data (each id, name, and country set). The "id", "name", and "country" tags are not in fact necessary, but they make the results more readable.
Within tags, brackets ( "{" and "}" ) are used to identify expression content that needs to be evaluated, as opposed to literal text, which can also be included between tags. Here's a variation on the example expression that includes some literal text:
Here's what the result looks like:
For an example, let's look at the Euro 2004 web service I introduced a few posts back and look at the AllPlayerNames request. You can download a stripped down "test suite" consisting of a single test case here. Import the project into soapUI and run the test request; it should return a list of participating players in the Euro 2012 tournament:
Let's say (strictly for the sake of this example) we're only interested in validating the iId, sName, and sCountryName values for each player, verifying they match their expected values. Expand the Assertions panel for the test request, click the icon to add a new assertion, and select the XQuery Match assertion type (part of the Property Content group in the Add Assertion dialog) to bring up the assertion editor.
As with XPath assertions, you'll need to make some namespace declarations; click the Declare button at the top of the editor to let soapUI do this for you. The XQuery expression below returns the iId, sName, and sCountryName values for all players; enter it beneath the namespace declarations as shown:
Click the "Select from current" button to evaluate the XQuery expression. Here's a snippet of the results:
Let's break down the expression, starting with the for clause:
for $x in //m:tPlayerNames
. If you're familiar with for-in or foreach-in loops in some programming languages, used to iterate through a collection and perform some action on each of its members, this is a bit similar. The for clause here essentially translates to "for each member in the set of elements returned by //m:tPlayerNames
..." The clause also assigns those elements to the variable $x
in subsequent lines of the expression.The return clause does the heavy lifting, retrieving data associated with each element via XPath expressions. For example,
$x/m:iId/text()
returns the value of the iId child element for each element. The text() function may be new for some-- it simply indicates that you want the actual inner value (i.e., the value between tags) of an element. With soapUI's XPath expressions, the text() function isn't necessary (specifying an element is enough to indicate you want its value and not the node itself), it is required for XQuery expressions.Tags are used to group and organize expression results. Experimenting a little bit with the expression, you'll see a couple of general rules. If the XPath expression in the for clause returns multiple nodes, the entire expression should be wrapped in tags (like the "playerList" tag above). Likewise, you'll receive an error if you try to alter the example expression by removing the "player" tag around the return XPath expressions-- because there are multiple XPath expressions applied to each element, a tag is needed to separate each element's returned data (each id, name, and country set). The "id", "name", and "country" tags are not in fact necessary, but they make the results more readable.
Within tags, brackets ( "{" and "}" ) are used to identify expression content that needs to be evaluated, as opposed to literal text, which can also be included between tags. Here's a variation on the example expression that includes some literal text:
Here's what the result looks like:
As you can see, the literal characters within the tags (but outside the brackets) are left intact in the expression output.
Now that you're familiar with the basic syntax of XQuery expressions, we'll look at where and order by clauses in the next post.
Subscribe to:
Posts (Atom)