【问题标题】:Create A Table w/ XSLT 1.0 & Concatenate Multiple Values使用 XSLT 1.0 创建一个表并连接多个值
【发布时间】:2014-02-13 00:57:59
【问题描述】:

所以,我需要使用 xslt 1.0 创建一个动态表。我看过几篇文章/帖子,但似乎无法将它们放在一起。在许多情况下,会有几个表格单元格包含空数据。在其他情况下,将有多个值需要连接到一个单元格中。这是示例 XML:

<Document>
<Records>
  <User>
    <Name>User1</Name>
    <list xid="data.set">
      <Data>
        <Column>2</Column>
        <Type>Carbs</Type>
        <RowValue>Oatmeal</RowValue>
      </Data>
      <Data>
        <Column>1</Column>
        <Type>Protein</Type>
        <RowValue>sausage</RowValue>
        <RowValue>eggs</RowValue>
        <RowValue>turkey</RowValue>
      </Data>
    </list>
  </User>
  <User>
    <Name>User2</Name>
    <list xid="data.set">
      <Data>
        <Type>Vegetables</Type>
        <Column>8</Column>
        <RowValue>Squash</RowValue>
      </Data>
      <Data>
        <Column>3</Column>
        <Type>Sweets</Type>
        <RowValue>cake</RowValue>
        <RowValue>cookies</RowValue>
      </Data>
      <Data>
        <Column>5</Column>
        <Type>Other</Type>
      </Data>
      <Data>
        <Column>6</Column>
        <Type>Beverage</Type>
        <RowValue>grape juice</RowValue>
      </Data>
    </list>
    </User>
  <User>
    <Name>User4</Name>
    <list xid="data.set">
        <Data>
          <Column>7</Column>
          <Type>Fats</Type>
          <RowValue>cashews</RowValue>
        </Data>
        <Data>
          <Column>8</Column>
          <Type>Vegetables</Type>
          <RowValue>Green Beans</RowValue>
        </Data>
        <Data>
          <Column>2</Column>
          <Type>Carbs</Type>
          <RowValue>Brown Rice</RowValue>
        </Data>
      </list>
    </User>
    <User>
      <Name>User5</Name>
      <list xid="data.set">
        <Data>
          <Column>3</Column>
          <Type>Sweets</Type>
          <RowValue>gummy worms</RowValue>
        </Data>
        <Data>
          <Column>4</Column>
          <Type>Fruit</Type>
          <RowValue>apples</RowValue>
        </Data>
      </list>
    </User>
    <User>
      <Name>User5</Name>
      <list xid="data.set">
        <Data>
          <Column>3</Column>
          <Type>Sweets</Type>
          <RowValue>gummy worms</RowValue>
        </Data>
        <Data>
          <Column>4</Column>
          <Type>Fruit</Type>
          <RowValue>grapes</RowValue>
        </Data>
      </list>
    </User>
    <User>
      <Name>User5</Name>
      <list xid="data.set">
        <Data>
          <Column>3</Column>
          <Type>Sweets</Type>
          <RowValue>gummy worms</RowValue>
        </Data>
        <Data>
          <Column>4</Column>
          <Type>Fruit</Type>
          <RowValue>grapes</RowValue>
        </Data>
      </list>
    </User>
</Records>
</Document>

编辑:在 HTML 输出中,当用户名多次存在时,表格单元格中会出现重复值(见下文)。我想删除每个单元格中存在的重复值,例如“gummy worms、gummy worms、gummy worms”。例如,列出了三个“users5”。我想保留包含“user5”的每一行,但删除这些行的每个单元格中的重复值。

