Перегруппировка узлов в переменную, содержащую последовательность узлов - PullRequest
0 голосов
/ 07 июня 2011

Я пытаюсь создать список телефонов HTML с возможностью печати в две колонки из файла XML организационных групп, в котором есть связанный персонал

 <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, но не могу понять, как должен выглядеть код group-by или соседний с группой код. Я также попробовал следующий ужасный тест:

<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, где node - это переменная, содержащая последовательность групп, line_count - количество строк на группу, а 40 - количество строк на страницу. Я использую таблицы HTML для максимальной поддержки браузера.

Есть ли лучший способ сделать это? Может быть, с помощью CSS? Ларри Уолл, автор языка Perl, сказал, что в языке программирования простые вещи должны быть простыми, а сложные должны быть возможными. Что я после возможного в XSLT / XPath? Спасибо всем, кто хочет пройти через все это.

1 Ответ

1 голос
/ 07 июня 2011

Я предполагаю, что каждый человек занимает одну строку, и что ни одна группа не является слишком большой, чтобы поместиться на одной странице. Следующая таблица стилей разбивается на страницы путем рекурсивного сбора групп в переменную ($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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...