来自 XML 的 XSLT 2.0 分组(对于 WordML)

XSLT 2.0 Grouping (for WordML) from XML

我有一个时间表列表,要通过 WordML(使用 XSLT 2.0)在 MS Word 中列为输出,我想我需要做一些我不确定如何完成的分组(如果可能的话) .

高层要找的是每个日期(按日期排序),每个计时员的所有信息都集中在一个部分。 (日期、计时员首字母、该日期的总小时数、该日期该计时员的所有叙述数据列表)。

这是我目前拥有的,只是每个日期的每个计时员/考勤卡,没有适当的分组。

输入:

<xml-sample>
<timecard index="10">
    <timekeeper>
        <initials>NC1</initials>
    </timekeeper>
    <date type="timecard">2015-09-01</date>
    <card-values>
        <card-value type="billed">
            <rate>325.00</rate>
            <hours>0.20</hours>
            <amount>65.0000</amount>
        </card-value>
    </card-values>
    <narrative>
        <line id="1">Narrative for 9/1/2015. With some more detail</line>
        <line id="2">on the 2nd line ID.</line>
    </narrative>
</timecard>
<timecard index="11">
    <timekeeper>
        <initials>NC1</initials>
    </timekeeper>
    <date type="timecard">2015-09-01</date>
    <card-values>
        <card-value type="billed">
            <rate>325.00</rate>
            <hours>0.40</hours>
            <amount>130.0000</amount>
        </card-value>
    </card-values>
    <narrative>
        <line id="1">Another narrative for 9/1/2015. With some more</line>
        <line id="2">detail on the 2nd line ID.</line>
    </narrative>
</timecard>
<timecard index="12">
    <timekeeper>
        <initials>NC1</initials>
    </timekeeper>
    <date type="timecard">2015-09-12</date>
    <card-values>
        <card-value type="billed">
            <rate>325.00</rate>
            <hours>0.30</hours>
            <amount>97.5000</amount>
        </card-value>
    </card-values>
    <narrative>
        <line id="1">Narrative for 9/12/2015. With some more detail</line>
        <line id="2">detail on the 2nd line ID.</line>
    </narrative>
</timecard>

当前代码:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:aml="http://schemas.microsoft.com/aml/2001/core" 
    xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format" 
    xmlns:kmf="http://www.kleinmundo.com/functions" 
    xmlns:o="urn:schemas-microsoft-com:office:office" 
    xmlns:sl="http://schemas.microsoft.com/schemaLibrary/2003/core" 
    xmlns:tlr="http://www.elite.com/functions" 
    xmlns:st1="urn:schemas-microsoft-com:office:smarttags" 
    xmlns:v="urn:schemas-microsoft-com:vml" 
    xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml" 
    xmlns:w10="urn:schemas-microsoft-com:office:word" 
    xmlns:wsp="http://schemas.microsoft.com/office/word/2003/wordml/sp2" 
    xmlns:wx="http://schemas.microsoft.com/office/word/2003/auxHint" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:template name="Time_Detail_Sample">
        <xsl:for-each select="xsm-sample/timecard">
            <w:p>
                <w:r>
                    <w:t>Date: <xsl:value-of select="format-date(date, '[M01]/[D01]/[Y01]')" />
                    </w:t>
                </w:r>
            </w:p>
            <w:p>
                <w:r>
                    <w:t>Timekeeper: <xsl:value-of select="timekeeper/initials" />
                    </w:t>
                </w:r>
            </w:p>
            <w:p>
                <w:r>
                    <w:t>Hours: <xsl:value-of select="format-number(card-values/card-value[@type='billed']/hours, '###,##0.00')" />
                    </w:t>
                </w:r>
            </w:p>
            <w:p>
                <w:r>
                    <xsl:for-each select="narrative/line">
                        <w:t>
                            <xsl:value-of select="(.)" />
                            <xsl:value-of select="' '" />
                        </w:t>
                    </xsl:for-each>
                </w:r>
            </w:p>
            <w:p />
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

当前输出:

期望输出: (如您所见,2015 年 9 月 1 日的数据汇总到小时总和中,所有叙述细节都一并列出)。

我建议首先获取 date 的所有不同值,然后将具有当前日期的所有 timecard 元素放入一个变量中,然后从该变量中提取您想要的任何内容. 所以,像这样:

<xsl:variable name="root" select="/"/>
<xsl:for-each select="distinct-values(//date[@type='timecard'])">
            <xsl:variable name="current_value" select="."/>
            <xsl:variable name="all_timecards_with_current_date" select="$root//timecard[descendant::date=$current_value]"/>
            <w:p>
                <w:r>
                    <w:t>Date: <xsl:value-of select="format-date($current_value, '[M01]/[D01]/[Y01]')" />
                    </w:t>
                </w:r>
            </w:p>

            <w:p>
                <w:r>
                    <w:t>Hours: <xsl:value-of select="sum($all_timecards_with_current_date//card-values/card-value[@type='billed']/hours)" />
                    </w:t>
                </w:r>
            </w:p>
            <w:p>
                <w:r>
                    <xsl:for-each select="$all_timecards_with_current_date//narrative/line">
                        <w:t>
                            <xsl:value-of select="." />
                        </w:t>
                    </xsl:for-each>
                </w:r>
            </w:p>

        </xsl:for-each>

不是很漂亮,肯定不是最快的方法。但是,在我看来,它比分组更容易处理。

我肯定会使用 xsl:for-each-group...

<xsl:for-each-group select="timecard"
  group-by="string-join((timekeeper/initials,date[@type='timecard']),'|')">
  <xsl:sort select="date[@type='timecard']"/>
  <w:p>
    <w:r>
      <w:t>
        <xsl:text>Date: </xsl:text>
        <xsl:value-of select="format-date(date, '[M01]/[D01]/[Y01]')"/>
      </w:t>
    </w:r>
  </w:p>
  <w:p>
    <w:r>
      <w:t>
        <xsl:text>Timekeeper: </xsl:text>
        <xsl:value-of select="timekeeper/initials"/>
      </w:t>
    </w:r>
  </w:p>
  <w:p>
    <w:r>
      <w:t>
        <xsl:text>Hours: </xsl:text>
        <xsl:value-of select="format-number(sum(current-group()/card-values/card-value[@type='billed']/hours), '###,##0.00')"/>
      </w:t>
    </w:r>
  </w:p>
  <w:p>
    <w:r>
      <w:t>
        <xsl:value-of select="current-group()/narrative/line" separator=" "/>
      </w:t>
    </w:r>
  </w:p>
  <w:p/>
</xsl:for-each-group>