<table border="1">
<thead>
<tr>
<th>
</th>
<th>Protein</th>
<th>Carbs</th>
<th>Sweets</th>
<th>Fruit</th>
<th>Other</th>
<th>Beverage</th>
<th>Fats</th>
<th>Vegetables</th>
</tr>
<tr>
<th></th>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
<th>5</th>
<th>6</th>
<th>7</th>
<th>8</th>
</tr></thead><tbody><tr><th>User1</th>
<td>sausage, eggs, turkey</td>
<td>Oatmeal</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr><th>User2</th>
<td></td>
<td></td>
<td>cake, cookies</td>
<td></td>
<td></td>
<td>grape juice</td>
<td></td>
<td>Squash</td>
</tr>
<tr><th>User4</th>
<td></td>
<td>Brown Rice</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>cashews</td>
<td>Green Beans</td>
</tr>
<tr><th>User5</th>
<td></td>
<td></td>
<td>gummy worms, gummy worms, gummy worms</td>
<td>apples, grapes, grapes</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr><th>User5</th>
<td></td>
<td></td>
<td>gummy worms, gummy worms, gummy worms</td>
<td>apples, grapes, grapes</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr><th>User5</th>
<td></td>
<td></td>
<td>gummy worms, gummy worms, gummy worms</td>
<td>apples, grapes, grapes</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>

这是我试图完成这项工作的非常微弱的尝试。我是新手,请温柔...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">


  <xsl:key name="food-by-Category" match="Data" use="Column" />
 <xsl:key name="food-by-Value" match="Columns" use="RowValue" />

  <xsl:template match="/Document/Records/User/list[@xid = 'data.set']">

 <table><tr>
    <xsl:for-each select="Data[count(. | key('food-by-Category', Column)[1]) = 1]">
      <!-- Sort by the Category -->
      <xsl:sort select="Column" />
 <td>
      <xsl:value-of select="Type" />
</td>
</xsl:for-each>
</tr>

  <xsl:for-each select="Data[count(. | key('food-by-Category', Column)[1]) = 1]">
 <tr>
      <xsl:for-each select="key('food-by-Category', Column)">
         <!-- Sort by the item Value -->
        <xsl:sort select="RowValue" />
<td>
        <xsl:value-of select="RowValue" />
</td>      
    </xsl:for-each>
 </tr>
</xsl:for-each>
</table>
  </xsl:template>
</xsl:stylesheet>

