In this step, you will add additional mappings to the existing query. In the previous sections, you mapped some data from the source type defined by the PriceQuote.xsd XML Schema to the target type defined by the Quote.xsd XML Schema. In this section, you will map additional data from the source types (defined by the PriceQuote.xsd XML Schema, the AvailQuote.xsd XML Schema, and the Java float primitive: taxRate) to the target type (defined by the Quote.xsd XML Schema) as shown in the following figure.
Mappings created in this section will create a join between repeating elements in the source and target XML Schemas. Complete the following tasks to create, test, and alter the join:
Create a User-Defined Java Method to Invoke From the Join Query
In this task, you will create a user-defined Java method in the MyTutorialJoin Transformation file that calculates the total price of the widgets requested including tax. In Call the calculateTotalPrice User Method From the Query, you will change the query to invoke this method.
The graphical representation of the MyTutorialJoin Transformation file is displayed, as shown in the following figure:
A User method is created in the MyTutorialJoin Transformation file.
The methods that make up the MyTutorialJoin Transformation file are displayed, as shown in the following figure.
public String calculateTotalPrice() { return ""; }
With the following calculateTotalPrice Java method:
public float calculateTotalPrice(float taxRate, int quantity, float price, boolean fillOrder) { float totalTax, costNoTax, totalCost; if (fillOrder) { // Calculate the total tax totalTax = taxRate * quantity * price; // Calculate the total cost without tax costNoTax = quantity * price; // Add the tax and the cost to get the total cost totalCost = totalTax + costNoTax; } else { totalCost = 0; } return totalCost; }
Warning: Make sure you change the return type of the calculateTotalPrice function from String to float.
To Join Two Sets of Repeating Elements
These nodes are both repeating nodes. A repeating node means more than one instance of this node can be specified. The + symbol to the right of the node indicates these nodes are repeating nodes.
Warning: You must select the priceRequest node and not the priceRequests node.
A dashed line linking the two repeating nodes is displayed, as shown in the following figure.
The dashed line with short dashes represents a structural link—a link between two parent structures that does not map data directly.
To learn more about XML repeating nodes, see Understanding XML Repeating Nodes.
A dashed line linking the two repeating elements is displayed, as shown in the following figure.
The following query is displayed in the Source View:
{-- requestquote/MyTutorialJoin.dtf#myJoin --} declare namespace ns0 = "http://www.example.org/price" declare namespace ns1 = "http://www.example.org/avail" declare namespace ns2 = "http://www.example.org/quote" <ns2:quote> <name>{ data($priceQuoteDoc/ns0:customerName) }</name> <address>{ concat($priceQuoteDoc/ns0:shipAddress/@street , ",", $priceQuoteDoc/ns0:shipAddress/@city ,",", xf:upper-case($priceQuoteDoc/ns0:shipAddress/@state) , ",", $priceQuoteDoc/ns0:shipAddress/@zip) }</address> { for $priceRequest in $priceQuoteDoc/ns0:priceRequests/ns0:priceRequest, $availRequest in $availQuoteDoc/ns1:availRequest return <quoteResponse/> } </ns2:quote>
In the preceding query, there are no data links between the children of the repeating nodes, so the quoteResponse element is empty. (The string: <quoteResponse/> is an empty node.)
The structural links between the repeating nodes generates the for loop which is shown in bold in the preceding query listing. This XQuery for loop iterates through the set of priceRequest and availReqest repeating elements. For example, if the source XML data to this query contains three instances of the priceRequest element and three instances of the availRequest element, the for loop would execute a total of nine times with the following combinations:
For some transformations, you may want the query to generate all the possible combinations but for others, you may want to constrain the combinations as described in the following steps.
Note: Both of these elements are in the Source pane.
A line between the two widgetId nodes is displayed, as shown in the following figure.
The following query is displayed in the Source View:
{-- requestquote/MyTutorialJoin.dtf#myJoin --} declare namespace ns0 = "http://www.example.org/price" declare namespace ns1 = "http://www.example.org/avail" declare namespace ns2 = "http://www.example.org/quote" <ns2:quote> <name>{ data($priceQuoteDoc/ns0:customerName) }</name> <address>{ concat($priceQuoteDoc/ns0:shipAddress/@street , ",", $priceQuoteDoc/ns0:shipAddress/@city , ",", xf:upper-case($priceQuoteDoc/ns0:shipAddress/@state) , ",", $priceQuoteDoc/ns0:shipAddress/@zip) }</address> { for $priceRequest in $priceQuoteDoc/ns0:priceRequests/ns0:priceRequest, $availRequest in $availQuoteDoc/ns1:availRequest where data($priceRequest/ns0:widgetId) = data($availRequest/ns1:widgetId) return <quoteResponse/> } </ns2:quote>
The link between the widgetId nodes generates the where clause in the for loop, as shown in bold in the preceding query listing. This where clause constrains or limits the output of the for loop. Specifically, the where clause specifies that if the expression in the where clause is true, the for loop will output the contents of the return. For this example, if the widgetId of the availRequest element is equal to the widgetId of the priceQuest element, the following XML data is returned:
<quoteResponse/>
An empty quoteReponse element isn't very useful. In the following task: Add Links to Populate the quoteResponse Element, you will add data links that will populate the quoteResponse element.
Add Links to Populate the quoteResponse Element
Note: In the next section, to calculate the total cost of the order, you will edit the link between the taxRate Java primitive and the quote/quoteResponse/totalCost node.
In the Design View, the following links are displayed, as shown in the following figure.
Call the calculateTotalPrice User Method From the Query
Leave $float-var selected in the General Expression pane.
In the General Expression pane, the default argument: $float_var is replaced with the $taxRate argument and the next argument becomes selected, as shown in the following figure.
Leave $int-var selected in the General Expression pane.
In the General Expression pane, the default argument: $int_var is replaced with the $availRequest/ns1:requestedQuantity argument and the next argument becomes selected, as shown in the following figure.
Leave $float-var selected in the General Expression pane.
In the General Expression pane, the default argument: $float_var is replaced with the $priceRequest/ns0:price argument and the next argument becomes selected, as shown in the following figure.
Leave $boolean-var selected in the General Expression pane.
In the General Expression pane, the default argument: $boolean_var is replaced with the $availRequest/ns1:quantityAvail argument, as shown in the following figure.
In the Design View, the following is displayed, as shown in the following figure.
The following query is displayed in Source View:
{-- requestquote/MyTutorialJoin.dtf#myJoin --}
declare namespace ns0 = "http://www.example.org/price"
declare namespace ns1 = "http://www.example.org/avail"
declare namespace ns2 = "http://www.example.org/quote"
<ns2:quote>
<name>{ data($priceQuoteDoc/ns0:customerName) }</name>
<address>{ concat($priceQuoteDoc/ns0:shipAddress/@street , ",",
$priceQuoteDoc/ns0:shipAddress/@city , ",",
xf:upper-case($priceQuoteDoc/ns0:shipAddress/@state) , ",",
$priceQuoteDoc/ns0:shipAddress/@zip) }</address>
{
for $priceRequest in $priceQuoteDoc/ns0:priceRequests/ns0:priceRequest,
$availRequest in $availQuoteDoc/ns1:availRequest
where data($priceRequest/ns0:widgetId) = data($availRequest/ns1:widgetId)
return
<quoteResponse>
<widgetId>{ data($priceRequest/ns0:widgetId) }</widgetId>
<unitPrice>{ data($priceRequest/ns0:price) }</unitPrice>
<requestedQuantity>{ data($availRequest/ns1:requestedQuantity) }</requestedQuantity>
<fillOrder>{ data($availRequest/ns1:quantityAvail) }</fillOrder>
{
for $shipDate in $availRequest/ns1:shipDate
return
<shipDate>{ data($shipDate) }</shipDate>
}
<taxRate>{ $taxRate }</taxRate>
<totalCost>{ calculateTotalPrice($taxRate,
$availRequest/ns1:requestedQuantity,
$priceRequest/ns0:price,
$availRequest/ns1:quantityAvail) }</totalCost>
</quoteResponse>
}
</ns2:quote>
The links added in the preceding task generate the additional XQuery source code listed between the <quoteResponse> and </quoteResponse> tags highlighted in bold in the preceding query listing.
The Open XML File to Test dialog box is displayed.
A graphical representation of the AvailQuote.xml file appears in the Source Data pane.
The query is run with the test XML data. A graphical representation of the resulting XML data is shown in the XML Design View of the Result Data pane, as shown in the following figure.
This query joins the two sets of source repeating elements (availRequest and priceRequest) to a single repeating element (quoteResponse).
The Output tab will show whether the XML data is valid to the target XML Schema. In this example, the resulting XML data is checked against the XML Schema in the Quote.xsd file. To learn more, see Validating.
Create an Instance of the MyTutorialJoin Control
In this task, you create an instance of the MyTutorialJoin.dtf control.
Note: The Data Palette associated with business processes is different than the Data Palette associated with the mapper.
The Insert - Transformation dialog box is displayed.
The following in displayed in the Insert - Transformation dialog box:
An instance called myTutorialJoin is created in your project and displayed in the Controls pane as shown by the following figure:
Edit the Node That Invokes the Transformation
In this task, you edit the Combine Price and Avail Quotes node in the RequestQuote business process and change the instance that gets invoked by this node from an instance of the TutorialJoin.dtf to an instance of the MyTutorialJoin.dtf. Additionally, you change the design of the Combine Price and Avail Quotes node to call the myJoin() method on the MyTutorialJoin control. The myJoin() method combines the data returned to your business process from different systems creating a single XML response document (quote) that is subsequently returned to the business process's client.
The node builder opens on the General Settings pane.
The Select variables to assign fields are populated with default variables. The data types match the data type expected in the source parameters to the myJoin() method as shown in the following list:
priceQuote holds the price quote data, which is returned from the PriceProcessor service in the For Each loop in your business process.
availQuote holds the availability quote data, which is returned from the AvailProcessor service in the For Each loop in your business process.
taxRate holds the rate of sales tax applied to the quote, based on the shipping address, which is returned to your business process from the taxCalculation service.
The Control Expects fields are populated with the data type expected by the myJoin() method on the MyTutorialJoin control, as shown in the following figure.
On the Receive Data tab, the Select variables to assign field is populated with the default variable: Quote. The data type matches the data type expected in the target parameter to the myJoin() method. The Control Expects field is populated with the data type returned by the myJoin() method: QuoteDocument, as shown in the following figure.
Earlier in this tutorial, you entered the XML data that is run against the query. During run time, the business process builds the XML data and passes it to the query that was built in this tutorial. To run the business process and invoke the query, follow the instructions in Step 12: Run the RequestQuote Business Process in the Tutorial: Building Your First Business Process.
![]() |
![]() |