对于给定的xml,我需要生成一个html表来表示xml中的值。 我需要任何keyN的递归,如果valueN是文本然后只是打印它。如果valueN是xml,则使用它的值打印(嵌套)表。我认为我对如何正确使用XSLT递归缺乏了解是问题的基础。任何帮助赞赏。
输入:
<root>
<key1> Text Value </key1>
<key2>
<a> aaa </a>
<b> bbb </b>
</key2>
<keyN> valueN </keyN>
<root>
输出:
<table border="1px">
<tr>
<td> key1 </td>
<td> Text Value </td>
</tr>
<tr>
<td> key2 </td>
<td>
<table border="1px">
<tr> <td> a </td> <td> aaa </td> </tr>
<tr> <td> b </td> <td> bbb </td> </tr>
</table>
</td>
</tr>
<tr>
<td> keyN </td>
<td>
valueN (if valueN is text)
OR
<table> ... </table> (if valueN is xml)
<td>
</tr>
</table>
答案 0 :(得分:5)
此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/*//*[1]">
<table border="1">
<xsl:call-template name="makeRow"/>
</table>
</xsl:template>
<xsl:template match="*" name="makeRow">
<tr>
<td>
<xsl:value-of select="name()"/>
</td>
<td>
<xsl:apply-templates select="node()[1]"/>
</td>
</tr>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<xsl:template match="/*">
<xsl:apply-templates select="node()[1]"/>
</xsl:template>
</xsl:stylesheet>
输出:
<table border="1">
<tr>
<td>key1</td>
<td> Text Value </td>
</tr>
<tr>
<td>key2</td>
<td>
<table border="1">
<tr>
<td>a</td>
<td> aaa </td>
</tr>
<tr>
<td>b</td>
<td> bbb </td>
</tr>
</table></td>
</tr>
<tr>
<td>keyN</td>
<td> valueN </td>
</tr>
</table>
注意:这使用细粒度的遍历模式。三个规则:“根元素的第一个子后代”,输出table
并调用makeRow
; makeRow
(匹配任何不是第一个子元素或根元素的元素)输出tr
和具有名称和第一个子应用程序的表格单元格,然后将模板应用于下一个兄弟;根元素规则,启动细粒度遍历。
答案 1 :(得分:3)
此转化:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<table border="1px">
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="*[*][parent::*]">
<tr>
<td><xsl:value-of select="name()"/></td>
<td>
<table border="1px">
<xsl:apply-templates/>
</table>
</td>
</tr>
</xsl:template>
<xsl:template match="*[not(*)]">
<tr>
<td><xsl:value-of select="name()"/></td>
<td><xsl:value-of select="."/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<root>
<key1> Text Value </key1>
<key2>
<a> aaa </a>
<b> bbb </b>
</key2>
<keyN> valueN </keyN>
</root>
生成想要的正确结果:
<table border="1px">
<tr>
<td>key1</td>
<td> Text Value </td>
</tr>
<tr>
<td>key2</td>
<td>
<table border="1px">
<tr>
<td>a</td>
<td> aaa </td>
</tr>
<tr>
<td>b</td>
<td> bbb </td>
</tr>
</table>
</td>
</tr>
<tr>
<td>keyN</td>
<td> valueN </td>
</tr>
</table>
请注意XSLT的强大功能:
没有明确的递归。
任何模板内无条件。
完全推送式处理。
答案 2 :(得分:0)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<!-- apply root as a table -->
<xsl:apply-templates select="root" mode="table"/>
</body>
</html>
</xsl:template>
<xsl:template match="node()[not(self::text())]" mode="table">
<table border="1px">
<!-- create table and process children as rows -->
<xsl:apply-templates select="node()" mode="row"/>
</table>
</xsl:template>
<xsl:template match="node()[not(self::text())]" mode="row">
<tr>
<!-- make decision here.
If row contains only text - apply is as a simple row
In case there are some other nodes proces them as a table.
-->
<xsl:choose>
<xsl:when test=". = text()">
<xsl:apply-templates select="." mode="column"/>
</xsl:when>
<xsl:otherwise>
<td><xsl:value-of select="name()"/></td>
<td><xsl:apply-templates select="." mode="table"/></td>
</xsl:otherwise>
</xsl:choose>
</tr>
</xsl:template>
<xsl:template match="node()" mode="column">
<td><xsl:value-of select="name()"/></td>
<td><xsl:value-of select="."/></td>
</xsl:template>
</xsl:stylesheet>
输出:
<html>
<body>
<table border="1px">
<tr>
<td>key1</td>
<td>Text Value</td>
</tr>
<tr>
<td>key2</td>
<td>
<table border="1px">
<tr>
<td>a</td>
<td>aaa</td>
</tr>
<tr>
<td>b</td>
<td>bbb</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>keyN</td>
<td>valueN</td>
</tr>
</table>
</body>
</html>
顺便说一下,重写xsl会更好:选择两个独立的模板。
答案 3 :(得分:0)
这听起来像家庭作业: - )
你在这里做了两件事:
您希望使用可以任意匹配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
属性可消除歧义。
答案 4 :(得分:0)
增加显示属性的功能
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/*//*[1]">
<table border="1">
<xsl:call-template name="makeRow" />
</table>
</xsl:template>
<xsl:template match="*" name="makeRow">
<tr>
<td><xsl:value-of select="name()" /> <xsl:if
test="count(@*) > 0">
<table>
<xsl:apply-templates select="@*" />
</table>
</xsl:if></td>
<td><xsl:apply-templates select="node()[1]" /></td>
</tr>
<xsl:apply-templates select="following-sibling::node()[1]" />
</xsl:template>
<xsl:template match="/*">
<xsl:apply-templates select="node()[1]" />
</xsl:template>
<xsl:template match="@*">
<tr>
<td>@<xsl:value-of select="name()" /></td>
<td><xsl:value-of select="." /></td>
</tr>
</xsl:template>
</xsl:stylesheet>