如您所见,当有多个 时,它不会将表格标题/单元格组合在一起或连接值。

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    哇。我认为您至少有三个不同的问题值得:

    1. 如何生成唯一的列标题;
    2. 如何从稀疏数组中获取数据到表中;
    3. 如何将多个匹配的数据项连接到一个单元格中。

    如果这还不够复杂,您可以通过修改最后一个用户的数据(使 &lt;Name&gt; 成为 &lt;list&gt; 的子代而不是兄弟姐妹)来确保它。

    不管怎样,看看下面的样式表:

    <?xml version="1.0" encoding="utf-8"?>
    <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:key name="data_by_column" match="Data" use="Column" />
    <xsl:key name="value_by_cell" match="RowValue" use="concat(ancestor::User/Name, '|', preceding-sibling::Column)" />
    
    <xsl:template match="/">
    <table border="1">
    <thead>
        <tr>
            <th/>
            <!--unique column headers -->
            <xsl:for-each select="Document/Records/User/list/Data[count(. | key('data_by_column', Column)[1]) = 1]">
            <xsl:sort select="Column" data-type="number" order="ascending"/>
            <th><xsl:value-of select="Type"/></th>
            </xsl:for-each>
        </tr>
        <tr>
            <th/>
            <!--unique column headers -->
            <xsl:for-each select="Document/Records/User/list/Data[count(. | key('data_by_column', Column)[1]) = 1]">
            <xsl:sort select="Column" data-type="number" order="ascending"/>
            <th><xsl:value-of select="Column"/></th>
            </xsl:for-each>
        </tr>
    </thead>
    <tbody>
        <xsl:for-each select="Document/Records/User">
        <xsl:variable name="row" select="Name" />
        <tr>
            <th><xsl:value-of select="$row"/></th>
            <!-- for each unique column header -->
            <xsl:for-each select="/Document/Records/User/list/Data[count(. | key('data_by_column', Column)[1]) = 1]">
            <xsl:sort select="Column" data-type="number" order="ascending"/>
            <xsl:variable name="col" select="Column" />
            <!-- new cell -->
            <td>
                <!-- get matching data -->
                <xsl:for-each select="key('value_by_cell', concat($row, '|', $col))">
                    <xsl:value-of select="."/>
                    <xsl:if test="position()!=last()">
                        <xsl:text>, </xsl:text>
                    </xsl:if>
                </xsl:for-each>     
            </td>
            </xsl:for-each>
        </tr>
        </xsl:for-each>
    </tbody>
    </table>
    </xsl:template>
    </xsl:stylesheet>
    

    注意:我本可以先将相同的代码转储到一个变量中,从而消除对唯一列标题重复三次相同的代码,但我没时间了。

    【讨论】:

    • 这非常有效。我遇到的唯一问题是,当有一个 &或它破坏的文档中的任何其他 html 实体。我尝试将 , 放在第 44 行,但它似乎不起作用。如何解决这个问题?
    • @user3303297 无法重现该问题。您为什么不发布一个关于此的新问题,最好与其他问题隔离开来?
    • 谢谢。我想通了,但我想知道您是否可以帮助我解决最后一个问题。似乎当有一个同名用户时,每个用户的值都是重复的。如果用户名存在不止一次,那很好,但我不希望该用户的数据重复多次。 IE。 粘虫,粘虫,粘虫。粘性蠕虫应该只出现一次。
    • 我不确定我是否遵循。您能否编辑您的问题,以便重复数据出现在示例输入中 - 并相应地调整所需的输出?
    • 我根据您提供的 xsl 样式表更新了 XML 和 HTML 输出。您现在应该能够看到每个单元格中的重复值。
    【解决方案2】:

    我是使用递归模板完成的。我只是没有对数据进行排序,列数是硬连线的。您可以改进它,在所有列中添加一个键并选择最大的数字,或者通过变量或参数设置它。

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    
        <xsl:output method="html" indent="yes"/>
    
        <xsl:key name="food-by-Category" match="Data" use="Type" />
    
        <!-- Match the Records tree, set the table elements and first row -->
        <xsl:template match="Records">
            <table width="800" border="1">
                <tbody>
                    <tr>
                        <td>Name</td>
                        <xsl:for-each select="User/list/Data[count(. | key('food-by-Category', Type)[1]) = 1]">
                            <td><xsl:value-of select="Type"/></td>
                        </xsl:for-each>
                    </tr>
                    <!-- Apply the templates for each User subtree -->
                    <xsl:apply-templates select="User" />
                </tbody>
            </table>
        </xsl:template>
    
        <!-- Set up one row for each User, get User name -->
        <xsl:template match="User">
            <tr>
                <td><xsl:value-of select="Name"/></td>
                <!-- Apply the templates for the list subtree -->
                <xsl:apply-templates select="list" />
            </tr>
        </xsl:template>
    
        <!-- This is a recursive template used to generate the columns 
             It's hardwired to generate 8 columns -->
        <xsl:template name="empty-tds">
            <xsl:param name="columns" />
            <xsl:param name="i" />
            <xsl:if test="$i &lt;= 8">
                <!-- Fills in each column with RowValues -->
                <td><xsl:apply-templates select="Data[Column = $i]/RowValue" /></td>
                <xsl:call-template name="empty-tds">
                    <xsl:with-param name="i" select="$i + 1" />
                </xsl:call-template>
            </xsl:if>
        </xsl:template>
    
        <!-- This calls the template above and generates columns -->
        <xsl:template match="list">
            <xsl:call-template name="empty-tds">
                <xsl:with-param name="i" select="1" />
            </xsl:call-template>
        </xsl:template>
    
        <!-- This one concatenates multiple RowValues within Data -->
        <xsl:template match="RowValue">
            <xsl:value-of select="."/>
            <xsl:if test="position() != last()">
                <xsl:text>, </xsl:text>
            </xsl:if>
        </xsl:template>
    
    </xsl:stylesheet>
    

    最后一个用户 (#6) 未打印,因为在源中它被放置在 list 内。

    【讨论】:

      猜你喜欢
      • 2020-06-21
      • 2018-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-08
      • 2020-09-05
      • 1970-01-01
      相关资源
      最近更新 更多