XSLT格式化删除空列(和标题)

时间:2010-12-14 16:05:35

标签: xslt

我有一个数据库字段,我正在拉出xml。此字段包含来自多个XML Feed的内容,我需要两个。我在页面上显示XML并使用XSLT对其进行格式化。

我的问题是,每个消息中最多可以有40个元素,我正在寻找大约30个。然而,并非所有消息都将包含所有30个。我需要帮助找出如何删除列没有可显示的数据。

如果我可以使用XSLT那么好,如果它是JavaScript(Jquery)那么那也没关系。一次永远不会有多行和一个标题。

以下是XML

的示例
<MessageToUser>
  <Name>Bob</Name> 
  <MessageType>Text Message</MessageType> 
  <MessageID>121223</MessageID>
  <ResponseTo />
  <Message>Call Me Please </Message> 
  <OfficePhone>555-555-1212</OfficePhone>
  <CellPhone>555-555-5555</CellPhone>
</MessageToUser>

这是我正在使用的XSL

<xsl:template match="/">
<html>
<head>
  <style type="text/css">
    .Header{min-width: 100px;background-color:#9acddd;}
  </style>
</head>
<body>
  <table border="1">
    <tr>
        <th class="Header">Name</th>
        <th class="Header">Message</th>
        <th class="Header">Cell Phone</th>
        <th class="Header">Office Phone</th>
        <th class="Header">Message Type</th>
        <th class="Header">Message Time</th>
        <th class="Header">Message ID</th>
      </tr>
      <xsl:for-each select="MessageFromUser">
        <tr>
          <td><xsl:value-of select="Name" /></td>
          <td><xsl:value-of select="Message" /></td>
          <td><xsl:value-of select="CellPhone" /></td>
          <td><xsl:value-of select="OfficePhone" /></td>
          <td><xsl:value-of select="MessageType" /></td>
          <td><xsl:value-of select="MessageTime" /></td>
          <td><xsl:value-of select="MessageID" /></td>
        </tr>
      </xsl:for-each>
      <xsl:for-each select="MessageToUser">
        <tr>
          <td><xsl:value-of select="Name" /></td>
          <td><xsl:value-of select="Message" /></td>
          <td><xsl:value-of select="CellPhone" /></td>
          <td><xsl:value-of select="OfficePhone" /></td>
          <td><xsl:value-of select="MessageType" /></td>
          <td><xsl:value-of select="MessageTime" /></td>
          <td><xsl:value-of select="MessageID" /></td>
        </tr>
      </xsl:for-each>
    </table>
 </body>

 

使用此XML MessageTime为空,应删除该列。

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:3)

