Как сгруппировать по дате и идентификатору с помощью XSLT 1.0 - PullRequest
0 голосов
/ 23 сентября 2019

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

У меня есть следующий XML:

<?xml version="1.0" encoding="UTF-8"?><RunPeriod PeriodStart="01102019"  PeriodEnd="02102019"><Employees>

<ID WageCode="2250"><Name>John Doe</Name><Date>01-10-2019</Date><Starttime>08:30</Starttime><Endtime>12:00</Endtime><Absence></Absence><PublicHoliday>0</PublicHoliday><OvertimeStart>08:30</OvertimeStart><OvertimeEnd>12:00</OvertimeEnd></ID>
<DatesAndWeekdays><Dates>01-10-2019</Dates><NameOfWeekday>Tuesday</NameOfWeekday></DatesAndWeekdays>
<ID WageCode="1857"><Name>Jane Doe</Name><Date>01-10-2019</Date><Starttime>09:45</Starttime><Endtime>12:45</Endtime><Absence></Absence><PublicHoliday>0</PublicHoliday><OvertimeStart>09:45</OvertimeStart><OvertimeEnd>12:45</OvertimeEnd></ID>
<DatesAndWeekdays><Dates>01-10-2019</Dates><NameOfWeekday>Tuesday</NameOfWeekday></DatesAndWeekdays>
<ID WageCode="2250"><Name>John Doe</Name><Date>01-10-2019</Date><Starttime>13:15</Starttime><Endtime>16:00</Endtime><Absence></Absence><PublicHoliday>0</PublicHoliday><OvertimeStart>13:15</OvertimeStart><OvertimeEnd>16:00</OvertimeEnd></ID>
<DatesAndWeekdays><Dates>01-10-2019</Dates><NameOfWeekday>Tuesday</NameOfWeekday></DatesAndWeekdays>
<ID WageCode="1857"><Name>Jane Doe</Name><Date>01-10-2019</Date><Starttime>14:45</Starttime><Endtime>17:30</Endtime><Absence></Absence><PublicHoliday>0</PublicHoliday><OvertimeStart>14:45</OvertimeStart><OvertimeEnd>17:30</OvertimeEnd></ID>
<DatesAndWeekdays><Dates>01-10-2019</Dates><NameOfWeekday>Tuesday</NameOfWeekday></DatesAndWeekdays>
<ID WageCode="2250"><Name>John Doe</Name><Date>01-10-2019</Date><Starttime>17:30</Starttime><Endtime>20:30</Endtime><Absence></Absence><PublicHoliday>0</PublicHoliday><OvertimeStart>17:30</OvertimeStart><OvertimeEnd>20:30</OvertimeEnd></ID>
<DatesAndWeekdays><Dates>01-10-2019</Dates><NameOfWeekday>Tuesday</NameOfWeekday></DatesAndWeekdays>
<ID WageCode="2250"><Name>John Doe</Name><Date>02-10-2019</Date><Starttime>08:15</Starttime><Endtime>18:00</Endtime><Absence></Absence><PublicHoliday>0</PublicHoliday><OvertimeStart>08:15</OvertimeStart><OvertimeEnd>18:00</OvertimeEnd></ID>
<DatesAndWeekdays><Dates>02-10-2019</Dates><NameOfWeekday>Wednesday</NameOfWeekday></DatesAndWeekdays>
<ID WageCode="1857"><Name>Jane Doe</Name><Date>02-10-2019</Date><Starttime>08:45</Starttime><Endtime>17:30</Endtime><Absence></Absence><PublicHoliday>0</PublicHoliday><OvertimeStart>08:45</OvertimeStart><OvertimeEnd>17:30</OvertimeEnd></ID>
<DatesAndWeekdays><Dates>02-10-2019</Dates><NameOfWeekday>Wednesday</NameOfWeekday></DatesAndWeekdays>
</Employees></RunPeriod>

