Я собираюсь просто ответить на комментарий внутри шаблона (возможно, ваш код нуждается в отладке и рефакторинге):
<!-- need to change /Datacenters to something
else so it will work on all nodes -->
Чтобы избежать жесткого кодирования:
1) заменить XPath следующим образом:
//tests/Datacenters/test_name
с //tests/*/test_name
2) Исправить итерацию (совершенно неверно), должно быть:
<xsl:for-each select="//tests/Datacenters">
и вы хотите:
<xsl:for-each select="//tests/*">
3) Наконец, замените:
<testcase classname="Datacenters">
с
<testcase classname="{local-name(.)}">
Редактировать после комментариев
Я собираюсь ответить с упрощенным выводом, просто чтобы показать вам, как работает группировка в XSLT 2.0 . Надеюсь, что этот ответ приемлем для вас, ваш настоящий шаблон немного сложно проверить здесь:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="tests">
<testsuites>
<xsl:for-each-group select="*" group-by="local-name()">
<testsuite name="{current-grouping-key()}">
<xsl:for-each select="current-group()">
<testcase classname="{current-grouping-key()}"/>
</xsl:for-each>
</testsuite>
</xsl:for-each-group>
</testsuites>
</xsl:template>
</xsl:stylesheet>
, примененное к входной выборке, указанной в вашем вопросе, дает:
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite name="Datacenters">
<testcase classname="Datacenters"/>
<testcase classname="Datacenters"/>
</testsuite>
<testsuite name="Network">
<testcase classname="Network"/>
</testsuite>
</testsuites>