代码之家  ›  专栏  ›  技术社区  ›  Kannan D

对xslt中缺少的表元素进行分组和填充

  •  0
  • Kannan D  · 技术社区  · 7 年前

    我有一个如下所示的xml。我正在尝试将此xml转换为html表。“ServerName”节点成为列标题。行在“类别”名称下分组。如果任何“数据”节点都不存在“类别名称”或“参数键”,则应显示“NA”。

    我尽了最大努力自己解决这个问题,但我在分组和填充缺失的元素方面失败得很惨。非常感谢您的帮助。

    <Results>
      <Data>
        <ServerName>Server1</ServerName>
        <CategorizedData>
          <Category>
            <Parameters>
              <Parameter key="A" value="1" />
              <Parameter key="B" value="2" />
              <Parameter key="C" value="3" />
            </Parameters>
          </Category>
          <Category Name="Misc">
            <Parameters>
              <Parameter key="A" value="2" />
              <Parameter key="B" value="5" />
            </Parameters>
          </Category>
        </CategorizedData>
      </Data>
      <Data>
        <ServerName>Server2</ServerName>
        <CategorizedData>
          <Category>
            <Parameters>
              <Parameter key="A" value="10" />
              <Parameter key="B" value="20" />
              <Parameter key="D" value="30" />
            </Parameters>
          </Category>
          <Category Name="Misc">
            <Parameters>
              <Parameter key="C" value="2" />
              <Parameter key="D" value="5" />
            </Parameters>
          </Category>
        </CategorizedData>
      </Data>
    </Results>

    <table>
    	<tr>
    		<td></td>
    		<td>Server1</td>
    		<td>Server2</td>
    	</tr>
    	<tr>
    		<td>A</td>
    		<td>1</td>
    		<td>10</td>
    	</tr>
    	<tr>
    		<td>B</td>
    		<td>2</td>
    		<td>20</td>
    	</tr>
    	<tr>
    		<td>C</td>
    		<td>3</td>
    		<td>NA</td>
    	</tr>
    	<tr>
    		<td>D</td>
    		<td>NA</td>
    		<td>30</td>
    	</tr>
    	<tr>
    		<td>Misc</td>
    		<td></td>
    		<td></td>
    	</tr>
    	<tr>
    		<td>A</td>
    		<td>2</td>
    		<td>NA</td>
    	</tr>
    	<tr>
    		<td>B</td>
    		<td>5</td>
    		<td>NA</td>
    	</tr>
    	<tr>
    		<td>C</td>
    		<td>NA</td>
    		<td>2</td>
    	</tr>
    	<tr>
    		<td>D</td>
    		<td>NA</td>
    		<td>5</td>
    	</tr>
    </table>
    2 回复  |  直到 7 年前
        1
  •  1
  •   Chertkov Pavel    7 年前

    使用XSLT 1: 例子: https://xsltfiddle.liberty-development.net/bFukv8n

    <?xml version="1.0" encoding="UTF-8"?>
    

    <xsl:template match="/">
        <xsl:variable name="vMsg" select="."/>
        <xsl:variable name="vServerNames" select="/Results/Data/ServerName" />
        <table>
            <tr>
                <td/>
                <xsl:for-each select="$vServerNames">
                    <td>
                        <xsl:value-of select="."/>
                    </td>
                </xsl:for-each>
            </tr>
            <!-- Categories with no Name -->
            <xsl:for-each select="$vMsg//Category[not(@Name)]/Parameters/Parameter[not(@key = following::Category[not(@Name)]/Parameters/Parameter/@key)]">
                <xsl:variable name="vCurrKey" select="@key" />
                <tr>
                    <td>
                        <xsl:value-of select="$vCurrKey"/>
                    </td>
                    <xsl:for-each select="$vServerNames">
                        <xsl:variable name="vCurrServer" select="text()" />
                        <xsl:variable name="vCurrVal" select="$vMsg/Results/Data[ServerName = $vCurrServer]/CategorizedData/Category[not(@Name)]/Parameters/Parameter[@key = $vCurrKey]"/>
                        <xsl:choose>
                            <xsl:when test="boolean($vCurrVal)">
                                <td>
                                    <xsl:value-of select="$vCurrVal/@value"/>
                                </td>
                            </xsl:when>
                            <xsl:otherwise>
                                <td>NA</td>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                </tr>
            </xsl:for-each>
            <!-- Categories with Name -->
            <xsl:for-each select="//Category[@Name and not(@Name = following::Category/@Name)]">
                <xsl:variable name="vCatName" select="@Name"/>
                <tr>
                    <td>
                        <xsl:value-of select="$vCatName"/>
                    </td>
                    <td/>
                    <td/>
                </tr>
                <xsl:variable name="vKeys" select="$vMsg//Category[@Name = $vCatName]/Parameters/Parameter[not(@key = following::Category[@Name = $vCatName]/Parameters/Parameter/@key)]" />
                <xsl:for-each select="$vKeys">
                    <xsl:variable name="vCurrKey" select="@key" />
                    <tr>
                        <td>
                            <xsl:value-of select="$vCurrKey"/>
                        </td>
                        <xsl:for-each select="$vServerNames">
                            <xsl:variable name="vCurrServer" select="text()" />
                            <xsl:variable name="vCurrVal" select="$vMsg/Results/Data[ServerName = $vCurrServer]/CategorizedData/Category[@Name = $vCatName]/Parameters/Parameter[@key = $vCurrKey]"/>
                            <xsl:choose>
                                <xsl:when test="boolean($vCurrVal)">
                                    <td>
                                        <xsl:value-of select="$vCurrVal/@value"/>
                                    </td>
                                </xsl:when>
                                <xsl:otherwise>
                                    <td>NA</td>
                                </xsl:otherwise>
                            </xsl:choose>
                        </xsl:for-each>
                    </tr>
                </xsl:for-each>
            </xsl:for-each>
        </table>
    </xsl:template>
    

        2
  •  1
  •   Martin Honnen    7 年前

    使用XSLT 2或3,可以使用嵌套的 for-each-group :

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        expand-text="yes"
        version="3.0">
    
    
      <xsl:output method="html" indent="yes" html-version="5"/>
    
      <xsl:template match="/">
        <html>
          <head>
            <title>.NET XSLT Fiddle Example</title>
          </head>
          <body>
            <xsl:apply-templates/>
          </body>
        </html>
      </xsl:template>
    
      <xsl:template match="Results">
          <table>
              <xsl:variable name="servers" select="Data/ServerName"/>
              <thead>
                  <tr>
                      <th>Key</th>
                      <xsl:for-each select="$servers">
                          <th>{.}</th>
                      </xsl:for-each>
                  </tr>
              </thead>
              <tbody>
                  <xsl:for-each-group select=".//Category" group-by="string(@Name)">
                      <xsl:variable name="cat-group" select="current-group()"/>
                      <tr>
                          <th>{current-grouping-key()}</th>
                          <th>{$servers[1]}</th>
                          <th>{$servers[2]}</th>
                      </tr>
                      <xsl:for-each-group select="current-group()" group-by="Parameters/Parameter/@key">
                          <tr>
                              <td>{current-grouping-key()}</td>
                              <td>{($cat-group[ancestor::Data[ServerName = $servers[1]]]/Parameters/Parameter[@key = current-grouping-key()]/@value, 'N/A')[1]}</td>
                              <td>{($cat-group[ancestor::Data[ServerName = $servers[2]]]/Parameters/Parameter[@key = current-grouping-key()]/@value, 'N/A')[1]}</td>
                          </tr>
                      </xsl:for-each-group>
                  </xsl:for-each-group>
              </tbody>
          </table>
      </xsl:template>
    
    </xsl:stylesheet>
    

    https://xsltfiddle.liberty-development.net/6qM2e2i/3 给出输出

      <table>
         <thead>
            <tr>
               <th>Key</th>
               <th>Server1</th>
               <th>Server2</th>
            </tr>
         </thead>
         <tbody>
            <tr>
               <th></th>
               <th>Server1</th>
               <th>Server2</th>
            </tr>
            <tr>
               <td>A</td>
               <td>1</td>
               <td>10</td>
            </tr>
            <tr>
               <td>B</td>
               <td>2</td>
               <td>20</td>
            </tr>
            <tr>
               <td>C</td>
               <td>3</td>
               <td>N/A</td>
            </tr>
            <tr>
               <td>D</td>
               <td>N/A</td>
               <td>30</td>
            </tr>
            <tr>
               <th>Misc</th>
               <th>Server1</th>
               <th>Server2</th>
            </tr>
            <tr>
               <td>A</td>
               <td>2</td>
               <td>N/A</td>
            </tr>
            <tr>
               <td>B</td>
               <td>5</td>
               <td>N/A</td>
            </tr>
            <tr>
               <td>C</td>
               <td>N/A</td>
               <td>2</td>
            </tr>
            <tr>
               <td>D</td>
               <td>N/A</td>
               <td>5</td>
            </tr>
         </tbody>
      </table>
    

    至于服务器列的动态数量,我希望

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        expand-text="yes"
        version="3.0">
    
    
      <xsl:output method="html" indent="yes" html-version="5"/>
    
      <xsl:template match="/">
        <html>
          <head>
            <title>.NET XSLT Fiddle Example</title>
          </head>
          <body>
            <xsl:apply-templates/>
          </body>
        </html>
      </xsl:template>
    
      <xsl:template match="Results">
          <table>
              <xsl:variable name="servers" select="Data/ServerName"/>
              <thead>
                  <tr>
                      <th>Key</th>
                      <xsl:for-each select="$servers">
                          <th>{.}</th>
                      </xsl:for-each>
                  </tr>
              </thead>
              <tbody>
                  <xsl:for-each-group select=".//Category" group-by="string(@Name)">
                      <xsl:variable name="cat-group" select="current-group()"/>
                      <tr>
                          <th>{current-grouping-key()}</th>
                          <xsl:for-each select="$servers">
                              <th>{.}</th>
                          </xsl:for-each>
                      </tr>
                      <xsl:for-each-group select="current-group()" group-by="Parameters/Parameter/@key">
                          <tr>
                              <td>{current-grouping-key()}</td>
                              <xsl:for-each select="$servers">
                                  <td>{($cat-group[ancestor::Data[ServerName = current()]]/Parameters/Parameter[@key = current-grouping-key()]/@value, 'N/A')[1]}</td>
                              </xsl:for-each>
                          </tr>
                      </xsl:for-each-group>
                  </xsl:for-each-group>
              </tbody>
          </table>
      </xsl:template>
    
    </xsl:stylesheet>
    

    管理: https://xsltfiddle.liberty-development.net/6qM2e2i/4