1

Web 服务正在返回以下 xml 格式的人员列表。这些值用分号分隔。我需要在 2 或 3 列中显示值(需要是变量)。

期望的结果:

<table border="1">
 <tr>
  <td>Smith, John</td>
  <td>Jackson, Samuel</td>
  <td>Wayne, Bruce</td>
 </tr>
 <tr>
  <td>Cosby, Bill</td>
  <td>Kent, Clarke</td>
  <td>Leno, Jay</td>
 </tr>
 <tr>
  <td>OBrian, Conan</td>
  <td> </td>
  <td> </td>
 </tr>
</table>

Xml 样本

 <?xml version="1.0" encoding="UTF-8"?> <PI>Smith, John; Jackson,
 Samuel; Wayne, Bruce; Cosby, Bill; Kent, Clarke; Leno, Jay; OBrian,
 Conan; </PI>
4

2 回答 2

0

这是一个 XSLT 2.0 解决方案,其中列数作为请求的变量。这采用了我在课堂上教授的一种技术,它强调分组不必按 XML 中的值(正如许多 XSLT 用户所假设的那样),而是可以通过任意计算(在本例中为除法的结果)。

[编辑以显示具有不同列数的多个调用]

t:\ftemp>type names.xml 
<?xml version="1.0" encoding="UTF-8"?> <PI>Smith, John; Jackson,
Samuel; Wayne, Bruce; Cosby, Bill; Kent, Clarke; Leno, Jay; OBrian,
Conan; </PI>
t:\ftemp>call xslt2 names.xml names.xsl names.out.xml "cols=3" 

t:\ftemp>type names.out.xml 
<?xml version="1.0" encoding="UTF-8"?>
<table border="1">
   <tr>
      <td>Smith, John</td>
      <td>Jackson, Samuel</td>
      <td>Wayne, Bruce</td>
   </tr>
   <tr>
      <td>Cosby, Bill</td>
      <td>Kent, Clarke</td>
      <td>Leno, Jay</td>
   </tr>
   <tr>
      <td>OBrian, Conan</td>
      <td/>
      <td/>
   </tr>
</table>

t:\ftemp>call xslt2 names.xml names.xsl names.out.xml "cols=2" 

t:\ftemp>type names.out.xml 
<?xml version="1.0" encoding="UTF-8"?>
<table border="1">
   <tr>
      <td>Smith, John</td>
      <td>Jackson, Samuel</td>
   </tr>
   <tr>
      <td>Wayne, Bruce</td>
      <td>Cosby, Bill</td>
   </tr>
   <tr>
      <td>Kent, Clarke</td>
      <td>Leno, Jay</td>
   </tr>
   <tr>
      <td>OBrian, Conan</td>
      <td/>
   </tr>
</table>

t:\ftemp>type names.xsl 
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">

<xsl:output indent="yes"/>

<xsl:param name="cols" required="yes"/>

<xsl:template match="PI">
  <table border="1">
    <!--determine population and group by number of columns-->
    <xsl:for-each-group select="tokenize(.,';\s+')"
                        group-by="(position()-1) idiv $cols">
      <tr>
        <!--put members into the row-->
        <xsl:for-each select="current-group()">
          <td>
            <xsl:value-of select="normalize-space(.)"/>
          </td>
        </xsl:for-each>
        <!--filler for the last row-->
        <xsl:if test="position()=last()">
          <xsl:for-each select="count(current-group())+1 to $cols">
            <td/>
          </xsl:for-each>
        </xsl:if>
      </tr>
    </xsl:for-each-group>
  </table>
</xsl:template>

</xsl:stylesheet>
t:\ftemp>rem
于 2013-08-05T20:26:30.197 回答
0

请接受霍尔曼的解决方案。他的技术很到位。

XSLT 2.0 解决方案

您的示例输入数据建议使用分号结尾的列表,而不是分号分隔的列表。

此 XSLT 2.0 样式表可以与分号终止的列表或分号分隔的列表一起正常工作。它接受一个输入参数col-count,默认为 3。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:param name="col-count" select="3" />

<xsl:template match="/*">
 <table border="1">
  <xsl:variable name="names" select="tokenize(.,';')[normalize-space(.)]" />
  <xsl:for-each-group select="$names , for $x in 1 to
    ($col-count - (count($names) mod $col-count)) mod $col-count return ''"
                      group-by="(position() - 1) idiv $col-count"> 
   <tr>
    <xsl:for-each select="current-group()">
     <td><xsl:value-of select="normalize-space(.)" /></td>
    </xsl:for-each>
   </tr>
  </xsl:for-each-group>
 </table>
</xsl:template>

</xsl:stylesheet>

笔记:

(1) 注意解决方案的简洁性,并且没有笨拙的xsl:if陈述。计算序列的使用(与输入文档节点选择相反)不仅限于 group-by 属性,还可以应用于select. 计算序列的使用表明了更实用的视图,而不是程序视图。

(2) 如果您希望输出对于旧浏览器是安全的,那么替换...

  <xsl:for-each-group select="$names , for $x in 1 to
    ($col-count - (count($names) mod $col-count)) mod $col-count return ''"
                      group-by="(position() - 1) idiv $col-count"> 

... 和 ...

  <xsl:for-each-group select="$names , for $x in 1 to
    ($col-count - (count($names) mod $col-count)) mod $col-count return '&#160;'"
                      group-by="(position() - 1) idiv $col-count"> 

XSLT 1.0 解决方案

如果您停留在 XSLT 1.0 上,那么您可以使用这个等效但效率较低的样式表......

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:esl="http://exslt.org/common"
  xmlns:so="http://stackoverflow.com/questions/18066463"
  version="1.0"
  exclude-result-prefixes="xsl so esl">
<xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="col-count" select="3" /><!-- Must be 2 or 3. -->

<xsl:variable name="empty-rtf">
  <so:name>&#160;</so:name>
</xsl:variable>
<xsl:variable name="empty" select="esl:node-set($empty-rtf)/*" />


<xsl:template match="/*">
  <table border="1">
    <xsl:variable name="names-rtf">
      <xsl:call-template name="split">
        <xsl:with-param name="list" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="names" select="esl:node-set($names-rtf)/*" />
    <xsl:for-each select="$names[(position() mod $col-count) = 1]">
      <xsl:variable name="row" select="position() - 1" />
      <tr>
        <xsl:apply-templates select="$names[floor((position() - 1) div $col-count) = $row]" />
        <xsl:if test="position()=last()">
         <xsl:for-each select="($names|$empty)[position() &lt;=
                               (($col-count - (count($names) mod $col-count)) mod $col-count)]">
           <xsl:apply-templates select="$empty" />
         </xsl:for-each>  
        </xsl:if>  
      </tr>
    </xsl:for-each>  
  </table>
</xsl:template>

<xsl:template name="split">
  <xsl:param name="list" />
  <xsl:choose>
    <xsl:when test="contains($list,';')">
      <xsl:call-template name="split">
        <xsl:with-param name="list" select="substring-before($list,';')" />
      </xsl:call-template>
      <xsl:call-template name="split">
        <xsl:with-param name="list" select="substring-after($list,';')" />
      </xsl:call-template>
    </xsl:when>  
    <xsl:when test="normalize-space($list)">
      <so:name><xsl:value-of select="normalize-space($list)" /></so:name>
    </xsl:when>  
    <xsl:otherwise />
  </xsl:choose>
</xsl:template>

<xsl:template match="so:*" priority="2">
  <td><xsl:value-of select="." /></td>
</xsl:template>  

</xsl:stylesheet>
于 2013-08-06T03:51:23.150 回答