xml - XSLT - 创建动态网格

标签 xml xslt xslt-1.0 xslt-2.0

我正在使用 xslt 创建动态表(网格),

XSLT:

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>

     <xsl:key name="RowAttribsByName" match="Row/@*"

      use="concat(generate-id(..), '|', name())"/>

 <xsl:variable name="vColNames" select=
  "/*/Columns/*[not(@Hidden = 'true')]/@Name"/>

 <xsl:template match="/*">
  <table border="1">
    <tr>
     <xsl:apply-templates select="Columns/*"/>
    </tr>
    <xsl:apply-templates select="Rows/Row"/>
  </table>
 </xsl:template>

 <xsl:template match="Column[not(@Hidden = 'true')]">
  <td><xsl:value-of select="@Caption"/></td>
 </xsl:template>

 <xsl:template match="Row">
  <tr>
   <xsl:apply-templates select="$vColNames">
     <xsl:with-param name="pRowId"
          select="generate-id()"/>
   </xsl:apply-templates>
  </tr>
 </xsl:template>

 <xsl:template match="Column/@*">
  <xsl:param name="pRowId"/>

  <td width="50%">
    <xsl:value-of select=
      "key('RowAttribsByName',
           concat($pRowId, '|', .)
           )
    "/>
  </td>
 </xsl:template>
</xsl:stylesheet>

XML 数据:

<TableData>
    <Columns>
        <Column Name="ID" Hidden="true" />
        <Column Name="Name" Caption="Item Name" Link="Yes" Sort="Yes"/>
        <Column Name="Desc" Caption="Item Description" />
    </Columns>
    <Rows>
        <Row ID="0" Name="A" />
        <Row ID="1" Name="B" Desc="Some description"/>
        <Row ID="3" Name="C" />
    </Rows>
</TableData>

预期输出:

<table border="1">
    <tbody>
        <tr>
            <td>
                <a onclick="javascript:SortColumn('Item Name')">Item Name</a>
            </td>
            <td>
                <a onclick="javascript:SortColumn('Item Description')">Item Name</a></td>
        </tr>
        <tr>
            <td width="50%">
                <a onclick="javascript:OpenDifferentPage('A','0')">A</a>
            </td>
            <td width="50%"></td>
        </tr>
        <tr>
            <td width="50%">B</td>
            <td width="50%">Some description</td>
        </tr>
        <tr>
            <td width="50%">C</td>
            <td width="50%"></td>
        </tr>
    </tbody>
</table>

我是 XSLT 初学者,

我想在这里检查一下,如果列有“链接”属性="is",那么我需要在 anchor 标记(名称)之间显示数据。

我在此列上创建了许多复杂的功能。所以在这里我可以为特定列制作模板(列是 15 但它取决于用户选择,如果用户选择 8 列进行显示,并且还必须保持列的顺序)

最好是,如果我可以为所有列创建新模板,并根据传递的列数据维护列顺序。

谢谢大家的期待

最佳答案

对于 XSLT 初学者来说,您已经有了一个很好的开始,尤其是使用 xsl:key 时。

为了回答您直接的问题,您可以做什么,而不是像目前那样使用与 Column 元素的属性匹配的单个模板......

<xsl:template match="Column/@*">

设置Link属性后,您可以有一个与之匹配的显式模板

<xsl:template match="Column[@Link='Yes']/@*">

在此模板中,您可以添加额外的代码来输出a链接。请注意,如果您传入实际的 Row 作为参数,而不是传递 Row 的 generate-id 值,则可能会稍微简单一些,因为这会使获取 ID 属性的信息稍微简洁一些。

 <xsl:template match="Column[@Link='Yes']/@*">
  <xsl:param name="pRow"/>
  <xsl:variable name="pRowId" select="generate-id($pRow)"/>
  <xsl:variable name="pValue" select="key('RowAttribsByName', concat($pRowId, '|', .))" />
  <td width="50%">
     <a onclick="javascript:OpenDifferentPage('{$pValue}','{$pRow/@ID}')">
        <xsl:value-of select="$pValue"/>
     </a>
  </td>
 </xsl:template>

请注意此处在创建 onclick 属性时使用的属性值模板。大括号表示要计算的表达式,而不是按字面意思输出。

要使此模板正常工作,您还需要修改其他模板以显式匹配属性,其中链接属性未设置为"is"

<xsl:template match="Column[not(@Link='Yes')]/@*">

这是因为,否则原始模板会匹配链接为"is"的情况,并与新模板具有相同的优先级,这是不允许的。

