在包含节点序列的变量中重新分组节点

时间:2011-06-06 22:21:41

标签: xslt

我正在尝试从包含相关人员的组织组的XML文件中创建一个两列可打印的HTML电话列表

 <group print_order=1>
 <group_name><![CDATA[Human Resources]]></group_name>
    <person>...(name, address, phone data)...</person>
    <person> ... </person>
    <person> ... </person>
 </group>
 <group print_order=2>
 <group_name><![CDATA[Operations]]></group_name>
    <person> ... </person>
    <person> ... </person>
    <person> ... </person>
    <person> ... </person>
 </group>
 <group print_order=3>
 <group_name><![CDATA[IT Services]]></group_name>

等。
我正在尝试使用以下html输出

 <table>
  <tr>
   <td>
   <div class=group>Human Resources
    <person>
     <span class=name> lastname, firstname </span>
     <span class=addr> room# building </span>
     <span class=phone> 555-5555 </span>
    </person>
        (repeated for each person in group)
   </div>
   <div class=group>Operations
    <person>
     <span class=name> lastname, firstname </span>
     <span class=addr> room# building </span>
     <span class=phone> 555-5555 </span>
    </person>
   </div>
  </td>
  <td>
   <div class=group>IT Services
    <person>
     <span class=name> lastname, firstname </span>
     <span class=addr> room# building </span>
     <span class=phone> 555-5555 </span>
    </person>
        (repeated for each person in group)
   </div>
     etc. 
  </td>
 </tr>
</table>
<p class=page_break>
<table>  (next table on next page)
 <tr>
  <td>  (next set of groups with people)
  </td>
  <td> ( next set of groups with people )
  </td>
  </tr>
</table>
(Repeat tables as needed until all groups output) 

问题在于我希望表格单元格中的行数小于或等于打印页面上的数字行,并且我不希望在表格元素之间拆分组。 我已经尝试了xsl:for-each-group指令,但我无法弄清楚分组或组相邻代码应该是什么样子。我也尝试了以下可怕的测试:

<xsl:if test="sum($nodes/group[following-sibling::group[preceding-sibling::group[1] is current()]]/@line_count) mod 40 &gt; sum($nodes/group[following-sibling::group[preceding-sibling::group[2] is current()]]/@line_count) mod 40 ">

for-each循环中,其中nodes是包含组序列的变量,line_count是每组的数字行,40是每页的行数。我正在使用HTML表来最大化浏览器支持。

有更好的方法吗?使用CSS可能吗? Perl语言的作者拉里沃尔说,在编程语言中,简单的事情应该很容易,而且应该有可能做的事情很难。我在XSLT / XPath中可能会遇到什么?感谢任何愿意趟过这一切的人。

1 个答案:

答案 0 :(得分:1)

我假设每个人只占一行,并且没有一个组太大而无法放在一个页面上。以下样式表通过递归地将组收集到变量($currentColumn)中进行分页,只要总人数低于所需的行数。只要列总数低于所需的列数,就会将列收集到另一个变量($columns)中。达到列限制后,将输出一个页面,然后递归继续下一页。

<xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:fn="http://www.w3.org/2005/xpath-functions">
    <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:param name="lineCount" select="25"/>
    <xsl:param name="columnCount" select="2"/>

    <xsl:template match="/">
        <html>
            <head>
                <title></title>
            </head>
            <body>
                <xsl:call-template name="paginate">
                    <xsl:with-param name="groups" select="/groups/group"/>
                </xsl:call-template>
            </body>
        </html>
    </xsl:template>

    <xsl:template name="paginate">
        <xsl:param name="groups"/>
        <xsl:param name="currentColumn" select="/.."/>
        <xsl:param name="columns" select="/.."/>
        <xsl:choose>
            <xsl:when test="not($groups)">
                <!-- End of input. Print current page and stop recursion. -->
                <xsl:variable name="column">
                    <column><xsl:sequence select="$currentColumn"/></column>
                </xsl:variable>
                <xsl:call-template name="print-page">
                    <xsl:with-param name="columns" select="$columns,$column"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="count($currentColumn//person) + count($groups[1]/person) le $lineCount">
                <xsl:call-template name="paginate">
                    <xsl:with-param name="currentColumn" select="$currentColumn,$groups[1]"/>
                    <xsl:with-param name="columns" select="$columns"/>
                    <xsl:with-param name="groups" select="$groups[position() gt 1]"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="count($groups[1]/person) gt $lineCount">
                <xsl:message terminate="yes">Too many persons in a group!</xsl:message>
            </xsl:when>
            <xsl:when test="count($columns) + 1 lt $columnCount">
                <!-- Start a new column -->
                <xsl:variable name="column">
                    <column><xsl:sequence select="$currentColumn"/></column>
                </xsl:variable>
                <xsl:call-template name="paginate">
                    <xsl:with-param name="columns" select="$columns,$column"/>
                    <xsl:with-param name="groups" select="$groups"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <!-- All columns full. Print current page and page break, then advance to next page. -->
                <xsl:variable name="column">
                    <column><xsl:sequence select="$currentColumn"/></column>
                </xsl:variable>
                <xsl:call-template name="print-page">
                    <xsl:with-param name="columns" select="$columns,$column"/>
                </xsl:call-template>
                <p class="page_break"/>
                <xsl:call-template name="paginate">
                    <xsl:with-param name="groups" select="$groups"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template name="print-page">
        <xsl:param name="columns"/>
        <table>
            <tr>
                <xsl:for-each select="$columns">
                    <td>
                        <xsl:apply-templates select="column/group"/>
                    </td>
                </xsl:for-each>
            </tr>
        </table>
    </xsl:template>

    <xsl:template match="group">
        <div class="group">
            <xsl:value-of select="group_name"/>
            <xsl:for-each select="person">
                <person>
                    <span class="name"><xsl:value-of select="name"/></span>
                    <span class="addr"><xsl:value-of select="addr"/></span>
                    <span class="phone"><xsl:value-of select="phone"/></span>
                </person>
            </xsl:for-each>
        </div>
    </xsl:template>

</xsl:stylesheet>