Где мои два предмета работают по вторникам и средам.До сих пор я был в состоянии сгруппировать их по их идентификатору, поэтому я получаю по одной строке на один день, используя следующий код:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

    <xsl:key name="grpEmployee" match="ID" use="@WageCode"/>
    <xsl:key name="grpDay" match="DatesAndWeekdays" use="Dates"/>
    <xsl:variable name="startDate"  select="RunPeriod/@PeriodStart"/>
    <xsl:variable name="endDate" select="RunPeriod/@PeriodEnd"/>

    <xsl:template match="Employees">
        <xsl:text>Employee name</xsl:text> <!--> Add first column employee name -->
        <xsl:text>;</xsl:text>
        <!--> Add the dates from the export period - PeriodStart and PeriodEnd -->
        <xsl:call-template name="DateList">
            <xsl:with-param name="day" select="number(substring($startDate, 1, 2))" />
            <xsl:with-param name="month" select="number(substring($startDate, 3, 2))" />
            <xsl:with-param name="year" select="number(substring($startDate, 5))" />
        </xsl:call-template>
        <xsl:text>&#xa;</xsl:text>
        <!--> Add employee data-->
        <xsl:apply-templates select="ID[generate-id(.)=generate-id(key('grpEmployee',@WageCode)[1])]"/>
    </xsl:template>


    <xsl:template match="ID">
        <xsl:value-of select="Name"/>
        <xsl:text>;</xsl:text>
        <xsl:for-each select="key('grpEmployee', @WageCode)">
            <xsl:choose>
                <xsl:when test="Absence = 'Annual leave'">
                    <xsl:value-of select="Absence"/>
                </xsl:when>

                <xsl:when test="PublicHoliday = '1'">
                    <xsl:text>Public Holiday</xsl:text>
                </xsl:when>

                <xsl:when test="Starttime = '00:00' and Endtime = '00:00'">
                    <xsl:text>Day off</xsl:text>
                </xsl:when>

                <xsl:otherwise>
                    <xsl:value-of select="Starttime"/>
                    <xsl:text>-</xsl:text>
                    <xsl:value-of select="Endtime"/>
                </xsl:otherwise>
            </xsl:choose>

            <xsl:text>;</xsl:text>

        </xsl:for-each>
        <xsl:text>&#xa;</xsl:text>
    </xsl:template>

    <xsl:template name="DateList">
        <xsl:param name="day" select="1" />
        <xsl:param name="month" select="1" />
        <xsl:param name="year" select="1" />
        <xsl:variable name="validationResult">
            <xsl:call-template name="date-is-valid">
                <xsl:with-param name="day" select="$day"/>
                <xsl:with-param name="month" select="$month"/>
                <xsl:with-param name="year" select="$year"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:choose>
            <xsl:when test="$validationResult = 0">
                <xsl:choose>
                    <xsl:when test="$month &gt; 12">           
                        <xsl:call-template name="DateList">
                            <xsl:with-param name="day" select="1" />
                            <xsl:with-param name="month" select="1" />
                            <xsl:with-param name="year" select="$year + 1" />
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:call-template name="DateList">
                            <xsl:with-param name="day" select="1" />
                            <xsl:with-param name="month" select="$month + 1" />
                            <xsl:with-param name="year" select="$year" />
                        </xsl:call-template>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:when>
            <xsl:otherwise>                                                
                <xsl:variable name="currentDate" select="concat(format-number($day, '00'), format-number($month, '00'), $year)" />

                <xsl:value-of select="concat($day,'-',$month,'-',$year)" />
                <xsl:text>;</xsl:text>

                <xsl:if test="not($currentDate = $endDate)">
                    <xsl:call-template name="DateList">
                        <xsl:with-param name="day" select="$day + 1" />
                        <xsl:with-param name="month" select="$month" />
                        <xsl:with-param name="year" select="$year" />
                    </xsl:call-template>
                </xsl:if>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="date-is-valid">
        <xsl:param name="year" select="''"/>
        <xsl:param name="month" select="''"/>
        <xsl:param name="day" select="''"/>

        <xsl:variable name="year-is-integer" select="number($year) = $year and floor($year) = $year" />
        <xsl:variable name="month-is-integer" select="number($month) = $month and floor($month) = $month" />
        <xsl:variable name="day-is-integer" select="number($day) = $day and floor($day) = $day" />

        <xsl:choose>
            <xsl:when test="
                    not($year-is-integer) or not($month-is-integer) or not($day-is-integer) or
                    $month &lt; 1 or $month &gt; 12 or
                    $day &lt; 1 or $day &gt; 31 or (
                    ($year mod 4 = 0 and $month = 2 and $day &gt; 29) or
                    ($year mod 4 != 0 and $month = 2 and $day &gt; 28) or
                    (($month = 4 or $month = 6 or $month = 9 or $month = 11) and $day &gt; 30))">
                <xsl:value-of select="0"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="1"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>


</xsl:transform>

ожидаемый результат:

Employee name     Tuesday                                Wednesday  
                 01-10-2019                             02-10-2019  
John Doe    08:30-12:00 13:15-16:00 17:30-20:00         08:15-18:00 
Jane Doe    09:45-12:45 14:45-17:30                     08:45-17:30 

фактическийВывод:

Employee name    Tuesday             Wednesday      
                 01-10-2019          02-10-2019     
John Doe         08:30-12:00         13:15-16:00    17:30-20:30 08:15-18:00
Jane Doe         09:45-12:45         14:45-17:30    08:45-17:30 

Если у моих предметов есть несколько рабочих дней в день, я хочу, чтобы все рабочие часы были показаны в этот день.Код работает нормально, если у них есть только одно рабочее время, например, 08: 15-18: 00, но он не может обрабатывать несколько рабочих дней в день.

Как мне настроить рабочее время в соответствии с их соответствующей датой?

1 Ответ

0 голосов
/ 23 сентября 2019

Я использовал ключ из комментария

<xsl:key name="group-id-and-date" match="ID" use="concat(@WageCode, '|', Date)"/>

, а затем переписал некоторые шаблоны в

<xsl:template match="ID">
    <xsl:value-of select="Name"/>
    <xsl:text>;</xsl:text>
    <xsl:apply-templates select="key('grpEmployee', @WageCode)[generate-id() = generate-id(key('group-id-and-date', concat(@WageCode, '|', Date))[1])]" mode="dates"/>
    <xsl:text>&#xa;</xsl:text>
</xsl:template>

<xsl:template match="ID" mode="dates">
    <xsl:if test="position() > 1">; </xsl:if>
    <xsl:apply-templates select="key('group-id-and-date', concat(@WageCode, '|', Date))" mode="date"/>
</xsl:template>

<xsl:template match="ID" mode="date">
    <xsl:if test="position() > 1">, </xsl:if>

        <xsl:choose>
            <xsl:when test="Absence = 'Annual leave'">
                <xsl:value-of select="Absence"/>
            </xsl:when>

            <xsl:when test="PublicHoliday = '1'">
                <xsl:text>Public Holiday</xsl:text>
            </xsl:when>

            <xsl:when test="Starttime = '00:00' and Endtime = '00:00'">
                <xsl:text>Day off</xsl:text>
            </xsl:when>

            <xsl:otherwise>
                <xsl:value-of select="Starttime"/>
                <xsl:text>-</xsl:text>
                <xsl:value-of select="Endtime"/>
            </xsl:otherwise>
        </xsl:choose>
</xsl:template>

https://xsltfiddle.liberty -development.net / gWEamKS / 2 тогда я думаю, что есть «правильные» «группы», возможно, вам придется адаптировать форматирование / разделители к вашим потребностям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...