<group>
This statement groups repeating nodes, optionally filtering and sorting them, based on an XPath expression. It constructs a document structure from the group using literal XML you define and dynamic expressions to determine content or perform calculations. Groups can be nested, allowing any level of detail.
This statement both transforms data and constructs a new document for the output variable using literal XML and dynamic mashup expressions. See Literal XML Structures with Literal or Dynamic Data for more information.
With this statement, you:
Optionally, Filter With a Condition
You can also Nest Groups to get multiple levels of sorting and calculations.
| Can Contain | ( group | literal XML and dynamic expressions that define the resulting output for the group) Literal XML must be well-formed, starting with a root node. Elements in the structure should use a namespace, so that they are clearly separated from EMML markup. |
| Allowed In | mashup, else, elseif, for, foreach, if, macro, operation, sequence, while, |
Attributes
| Name | Required | Description |
|---|---|---|
| by | yes | An XPath expression that defines the set of nodes to group and the value for each item in that node set that defines how they are grouped. For nested groups, this XPath expression is relative to the XPath expression for the parent group. |
| having | An XPath expression that defines a criteria to select the set of nodes in the group. |
|
| outputvariable | yes | The required variable to accept the output of this statement. |
<group> Examples
Select Groups
You use an XPath expression in the by attribute to select a set of repeating nodes from a variable and define the values used to group these nodes. You also set the outpuvariable attribute to hold the result. For example:
<group by="$catalog//book/genre" outputvariable="$groupResult"> </group>
This example selects book nodes from the $catalog variable and sorts them by the values in their genre children. Keep these points in mind:
The XPath expression in the by attributes doesn't explicitly identify which nodes are the repeating items that should be grouped - the group items. Starting backwards from the final node in this XPath expression, the EMML Reference Runtime Engine uses the first ancestor that repeats as the group items.
The final node in this XPath must result in a simple value that can be used for sorting. This can be an attribute or any child or descendant that contains simple data.
By default, this value is treated as a string for sorting purposes. You can use functions in the XPath expression to cast sorting values to other types.
The next example selects books from the $catalog variable and sorts them numerically by their price. The number() function ensures that the values of the price nodes are treated as numbers not strings.
<group by="$catalog//book/number(price)" outputvariable="$groupResult"> </group>
Do not use predicates in the by attribute to filter which items should be selected. Instead, specify a filtering condition in the having attribute.
Filter With a Condition
You can optionally filter group items using a condition in the having attribute. This next example selects books whose prices are greater than 5 and then sorts the selected books by genre:
<group by="$catalog//book/genre" having="price > 5"
outputvariable="$groupResult">
</group>
The condition in having is an XPath expression that is relative to the group items defined in the by attribute.
Construct the Result Document
You construct the grouped result to put into the output variable as literal XML with either literal data or Dynamic Mashup Expressions to generate data.
Tip: it is a good practice to add an XML namespace declaration to the <mashup> element that you will use in the literal XML.
Inside <group>, add the XML that should be generated as the result of the <group> statement for each repeating item. The XML must be well formed. So:
Each group item must be wrapped in a single node.
Optionally, you can also create the root node that wraps the entire document for the variable.
Note: if you omit a document root node, the Mashup Engine adds an <groupresult> root node by default, using any namespace you have defined for the group items.
This next example generates a single node for each genre of books in $catalog and calculates the total number of copies sold for that genre:
<group by="$catalog//book/genre" outputvariable="$groupResult">
<res:genre name="{$group_key}" copiessold="{sum(copiessold)}"/>
</group>
This example uses two mashup expressions:
{$group_key}: this expression uses a built-in variable reserved for <group>. $group_key holds the unique values, the keys, that resulted from sorting the group items.
{sum(copiessold)}: this expression uses the XPath sum() function to calculate the total number of copies sold for all items in each unique genre group. This uses an XPath expression that is relative to the group items.
You can use mashup expressions inside literal attributes or elements. You can also specify literal data. For example
<group by="$catalog//book/genre" outputvariable="$groupResult">
<res:genres>
<res:genre>
<res:name>{$group_key}"</res:name>
<res:authors>{count(author)}</res:author>
<res:date>2008-03-15</res:date>
</res:genre>
</res:genres>
</group>
Nest Groups
You can nest <group> elements within the literal XML of the result to get additional levels of grouping. The following example has three levels of grouping:
<group outputvariable="$groupedResult" by="$catalog//book/genre">
<res:genres>
<res:genre name="{$group_key}" copiessold="{sum(copiessold)}">
<group by="author">
<res:authors>
<res:author name="{$group_key}"
copiessold="{sum(copiessold)}">
<group by="title">
<res:title name="{$group_key}"
copiessold="{sum(copiessold)}"/>
</group>
</res:author>
</res:authors>
</group>
</res:genre>
</res:genres>
</group>
Some points to keep in mind for nested <group> statements:
An outputvariable attribute is not required in nested groups.
The Xpath expression in the by attribute is relative to the group items defined in the closest group level.
In the previous example, books were the group items for all three levels. They were grouped first by genre, then author within genre and then by title.
You can also have several levels of group items. For example:
<group outputvariable="$groupedResult" by="$inventory//items/item/sku"> <res:items> <res:item id="{$group_key}" quantity="{sum(quantity)}" ...> <group by="parts/part/partno"> <res:parts> <res:part partno="{$group_key}" quantity="{sum(quantity)}".../> </res:parts> </group> </res:item> </res:items> </group>The first group in this example is for items and the XPath to calculate the quantity in inventory is based on item/quantity.
The second group, however, also has repeating nodes in the by attribute - item/parts/part nodes. This becomes the group items for the second group and the quantity calculation is based on part/quantity.
The variable $group_key is relative to the scope of the group that it is used in. So in the first example, the first $group_key generates book genres, the second generates authors and the third generates book titles.
Calculations or the results of any XPath functions are based on the group level they are used in.
Enterprise Mashup Markup Language (EMML) Documentation is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.
