Это звучит как домашнее задание: -)
Вы работаете с двумя вещами здесь:
- Элементы с произвольным именем, к которым необходимо применить шаблон XSLT, и
- Определение типа содержимого элемента (текст или фрагмент XML).
Вы хотите использовать шаблон, который может произвольно сопоставлять элементы в вашем XML (то есть не элементы с определенным именем). <xsl:template match="*">
будет соответствовать всем элементам в вашем XML-документе.
Когда вы сталкиваетесь с элементом, вам нужно создать таблицу:
<xsl:template match="*">
<table border="1px">
</table>
</xsl:template>
Теперь мы хотим выяснить, имеем ли мы дело с фрагментом XML (элементом) или фрагментом текста. Для этого мы подходим на node()
. Помните, что узел может быть элементом, текстом, пробелом, инструкцией обработки или комментарием в документе XML. Когда вы сопоставили узел, вы хотите создать новую строку таблицы и отобразить имя текущего узла:
<xsl:template match="node()">
<tr>
<td>
<xsl:value-of select="local-name()"/>
</td>
</tr>
</xsl:template>
Затем вам нужно выяснить, является ли этот узел текстовым или нет. Вы можете использовать <xsl:if>
или <xsl:choose>
. Я склонен предпочесть последнее. Если это текстовый узел, отобразите значение текста, иначе обработайте узел как фрагмент XML и снова вызовите наш начальный шаблон (это рекурсивная часть).
...
<xsl:choose>
<xsl:when test="current() = text()">
<td>
<xsl:value-of select="." />
</td>
</xsl:when>
<xsl:otherwise>
<td>
<xsl:apply-templates select="*" mode="table"/>
</td>
</xsl:otherwise>
</xsl:choose>
...
Вот окончательное решение.
<xsl:template match="/root">
<xsl:apply-templates select="*" mode="table" />
</xsl:template>
<xsl:template match="*" mode="table">
<table border="1px">
<xsl:apply-templates select="." mode="table-row" />
</table>
</xsl:template>
<xsl:template match="node()" mode="table-row">
<tr>
<td>
<xsl:value-of select="local-name()"/>
</td>
<xsl:choose>
<xsl:when test="current() = text()">
<td>
<xsl:value-of select="." />
</td>
</xsl:when>
<xsl:otherwise>
<td>
<xsl:apply-templates select="*" mode="table"/>
</td>
</xsl:otherwise>
</xsl:choose>
</tr>
</xsl:template>
Я использую атрибут mode
в шаблоне, поскольку элемент также является узлом в документе XML, и <xsl:apply-templates select="*"/>
будет соответствовать как <xsl:template match="*">
, так и <xsl:template match="node()">
. Использование атрибута mode
устраняет неоднозначность.