# Step 4: Mapping Repeating Elements—Creating a Join

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
- To Join Two Sets of Repeating Elements
- Add Links to Populate the quoteResponse Element
- Call the calculateTotalPrice User Method From the Query
- To View the Generated Query
- To Test the Query
- Create an Instance of the MyTutorialJoin Control
- Edit the Node That Invokes the Transformation
- To Run the Business Process

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.

1. View MyTutorialJoin.dtf in the Design View:

1. If the Application tab is not visible in WebLogic Workshop, from the menu bar, choose View —> Application.
2. In the Application tab, double-click Tutorial_Process_Application\Tutorial_Process_ApplicationWeb\requestquote\MyTutorialJoin.dtf and select the Design View tab.

The graphical representation of the MyTutorialJoin Transformation file is displayed, as shown in the following figure:

2. Right-click in the box representing the MyTutorialJoin Transformation file. (The box shown in the preceding figure.)
3. From the drop-down menu, select Add User Method.

A User method is created in the MyTutorialJoin Transformation file.

4. Enter calculateTotalPrice as the method name.

The methods that make up the MyTutorialJoin Transformation file are displayed, as shown in the following figure.

5. Right-click the arrow representing the calculateTotalPrice method.
6. From the drop-down menu, select Edit in source view.
7. In Source View, edit the MyTutorialJoin Transformation file and replace the following generated calculateTotalPrice Java method:

    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.

8. Save all the files in this application. From the WebLogic Workshop menu bar, choose File —> Save All.

To Join Two Sets of Repeating Elements

1. View myJoin.xq in the Design View:

1. If the Application tab is not visible in WebLogic Workshop, from the menu bar, choose View —> Application.
2. In the Application tab, double-click Tutorial_Process_Application\Tutorial_Process_ApplicationWeb\requestquote\MyTutorialJoin.dtf\myJoin.xq and select the Design View tab.

2. In the Source pane, collapse the shipAddress node.
3. From the Source pane, drag-and-drop the priceQuoteDoc\priceRequests\priceRequest node onto the quote\quoteResponse node in the Target pane.

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.

4. From the Source pane, drag-and-drop the availQuoteDoc\availRequest node onto the quote\quoteResponse node in the Target pane.

A dashed line linking the two repeating elements is displayed, as shown in the following figure.

5. Select the Source View tab to view the changes to the query.
6. Expand prolog.

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:

- The first instance of the priceRequest element with the first instance of availRequest element.
- The first instance of the priceRequest element with the second instance of availRequest element.
- The first instance of the priceRequest element with the third instance of availRequest element.
- The second instance of the priceRequest element with the first instance of availRequest element.
- The second instance of the priceRequest element with the second instance of availRequest element.
- The second instance of the priceRequest element with the third instance of availRequest element.
- The third instance of the priceRequest element with the first instance of availRequest element.
- The third instance of the priceRequest element with the second instance of availRequest element.
- The third instance of the priceRequest element with the third instance of availRequest element.

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.

7. Select the Design View tab.
8. In the Source pane, drag-and-drop the priceQuoteDoc/priceRequests/priceRequest/widgetId node onto the target availQuote/availRequest/widgetId node.

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.

9. View the changes to the query by clicking the Source View tab.

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

1. Select the Design View tab.
2. From the Source pane, drag-and-drop the priceQuoteDoc/priceRequests/priceRequest/widgetId node onto the quote/quoteResponse/widgetId node in the Target pane.
3. From the Source pane, drag-and-drop the priceQuoteDoc/priceRequests/priceRequest/price node onto the quote/quoteResponse/unitPrice node in the Target pane.
4. From the Source pane, drag-and-drop the availQuoteDoc/availRequest/requestedQuantity node onto the quote/quoteResponse/requestedQuantity node in the Target pane.
5. From the Source pane, drag-and-drop the availQuoteDoc/availRequest/quantityAvail node onto the quote/quoteResponse/fillOrder node in the Target pane.
6. From the Source pane, drag-and-drop the availQuoteDoc/availRequest/shipDate node onto the quote/quoteResponse/shipDate node in the Target pane.
7. From the Source pane, drag-and-drop the taxRate Java primitive onto the quote/quoteResponse/taxRate node in the Target pane.
8. From the Source pane, drag-and-drop the taxRate Java primitive onto the quote/quoteRespons/totalCost node in the Target pane.

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.