试试这个 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output omit-xml-declaration="yes" indent="yes"/>
   <xsl:key name="RowAttribsByName" match="Row/@*" use="concat(generate-id(..), '|', name())"/>
   <xsl:variable name="vColNames" select="/*/Columns/*[not(@Hidden = 'true')]/@Name"/>

   <xsl:template match="/*">
      <table border="1">
         <tr>
            <xsl:apply-templates select="Columns/*"/>
         </tr>
         <xsl:apply-templates select="Rows/Row"/>
      </table>
   </xsl:template>

   <xsl:template match="Column[not(@Hidden = 'true')]">
      <td>
         <xsl:value-of select="@Caption"/>
      </td>
   </xsl:template>

   <xsl:template match="Row">
      <tr>
         <xsl:apply-templates select="$vColNames">
            <xsl:with-param name="pRow" select="."/>
         </xsl:apply-templates>
      </tr>
   </xsl:template>

   <xsl:template match="Column[not(@Link='Yes')]/@*">
      <xsl:param name="pRow"/>
      <xsl:variable name="pRowId" select="generate-id($pRow)"/>
      <xsl:variable name="pValue" select="key('RowAttribsByName', concat($pRowId, '|', .))"/>
      <td width="50%">
         <xsl:value-of select="$pValue"/>
      </td>
   </xsl:template>

   <xsl:template match="Column[@Link='Yes']/@*">
      <xsl:param name="pRow"/>
      <xsl:variable name="pRowId" select="generate-id($pRow)"/>
      <xsl:variable name="pValue" select="key('RowAttribsByName', concat($pRowId, '|', .))"/>
      <td width="50%">
         <a onclick="javascript:OpenDifferentPage('{$pValue}','{$pRow/@ID}')">
            <xsl:value-of select="$pValue"/>
         </a>
      </td>
   </xsl:template>
</xsl:stylesheet>

这种方法有一些缺点。有一些重复的代码,而且如果 Column 元素上有其他影响列输出的属性,管理起来也会更加困难。

这是 XSLT 的另一个版本,它使用 mode 元素重复匹配 Column 属性,允许您根据需要输出更多元素

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output omit-xml-declaration="yes" indent="yes"/>
   <xsl:key name="RowAttribsByName" match="Row/@*" use="concat(generate-id(..), '|', name())"/>
   <xsl:variable name="vColNames" select="/*/Columns/*[not(@Hidden = 'true')]/@Name"/>

   <xsl:template match="/*">
      <table border="1">
         <tr>
            <xsl:apply-templates select="Columns/*"/>
         </tr>
         <xsl:apply-templates select="Rows/Row"/>
      </table>
   </xsl:template>

   <xsl:template match="Column[not(@Hidden = 'true')]">
      <td>
         <xsl:value-of select="@Caption"/>
      </td>
   </xsl:template>

   <xsl:template match="Row">
      <tr>
         <xsl:apply-templates select="$vColNames">
            <xsl:with-param name="pRow" select="."/>
         </xsl:apply-templates>
      </tr>
   </xsl:template>

   <xsl:template match="Column/@Name">
      <xsl:param name="pRow"/>
      <xsl:variable name="pRowId" select="generate-id($pRow)"/>
      <xsl:variable name="pValue" select="key('RowAttribsByName', concat($pRowId, '|', .))"/>
      <td width="50%">
         <xsl:apply-templates select=".." mode="link">
            <xsl:with-param name="pRow" select="$pRow"/>
            <xsl:with-param name="pValue" select="$pValue"/>
         </xsl:apply-templates>
      </td>
   </xsl:template>

   <xsl:template match="Column[@Link='Yes']" mode="link">
      <xsl:param name="pRow"/>
      <xsl:param name="pValue"/>
      <a onclick="javascript:OpenDifferentPage('{$pValue}','{$pRow/@ID}')">
         <xsl:apply-templates select="self::*" mode="value">
            <xsl:with-param name="pRow" select="$pRow"/>
            <xsl:with-param name="pValue" select="$pValue"/>
         </xsl:apply-templates>
      </a>
   </xsl:template>

   <xsl:template match="Column" mode="link">
      <xsl:param name="pRow"/>
      <xsl:param name="pValue"/>
      <xsl:apply-templates select="self::*" mode="value">
         <xsl:with-param name="pRow" select="$pRow"/>
         <xsl:with-param name="pValue" select="$pValue"/>
      </xsl:apply-templates>
   </xsl:template>

   <xsl:template match="Column" mode="value">
      <xsl:param name="pRow"/>
      <xsl:param name="pValue"/>
      <xsl:value-of select="$pValue"/>
   </xsl:template>
</xsl:stylesheet>

请注意,在此示例中,链接有两个模板

<xsl:template match="Column[@Link='Yes']" mode="link">

<xsl:template match="Column" mode="link">

在这种情况下,第二个不需要检查 Link 属性。如果模板仅与显式元素名称匹配,则其优先级将低于使用 xpath 表达式限定的模板。因此,第二个模板将永远不会匹配链接为"is"的情况。

关于xml - XSLT - 创建动态网格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18030044/

相关文章:

xml - 如何在 xsl 中使用 xsl 变量

java - 多类型List注解翻译: JAXB to SimpleXML

xslt - 如何根据另一个节点列表的内容过滤节点列表

xml - 如何计算同名元素? XML -> Xquery

xslt - 在 XSL 中使用 Map 来扩展缩写

c# - XML读取子节点

java - 如何从 xml 文件中提取数据作为我的代码的输入

xslt - 根据参数使用 XSLT 更新元素的文本

xslt - 获取元素的下一个同级元素,但位于同一分支上?

javascript - XSLT - 自动打开 HREF