关于php:XSLT:按变量值选择一个元素

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>

我希望<xsl:value-of select="$row/$col_id" />让我根据存储在col_id变量中的列名来选择列。但是,PHP的XSLTProcessor对其进行了炸毁,并且报表无法呈现。

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的观察更新,匹配row之后的一些过程循环有助于满足以下要求:当关联的column时,省略的col_单元格必须导致空的td存在。]

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>