XSLT: Select an element by variable value
我有一些XML结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <report> <columns> <column col_id="col_1">Column 1 title</column> <column col_id="col_2">Column 2 title</column> <column col_id="col_3">Column 3 title</column> </columns> <rows> <row> <col_1>Value 1</col_1> <!-- No col_2 value exists --> <col_3>value 3</col_3> </row> <row> <col_1>Value 1</col_1> <col_2>Value 2</col_2> <col_3>value 3</col_3> <col_4>Value 4</col_4><!-- Not interested in this value --> </row> </rows> </report> |
我想使用XSLT将这些数据输出为HTML表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" encoding="utf-8" indent="yes" /> <xsl:template match="Report"> <!-- Get the column names --> <xsl:variable name="arr_columns" select="./columns/*" /> <table style="width:100%"> <thead> <tr class="header"> <!-- Columns first --> <xsl:for-each select="$arr_columns"> <th><xsl:value-of select="." /></th> </xsl:for-each> </tr> </thead> <tbody> <!-- Now the actual data --> <xsl:for-each select="./rows/row"> <xsl:variable name="row" select="." /> <tr> <xsl:for-each select="$arr_columns"> <xsl:variable name="col_id" select="./@column_id" /> <td><xsl:value-of select="$row/$col_id" /></td> </xsl:for-each> </tr> </xsl:for-each> </tbody> </table> </xsl:template> </xsl:stylesheet> |
我希望
PHP Warning: XSLTProcessor::transformToXml(): No stylesheet associated to this object
我尝试仅输出$ row(按预期输出整个行作为字符串)和$ row / col_1(按预期输出col_1的内容),但是尝试基于变量的值似乎不起作用。如果输出$ col_id的值,它将显示我要输出的节点的名称,以便在循环中正确设置该变量。
我正在猜测这是可能的,而且我做错了,但是我很难找到如何正确执行此操作的示例。我确实找到了一些示例,这些示例使您可以基于属性选择节点,但是如您所见,我没有的节点没有属性,它们的名称表示它们所拥有的属性。
有人可以为这种情况编写正确的选择器吗?
为完整起见,这是我希望生成的输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <table> <thead> <tr> <th>Column 1 title</th> <th>Column 2 title</th> <th>Column 3 title</th> </tr> </thead> <tbody> <tr> <td>Value 1</td> <td></td> <td>value 3</td> </tr> <tr> <td>Value 1</td> <td>value 2</td> <td>value 3</td> </tr> </tbody> </table> |
以这种方式尝试吗?
XSLT 1.0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:template match="/report"> <xsl:variable name="columns" select="columns/column" /> <table style="width:100%"> <thead> <tr> <xsl:for-each select="$columns"> <th><xsl:value-of select="." /></th> </xsl:for-each> </tr> </thead> <tbody> <xsl:for-each select="rows/row"> <xsl:variable name="current-row" select="." /> <tr> <xsl:for-each select="$columns"> <td><xsl:value-of select="$current-row/*[local-name()=current()/@col_id]"/></td> </xsl:for-each> </tr> </xsl:for-each> </tbody> </table> </xsl:template> </xsl:stylesheet> |
特别是因为您在输入XML的元素和目标HTML的元素之间具有如此清晰的映射,所以请考虑使用一种更加面向匹配的声明性方法,而不是当前的基于过程的基于循环的方法:
声明式方法
[根据@ michael.hor257k的观察更新,匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" encoding="utf-8" indent="yes" /> <xsl:template match="report"> <table style="width:100%"> <xsl:apply-templates/> </table> </xsl:template> <xsl:template match="row"> <tr> <xsl:variable name="row" select="."/> <xsl:for-each select="../../columns/column"> <xsl:variable name="col_id" select="@col_id"/> <td> <xsl:value-of select="$row/*[local-name()=$col_id]"/> </td> </xsl:for-each> </tr> </xsl:template> <xsl:template match="columns"> <thead><xsl:apply-templates/></thead> </xsl:template> <xsl:template match="column"> <th><xsl:apply-templates/></th> </xsl:template> <xsl:template match="rows"> <tbody><xsl:apply-templates/></tbody> </xsl:template> </xsl:stylesheet> |