9. Save all the files in this application. From the WebLogic Workshop menu bar, choose File —> Save All.

Call the calculateTotalPrice User Method From the Query

1. Select the Design View tab.
2. Select the link between the taxRate Java primitive and the quote/quoteResponse/totalCost node.
3. In the Palette, find the User Functions section. (If the Palette is not visible, from the WebLogic Workshop menu bar, choose View —> Windows —> Palette.)
4. In the User Functions section of the Palette, select the calculateTotalPrice function, and drag-and-drop it into the General Expression pane.

Leave $float-var selected in the General Expression pane.

5. In the Source pane, select the taxRate node and drag-and-drop it onto the $float-var parameter of 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.

6. In the Source pane, select availQuoteDoc/availRequest/requestedQuantity and drag-and-drop it onto the selected $int-var argument in the General 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.

7. In the Source pane, select priceQuoteDoc/priceRequests/priceRequest/price and drag-and-drop it onto the selected $float-var argument 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.

8. In the Source pane, select availQuoteDoc/availRequest/quantityAvail and drag-and-drop it onto the selected $boolean-var argument 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.

9. Click Apply.

In the Design View, the following is displayed, as shown in the following figure.

10. Save all the files in this application. From the WebLogic Workshop menu bar, choose File —> Save All.

To View the Generated Query

1. Select the Source View tab.
2. Expand prolog.

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.

To Test the Query

1. Select the Test View tab.
2. There are three import parameters to the myJoin Transformation method: $priceQuoteDoc, $availQuoteDoc, and $taxRate. In the task: To Test the Simple Query, you imported PriceQuote.xml as source data for the $priceQuoteDoc parameter. In this step, you import AvailQuote.xml for the source parameter: $availQuoteDoc:

1. From the drop-down menu in the Source Data pane, select $availQuoteDoc.
2. Click Import... .

The Open XML File to Test dialog box is displayed.

3. Double-click the requestquote folder.
4. Double-click the testxml folder.
5. Double-click the AvailQuote.xml file.

A graphical representation of the AvailQuote.xml file appears in the Source Data pane.

3. From the drop-down menu in the Source Data pane, select $taxRate .
4. In the Node Value field of the $taxRate node, double-click the existing value, enter "0.08", and then press Enter on your keyboard
5. In the Result Data, pane click Test.

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).

6. To view resulting data as XML, in the Result Data pane, select the XML Source View tab.
7. To check that the resulting XML data from the query is valid against the associated XML Schema, in the Result Data pane click Validate.

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.

1. View the RequestQuote business process in the Design View:

1. If the Application tab is not visible in WebLogic Workshop, from the menu bar choose View —> Application.
2. In the Application tab, double-click Tutorial_Process_Application\Tutorial_Process_ApplicationWeb\requestquote\RequestQuote.jpd and select the Design View tab.

2. Click Add on the Controls tab, then choose Integration Controls —> Transformation from the drop-down menu. (If the Controls pane is not visible in WebLogic Workshop, from the menu bar, choose View —> Windows —> Data Palette. The Controls pane is at the bottom of the Data Palette.)

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.

3. In the Insert - Transformation dialog box, complete the following steps:

1. In Step 1, enter myTutorialJoin as the variable name for the control.
2. In Step 2, ensure that the following option is selected: Use a Transformation already defined by a DTF file.
3. Click Browse beside the DTF file field, expand the requestquote folder, select MyTutorialJoin.dtf, and then click Select to close the file browser.

The following in displayed in the Insert - Transformation dialog box:

4. Click Create to close 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.

1. In the RequestQuote business process, double-click the Combine Price and Avail Quotes node to open its node builder.

The node builder opens on the General Settings pane.

2. From the drop-down menu in the Control field select myTutorialJoin.
3. Select QuoteDocument myJoin() from the Method field.
4. Click Send Data to open the second pane of the node builder.

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.

5. Click Receive Data to open the third pane of the node builder.

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.

6. In the node builder, click X in the top right-hand corner to save your specifications and close the node builder.
7. Save all the files in this application, including the RequestQuote business process. From the WebLogic Workshop menu bar, choose File —> Save All.

To Run the Business Process

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.