Overview
This article uses the XML dataset defined in the requirements detailed report. Users are directed to run this "requirements detailed" report in XML format to see the data available. In this article, we will create a new XSLT has been created which iterates through the requirements identifying the following fields.
- Hierarchy (Will be created dynamically at the rendering time based on the current hierarchical requirement structure)
- Requirement ID (Existing Requirement ID)
- Name (Existing Requirement Name)
- Parent Requirement (The immediate parent of the current requirement)
- Test Cases (A comma separated list of ordered test cases)
Modify Standard Section
- Clone the Requirements Detailed Report
- Update the name and description of the new report (shown below)
- Click on the "Customize" button near the "Requirements Details" in the "Standard Sections".

- Update the XSLT with the one provided below

- Save the "Standard Section" (The Save button is referenced in the screenshot above)
- Save the report (There will be another Save button to save the report)

- You are now ready to run the report from the Reporting area.
Modified XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<!-- Root template -->
<xsl:template match="/RequirementData">
<html>
<head>
<title>Requirements Traceability</title>
</head>
<body>
<h2>Requirements Traceability Report</h2>
<table class="DataGrid">
<tr>
<th>Hierarchy</th>
<th>Requirement ID</th>
<th>Requirement Name</th>
<th>Parent Requirement ID</th>
<th>Test Case IDs</th>
</tr>
<!-- Start from top-level requirements -->
<xsl:apply-templates select="Requirement[string-length(IndentLevel)=3]" mode="render">
<xsl:with-param name="prefix" select="''"/>
</xsl:apply-templates>
</table>
</body>
</html>
</xsl:template>
<!-- ================================================= -->
<!-- Recursive template to render requirement and kids -->
<!-- ================================================= -->
<xsl:template match="Requirement" mode="render">
<xsl:param name="prefix"/>
<xsl:variable name="reqId" select="RequirementId"/>
<xsl:variable name="reqName" select="Name"/>
<xsl:variable name="indentLevel" select="(string-length(IndentLevel) div 3) + 1"/>
<!-- Sequential number among siblings (XSLT 1.0 safe) -->
<xsl:variable name="seq">
<xsl:value-of
select="count(
preceding-sibling::Requirement
[string-length(IndentLevel)=string-length(current()/IndentLevel)]
) + 1"/>
</xsl:variable>
<!-- Hierarchical number -->
<xsl:variable name="hierNum">
<xsl:choose>
<xsl:when test="string-length($prefix)=0">
<xsl:value-of select="$seq"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($prefix,'.',$seq)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- Parent ID: indent minus 3 chars -->
<xsl:variable name="parentIndent"
select="substring(IndentLevel,1,string-length(IndentLevel)-3)"/>
<xsl:variable name="parentId"
select="/RequirementData/Requirement[IndentLevel=$parentIndent]/RequirementId"/>
<!-- Output current requirement row -->
<tr>
<td><xsl:value-of select="$hierNum"/></td>
<td><xsl:value-of select="$reqId"/></td>
<td>
<xsl:call-template name="indent">
<xsl:with-param name="level" select="$indentLevel"/>
</xsl:call-template>
<xsl:value-of select="$reqName"/>
</td>
<td><xsl:value-of select="$parentId"/></td>
<td>
<xsl:for-each select="TestCases/TestCase">
<xsl:value-of select="TestCaseId"/>
<xsl:if test="position()!=last()">, </xsl:if>
</xsl:for-each>
</td>
</tr>
<!-- Process child requirements recursively -->
<xsl:variable name="childPrefix" select="$hierNum"/>
<xsl:apply-templates
select="/RequirementData/Requirement
[substring(IndentLevel,1,string-length(IndentLevel)-3)=current()/IndentLevel]"
mode="render">
<xsl:with-param name="prefix" select="$childPrefix"/>
</xsl:apply-templates>
</xsl:template>
<!-- Indentation helper -->
<xsl:template name="indent">
<xsl:param name="level"/>
<xsl:if test="$level > 1">
<xsl:text>   </xsl:text>
<xsl:call-template name="indent">
<xsl:with-param name="level" select="$level - 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Summary Explanation
Indent Level-based hierarchy: Each requirement’s depth is determined by the length of its IndentLevel string — every 3 characters (e.g., AAA, AAAAAA, AAAAAAAAA) represents one level in the hierarchy.
Sibling numbering: For each requirement, the XSLT counts how many preceding siblings exist at the same level to assign its position number (e.g., first child = .1, second child = .2, etc.).
Parent–child relationship: The parent requirement ID is found by locating the nearest previous requirement with a shorter IndentLevel (one level higher), ensuring proper parent linkage.
Hierarchical label construction: The full hierarchy number (e.g., 3.1.4.2) is built recursively by combining the parent’s hierarchy number with the current requirement’s sibling count — creating the ordered structure seen in the report.
Report Output
Given below is the report output.

Callouts
It is possible that the outline scheme may sometime skip numbers. The logic in this report is constrained by the XSLT reporting considerations and does not completely reproduce the outline logic in the 'document' view of the requirements. This could happen because of the following potential reasons.
- Requirements that once existed but has been deleted subsequently.
- The requirement may exist but has been filtered by some information (like owner, status, etc.)
- Requirements may have imported through a third party tool with inconsistent hierarchy.
- Manual movement of requirements in the hierarchy by skipping some indent levels.
Possible Improvements
In the list of test cases or even possibly the parent requirement id, we are bringing only the identifier. Sometimes, customers may prefer to have a prefix like "TC" or "RQ" before the id. If that is the case, you may want to add the prefix in the area of the XSLT where the appropriate id is listed. For example, the following code enhancements will add a prefix "TC" before the test case id.
<td>
TC<xsl:value-of select="TestCaseId"/>
</td>