这种转变:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" exclude-result-prefixes="my" >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:Layout>
  <html>
   <head>
      <style type="text/css">
        .Header{min-width: 100px;background-color:#9acddd;}
      </style>
   </head>
     <body>
      <table border="1">
        <tr>
            <header name="Name">Name</header>
            <header name="Message">Message</header>
            <header name="CellPhone">Cell Phone</header>
            <header name="OfficePhone">Office Phone</header>
            <header name="MessageType">Message Type</header>
            <header name="MessageTime">Message Time</header>
            <header name="MessageID">Message ID</header>
        </tr>
        <every select="MessageFromUser">
         <tr>
            <Name/>
            <Message/>
            <CellPhone/>
            <OfficePhone/>
            <MessageType/>
            <MessageTime/>
            <MessageID/>
         </tr>
        </every>
        <every select="MessageToUser">
         <tr>
            <Name/>
            <Message/>
            <CellPhone/>
            <OfficePhone/>
            <MessageType/>
            <MessageTime/>
            <MessageID/>
         </tr>
        </every>
       </table>
      </body>
   </html>
 </my:Layout>

 <xsl:variable name="vLayout" select="document('')/*/my:Layout/*"/>
 <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="node()|@*">
   <xsl:param name="pContextNode"/>
     <xsl:copy>
       <xsl:apply-templates select="node()|@*">
       <xsl:with-param name="pContextNode" select="$pContextNode"/>
       </xsl:apply-templates>
     </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "Name|Message|CellPhone|OfficePhone|MessageType|MessageTime|MessageID">
  <xsl:param name="pContextNode"/>

  <xsl:if test="not($vDoc/*/*[not(*[name()=name(current())])])">
    <td><xsl:value-of select="$pContextNode/*[name()=name(current())]"/></td>
  </xsl:if>

 </xsl:template>

 <xsl:template match="/*">
  <xsl:apply-templates select="$vLayout"/>
 </xsl:template>

 <xsl:template match="header">
  <xsl:if test="not($vDoc/*/*[not(*[name()=current()/@name])])">
    <th class="Header"><xsl:value-of select="."/></th>
  </xsl:if>
 </xsl:template>

 <xsl:template match="every">
   <xsl:variable name="vLayoutTop" select="."/>
   <xsl:for-each select="$vDoc/*/*[name()=current()/@select]">
    <xsl:apply-templates select="$vLayoutTop/*">
     <xsl:with-param name="pContextNode" select="."/>
    </xsl:apply-templates>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

应用于此XML文档(提供的文档并添加了MessageFromUser):

<Messages>
    <MessageFromUser>
        <Name>Bob</Name>
        <MessageType>Text Message</MessageType>
        <MessageID>121223</MessageID>
        <ResponseTo />
        <Message>Call Me Please </Message>
        <OfficePhone>555-555-1212</OfficePhone>
        <CellPhone>555-555-5555</CellPhone>
    </MessageFromUser>
    <MessageToUser>
        <Name>Bob</Name>
        <MessageType>Text Message</MessageType>
        <MessageID>121223</MessageID>
        <ResponseTo />
        <Message>Call Me Please </Message>
        <OfficePhone>555-555-1212</OfficePhone>
        <CellPhone>555-555-5555</CellPhone>
    </MessageToUser>
</Messages>

生成所需的输出,其中不显示空列1MessageTime`:

<html xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my">
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   <style type="text/css">
        .Header{min-width: 100px;background-color:#9acddd;}
      </style></head>
   <body>
      <table border="1">
         <tr>
            <th class="Header">Name</th>
            <th class="Header">Message</th>
            <th class="Header">Cell Phone</th>
            <th class="Header">Office Phone</th>
            <th class="Header">Message Type</th>
            <th class="Header">Message ID</th>
         </tr>
         <tr>
            <td>Bob</td>
            <td>Call Me Please </td>
            <td>555-555-5555</td>
            <td>555-555-1212</td>
            <td>Text Message</td>
            <td>121223</td>
         </tr>
         <tr>
            <td>Bob</td>
            <td>Call Me Please </td>
            <td>555-555-5555</td>
            <td>555-555-1212</td>
            <td>Text Message</td>
            <td>121223</td>
         </tr>
      </table>
   </body>
</html>

请注意

  1. 更好的设计(填空)用于,用于分隔代码和演示文稿。 这是最基本和最强大的XSLT设计(填空)模式之一。

  2. 此设计允许相同的代码用于不同的布局(作为参数传递)以产生完全不同的结果。

  3. 标识规则“按原样”复制布局的所有非变量节点

  4. 我们仅覆盖布局的“变量”部分的身份规则。

  5. 辅助元素every指定应执行迭代处理

  6. 在实际应用中,<my:Layout>元素将作为单独的XML文档驻留在单独的文件中,在这种情况下,必须将document('')/*替换为{{ 1}}。当此文件URI作为参数传递给XSLT转换时,可以实现最大的通用性。

  7. 为了处理至少在一个记录中至少出现一次的字段/列而测试的条件是(对于标题):

  8. document('theFileURI')

    细胞的类似条件是:

    not($vDoc/*/*[not(*[name()=current()/@name])])

答案 1 :(得分:0)

你能这样做吗?

<xsl:if test="MessageTime">
  <td><xsl:value-of select="MessageTime" /></td>
</xsl:if>

答案 2 :(得分:0)

这个XSLT:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>

<xsl:key name="notEmptyAll" match="/root/MessageToUser/*" use="local-name()"/> 

<xsl:template match="root">
<html>
<head>
  <style type="text/css">
    th {min-width: 100px;background-color:#9acddd;}
  </style>
</head>
<body>
    <table border="1">
        <tr>
            <xsl:apply-templates select="MessageToUser[1]/*" mode="header"/>
        </tr>
        <xsl:apply-templates select="MessageToUser"/>
    </table>
</body>
</html>
</xsl:template>

<xsl:template match="*" mode="header">
<xsl:if test="count( key('notEmptyAll', local-name())[text()] ) != 0">
    <th>        
        <xsl:value-of select="local-name()"/>
    </th>
</xsl:if>
</xsl:template>

<xsl:template match="MessageToUser">
<tr>
    <xsl:apply-templates select="*" mode="tbody"/>
</tr>
</xsl:template>

<xsl:template match="*" mode="tbody">
<xsl:if test="count( key('notEmptyAll', local-name())[text()] ) != 0">
    <td>        
        <xsl:value-of select="."/>
    </td>
</xsl:if>
</xsl:template>

</xsl:stylesheet>

使用此XML输入:

<root>
<MessageToUser>
    <Name>Bob</Name> 
    <MessageType>Text Message</MessageType> 
    <MessageID>121223</MessageID>
    <ResponseTo>   </ResponseTo>
    <Message>Call Me Please </Message> 
    <OfficePhone></OfficePhone>
    <CellPhone>555-555-5555</CellPhone>  
 </MessageToUser>
 <MessageToUser>
    <Name></Name> 
    <MessageType>Text Message</MessageType> 
    <MessageID>121223</MessageID>
    <ResponseTo>   </ResponseTo>
    <Message>Call Me Please </Message> 
    <OfficePhone>555-555-1212</OfficePhone>
    <CellPhone>555-555-5555</CellPhone>  
 </MessageToUser>
 </root>

将提供此结果(摘录):

<table border="1">
    <tr>
        <th>Name</th>
        <th>MessageType</th>
        <th>MessageID</th>
        <th>Message</th>
        <th>OfficePhone</th>
        <th>CellPhone</th>
    </tr>
    <tr>
        <td>Bob</td>
        <td>Text Message</td>
        <td>121223</td>
        <td>Call Me Please </td>
        <td></td>
        <td>555-555-5555</td>
    </tr>
    <tr>
        <td></td>
        <td>Text Message</td>
        <td>121223</td>
        <td>Call Me Please </td>
        <td>555-555-1212</td>
        <td>555-555-5555</td>
    </tr>
</table>

因此,显示所有至少有一个非空值的元素。

local-name对您来说效率不高,因为标题会像OfficePhone一样。这可以通过子串或“词汇”来解决。请自由评论什么更适合,因为从你的XML摘录中看不出来。

我没有使用MessageFromUser,因为你没有提供XML样本。