Friday, April 4, 2014

Extracting Data from XML files using XSL and XPath...4

Counting a tag – ‘count’ function and the tag value – ‘sum’ function

The function ‘count’ is used to count an entity in the current ‘for-each’ ‘testplan’.

So, since we are at the ‘testplan’ level, we are counting the total occurrences of the ‘testcase_id’ within that ‘testplan’. This could also be accomplished by using only
<xsl:value-of select="count(.//testcase_id)"/>
This command is equally functional, just that the former one shows the hierarchy. There is a count of ‘tc_test_design_status’. This is a conditional count, which counts all the test cases when the testcase has the custom attribute of ‘tc_test_design_status’ set as ‘Complete’. See the XML below (under a testcase tag):

Another example of conditional copying can be seen as follows, when we count the number of ‘passed’ testcases (indicated with value ‘p’ in the Example.xml)

The value for testcase to be passed must come from XML as follows:

Remember that all these counts are within ‘testplan’, so when we use ‘//’ within that, we go directly to the ‘tcexecution_status’ tag and count when its value is ‘p’.
Did you notice the XPath expression? Here it is:
‘.//build/platform/testcase/testcase_id’

On the similar lines, we might sometimes need to sum the value within the tags. Consider the following XML:

<AllDCs>
<DCDetails>
<DC>DC 8</DC>
<TTLTCs>30</TTLTCs>
<TTLBTCs>3</TTLBTCs>
<TTLPTCs>26</TTLPTCs>
<TTLFTCs>1</TTLFTCs>
</DCDetails>
<DCDetails>
<DC>DC 1</DC>
<TTLTCs>11</TTLTCs>
<TTLBTCs>0</TTLBTCs>
<TTLPTCs>11</TTLPTCs>
<TTLFTCs>0</TTLFTCs>
</DCDetails>
<AllDCs>
If we have to get the sum of <TTLPTCs> for both the DCDetails, then we need to use the function as:
<xsl:value-of select = “sum(DCDetails/TTLPTCs)”>
assuming that we are at the DCDetails level. The difference between count and sum is that ‘count’ is used to count the number of occurrences of a tag, while sum is used to add the contents of a tag.
We can also use conditional sum. For example, consider the following XML:
<DCRecord>
<DC>DC 8</DC>
<DCBuildRecord>
<BuildNumber>1</BuildNumber>
<PlanDetails>
<Phase>2013-R3-Dec</Phase>
<Test_Type>DC System</Test_Type>
<BP>Purchase</BP>
<LOB>Multi - LOB</LOB>
<TTLs>
<TTLTCs>153</TTLTCs>
<TTLBTCs>11</TTLBTCs>
<TTLPTCs>142</TTLPTCs>
<TTLFTCs>0</TTLFTCs>
<TTLIPTCs>0</TTLIPTCs>
<TTLDTCs>0</TTLDTCs>
<TTLWTCs>0</TTLWTCs>
</TTLs>
</PlanDetails>
</DCBuildRecord>
</DCRecord>
<DCRecord>
<DC>DC 8</DC>
<DCBuildRecord>
<BuildNumber>3</BuildNumber>
<PlanDetails>
<Phase>2013-R3-Dec</Phase>
<Test_Type>Integration</Test_Type>
<BP>Payments</BP>
<LOB>Multi - LOB</LOB>
<TTLs>
<TTLTCs>147</TTLTCs>
<TTLBTCs>0</TTLBTCs>
<TTLPTCs>116</TTLPTCs>
<TTLFTCs>1</TTLFTCs>
<TTLIPTCs>0</TTLIPTCs>
<TTLDTCs>24</TTLDTCs>
<TTLWTCs>6</TTLWTCs>
</TTLs>
</PlanDetails>
</DCBuildRecord>
</DCRecord>

To get the totals depending on various conditions following code was used:

<TTLTCs>
<xsl:value-of select = "sum(//PlanDetails[../../DC = 'DC 8' and Test_Type = 'Integration' and BP = 'Purchase' and (Phase = '2014-R3' or Phase = 'ICP_Ph1.001.500.000')]//TTLTCs)"/>
</TTLTCs>
<xsl:text>&#xa;</xsl:text>
<TTLBTCs>
<xsl:value-of select = "sum(//PlanDetails[../../DC = 'DC 8' and Test_Type = 'Integration' and BP = 'Purchase' and (Phase = '2014-R3' or Phase = 'ICP_Ph1.001.500.000')]//TTLBTCs)"/>
</TTLBTCs>
<xsl:text>&#xa;</xsl:text>
<TTLPTCs>
<xsl:value-of select = "sum(//PlanDetails[../../DC = 'DC 8' and Test_Type = 'Integration' and BP = 'Purchase' and (Phase = '2014-R3' or Phase = 'ICP_Ph1.001.500.000')]//TTLPTCs)"/>
</TTLPTCs>
<xsl:text>&#xa;</xsl:text>
<TTLFTCs>
<xsl:value-of select = "sum(//PlanDetails[../../DC = 'DC 8' and Test_Type = 'Integration' and BP = 'Purchase' and (Phase = '2014-R3' or Phase = 'ICP_Ph1.001.500.000')]//TTLFTCs)"/>
</TTLFTCs>

The output of the above file could be an XML file shown below:

<TTLTCs>50<TTLTCs>
<TTLBTCs>20<TTLTCs>
<TTLPTCs>20<TTLTCs>
<TTLFTCs>10<TTLTCs>

Carefully note the use of brackets and conditions and the use of ../ in the above example.

‘Choose:when:otherwise’ construct

Under the section – “Getting the values – conditional ‘xsl:value-of’ tag” we counted testcases that had the custom attribute of ‘tc_test_design_status’ set as ‘Complete’. For the group that had an exception, we actually had Test Design Status set at the ‘testplan’ level, so there is nothing to count. The value will be set at ‘testplan’ level. Hence for that the code was written as follows:



Here we have new construct called choose:when:otherwise, that is similar to if:then:else.
‘Choose’ is just selecting something ‘when’ a condition is true; ‘otherwise’ the other statement is executed (something else is selected).
It is evident that the condition is put at the ‘testplan’ level and if the value is set correctly ‘Complete’, we will count all testcases within that ‘testplan’.

Counting at a different level of hierarchy

The next requirement was to get the counts at the level of ‘testplans’ and also the builds. For ‘testplans’, the above points explain how to get the totals. But, now when we go down to the level of builds, then we can get totals only at the builds level, in the following way:

Ignore the conditions in between; they are similar to previously discussed code. Just take note of how we have gone one level down to builds. But now, when we will use the ‘./’ construct, we will get all the attributes (fields) at the build level only. How to get the values at the ‘testplan’ level (custom attributes, ‘testplan_name’, ‘testplan_id’, Total TCs at Test Plan level etc.)? Simple, we will use the construct ‘../’, - to go one level up from build and get the values. This will be applied to all fields that we need.

As it is evident from the above code snippet, we have just included an extra ‘../’ to get ‘datasource_description’ and ‘repository_id’ values (as compared to that when we did the same thing at the ‘testplan’ level). Also, to get the values at the ‘testplan’ level, ‘../’ has been included in place of ‘./’ since we are now looking at one level up the ‘build’. Similarly the following code will give us totals at the ‘testplan’ level even though ‘for-each’ has gone down to ‘build’ level.

Read the above statement simply as – Give total number of ‘testcase_id’s within one level up the current level.

Variables in XSLT

Use of variables in XSLT is different from the way we use them in conventional structured programming languages such as C, C++, Java etc. There is a scope limitation for each variable, out of which it cannot be used. You cannot reassign a variable within that scope and neither can you re-declare it.

This tag will put the value of ‘testplan_id’ into variable TP1. To use a variable we need to prefix it with a $ sign as follows:



Variables are immutable, meaning that when once assigned with a value, they cannot be changes. In a way, they behave like constants.

No comments:

Post a Comment