XSLT 2.0:根据 for-each -group 的当前索引评估和修改元素值
XSLT 2.0: Evaluate and modify element value according to current index of for-each -group
我正在尝试将 EndDate 评估为下一个“StartDate -1”(下一个开始日期的前一天)。下面给出的是输入 XML:
<?xml version="1.0" encoding="UTF-8"?>
<queryCompoundEmployeeResponse>
<CompoundEmployee>
<id>176</id>
<person>
<action>NO CHANGE</action>
<person_id_external>10005005</person_id_external>
<personal_information>
<end_date>9999-12-31</end_date>
<start_date>2021-06-03</start_date>
</personal_information>
<personal_information>
<end_date>2021-06-02</end_date>
<start_date>2017-12-06</start_date>
</personal_information>
<phone_information>
<phone_type>B</phone_type>
</phone_information>
<phone_information>
<phone_number>7CAED430A494B3C404</phone_number>
</phone_information>
<email_information>
<last_modified_on>2019-03-25T02:44:51.000Z</last_modified_on>
</email_information>
<employment_information>
<start_date>2017-12-06</start_date>
<user_id>10005005</user_id>
<job_information>
<end_date>9999-12-31</end_date>
<start_date>2019-03-02</start_date>
</job_information>
</employment_information>
</person>
<execution_timestamp>2021-07-14T15:08:38.000Z</execution_timestamp>
<version_id>2105P0</version_id>
<Start_Dates>
<StartDate>2017-12-06</StartDate>
<StartDate>2017-12-06</StartDate>
<StartDate>2019-03-02</StartDate>
<StartDate>2021-06-03</StartDate>
</Start_Dates>
<End_Dates>
<EndDate>2021-06-02</EndDate>
<EndDate>NA</EndDate>
<EndDate>9999-12-31</EndDate>
<EndDate>9999-12-31</EndDate>
</End_Dates>
</CompoundEmployee>
</queryCompoundEmployeeResponse>
当前输出:
<?xml version="1.0" encoding="UTF-8"?>
<queryCompoundEmployeeResponse xmlns:xs="http://www.w3.org/2001/XMLSchema">
<CompoundEmployee>
<Person>
<StartDate>2017-12-06</StartDate>
<EndDate>2019-03-01</EndDate>
</Person>
<Person>
<StartDate>2019-03-02</StartDate>
<EndDate/>
</Person>
<Person>
<StartDate>2021-06-03</StartDate>
<EndDate>9999-12-31</EndDate>
</Person>
</CompoundEmployee>
</queryCompoundEmployeeResponse>
所需输出:
<?xml version="1.0" encoding="UTF-8"?>
<queryCompoundEmployeeResponse xmlns:xs="http://www.w3.org/2001/XMLSchema">
<CompoundEmployee>
<Person>
<StartDate>2017-12-06</StartDate>
<EndDate>2019-03-01</EndDate>
</Person>
<Person>
<StartDate>2019-03-02</StartDate>
<EndDate>2021-06-02</EndDate>
</Person>
<Person>
<StartDate>2021-06-03</StartDate>
<EndDate>9999-12-31</EndDate>
</Person>
</CompoundEmployee>
</queryCompoundEmployeeResponse>
我正在尝试将每个 Person 节点的 EndDate 计算为一天减去下一个 StartDate。对于最后一个人,EndDate 应该是输入中的最后一个 EndDate XML.
这是我要增强的代码:
<xsl:template match="/queryCompoundEmployeeResponse">
<queryCompoundEmployeeResponse>
<xsl:for-each select="CompoundEmployee">
<xsl:copy>
<xsl:variable name="person" select="person" />
<xsl:for-each-group select="Start_Dates/StartDate" group-by=".">
<Person>
<xsl:copy-of select="."/>
<!--Start of EndDate logic for last record-->
<xsl:variable name="nxtStartDate" select="following-sibling::StartDate"/>
<xsl:if test="not($nxtStartDate)">
<xsl:variable name="i" select="position()"/>
<EndDate>
<xsl:value-of select="../following-sibling::End_Dates/EndDate[last()]"/>
</EndDate>
</xsl:if>
<!-- End of EndDate logic for last record-->
<!--Calculate next start date -1 -->
<xsl:if test="$nxtStartDate">
<xsl:variable name="currentDate" select="Start_Dates/StartDate"/>
<xsl:variable name="i" select="position()"/>
<EndDate>
<xsl:apply-templates select="following-sibling::StartDate[$i+1]"/>
</EndDate>
</xsl:if>
<!--Calculate next start date -1 -->
<!-- //Some additional required code://
<xsl:copy-of select="$person/* except $person/(personal_information | phone_information | email_information | employment_information)"/>
<xsl:copy-of select="$person/personal_information[start_date le current() and current() le end_date]"/>
<xsl:copy-of select="$person/employment_information[start_date le current() and current() le end_date]"/>
<xsl:copy-of select="$person/employment_information/job_information[start_date le current() and current() le end_date]"/>
-->
</Person>
</xsl:for-each-group>
</xsl:copy>
</xsl:for-each>
</queryCompoundEmployeeResponse>
</xsl:template>
<xsl:template match="StartDate">
<xsl:variable name="sDate" select="." as="xs:date"/>
<xsl:copy-of select="$sDate - 1*xs:dayTimeDuration('P1D')"/>
</xsl:template>
</xsl:stylesheet>
I need something like following-sibling::(.)[index+1]. It gives me the End date in first Person. But next one is still empty.
我做错了什么?
另外,我该如何修改它,让每个部分都有单独的模板?
提前致谢!
当您执行 xsl:for-each-group
时,您将被置于组中第一项的上下文中。从此上下文中,您的表达式 following-sibling::StartDate
选择组的第一个 StartDate 在原始 XML 文档 中的以下兄弟姐妹 - 不在当前组中。而且您当然不能使用任何轴到达下一组的第一项 - 这才是您真正想要的。
也许这样试试:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/queryCompoundEmployeeResponse">
<queryCompoundEmployeeResponse>
<xsl:for-each select="CompoundEmployee">
<xsl:copy>
<xsl:variable name="start-dates">
<xsl:for-each-group select="Start_Dates/StartDate" group-by=".">
<xsl:copy-of select="."/>
</xsl:for-each-group>
</xsl:variable>
<xsl:for-each select="$start-dates/StartDate">
<Person>
<xsl:copy-of select="."/>
<xsl:variable name="next" select="following-sibling::StartDate[1]"/>
<EndDate>
<xsl:value-of select="if ($next) then xs:date($next) - xs:dayTimeDuration('P1D') else '9999-12-31'"/>
</EndDate>
</Person>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
</queryCompoundEmployeeResponse>
</xsl:template>
</xsl:stylesheet>
注意:这是一个快速草稿;它可能会被精简一点——也许是这样的:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/queryCompoundEmployeeResponse">
<queryCompoundEmployeeResponse>
<xsl:for-each select="CompoundEmployee">
<xsl:copy>
<xsl:variable name="start-dates" select="distinct-values(Start_Dates/StartDate)"/>
<xsl:for-each select="$start-dates">
<Person>
<StartDate>
<xsl:value-of select="."/>
</StartDate>
<xsl:variable name="i" select="position()"/>
<EndDate>
<xsl:value-of select="if ($i != last()) then xs:date($start-dates[$i+ 1]) - xs:dayTimeDuration('P1D') else '9999-12-31'"/>
</EndDate>
</Person>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
</queryCompoundEmployeeResponse>
</xsl:template>
</xsl:stylesheet>
我正在尝试将 EndDate 评估为下一个“StartDate -1”(下一个开始日期的前一天)。下面给出的是输入 XML:
<?xml version="1.0" encoding="UTF-8"?>
<queryCompoundEmployeeResponse>
<CompoundEmployee>
<id>176</id>
<person>
<action>NO CHANGE</action>
<person_id_external>10005005</person_id_external>
<personal_information>
<end_date>9999-12-31</end_date>
<start_date>2021-06-03</start_date>
</personal_information>
<personal_information>
<end_date>2021-06-02</end_date>
<start_date>2017-12-06</start_date>
</personal_information>
<phone_information>
<phone_type>B</phone_type>
</phone_information>
<phone_information>
<phone_number>7CAED430A494B3C404</phone_number>
</phone_information>
<email_information>
<last_modified_on>2019-03-25T02:44:51.000Z</last_modified_on>
</email_information>
<employment_information>
<start_date>2017-12-06</start_date>
<user_id>10005005</user_id>
<job_information>
<end_date>9999-12-31</end_date>
<start_date>2019-03-02</start_date>
</job_information>
</employment_information>
</person>
<execution_timestamp>2021-07-14T15:08:38.000Z</execution_timestamp>
<version_id>2105P0</version_id>
<Start_Dates>
<StartDate>2017-12-06</StartDate>
<StartDate>2017-12-06</StartDate>
<StartDate>2019-03-02</StartDate>
<StartDate>2021-06-03</StartDate>
</Start_Dates>
<End_Dates>
<EndDate>2021-06-02</EndDate>
<EndDate>NA</EndDate>
<EndDate>9999-12-31</EndDate>
<EndDate>9999-12-31</EndDate>
</End_Dates>
</CompoundEmployee>
</queryCompoundEmployeeResponse>
当前输出:
<?xml version="1.0" encoding="UTF-8"?>
<queryCompoundEmployeeResponse xmlns:xs="http://www.w3.org/2001/XMLSchema">
<CompoundEmployee>
<Person>
<StartDate>2017-12-06</StartDate>
<EndDate>2019-03-01</EndDate>
</Person>
<Person>
<StartDate>2019-03-02</StartDate>
<EndDate/>
</Person>
<Person>
<StartDate>2021-06-03</StartDate>
<EndDate>9999-12-31</EndDate>
</Person>
</CompoundEmployee>
</queryCompoundEmployeeResponse>
所需输出:
<?xml version="1.0" encoding="UTF-8"?>
<queryCompoundEmployeeResponse xmlns:xs="http://www.w3.org/2001/XMLSchema">
<CompoundEmployee>
<Person>
<StartDate>2017-12-06</StartDate>
<EndDate>2019-03-01</EndDate>
</Person>
<Person>
<StartDate>2019-03-02</StartDate>
<EndDate>2021-06-02</EndDate>
</Person>
<Person>
<StartDate>2021-06-03</StartDate>
<EndDate>9999-12-31</EndDate>
</Person>
</CompoundEmployee>
</queryCompoundEmployeeResponse>
我正在尝试将每个 Person 节点的 EndDate 计算为一天减去下一个 StartDate。对于最后一个人,EndDate 应该是输入中的最后一个 EndDate XML.
这是我要增强的代码:
<xsl:template match="/queryCompoundEmployeeResponse">
<queryCompoundEmployeeResponse>
<xsl:for-each select="CompoundEmployee">
<xsl:copy>
<xsl:variable name="person" select="person" />
<xsl:for-each-group select="Start_Dates/StartDate" group-by=".">
<Person>
<xsl:copy-of select="."/>
<!--Start of EndDate logic for last record-->
<xsl:variable name="nxtStartDate" select="following-sibling::StartDate"/>
<xsl:if test="not($nxtStartDate)">
<xsl:variable name="i" select="position()"/>
<EndDate>
<xsl:value-of select="../following-sibling::End_Dates/EndDate[last()]"/>
</EndDate>
</xsl:if>
<!-- End of EndDate logic for last record-->
<!--Calculate next start date -1 -->
<xsl:if test="$nxtStartDate">
<xsl:variable name="currentDate" select="Start_Dates/StartDate"/>
<xsl:variable name="i" select="position()"/>
<EndDate>
<xsl:apply-templates select="following-sibling::StartDate[$i+1]"/>
</EndDate>
</xsl:if>
<!--Calculate next start date -1 -->
<!-- //Some additional required code://
<xsl:copy-of select="$person/* except $person/(personal_information | phone_information | email_information | employment_information)"/>
<xsl:copy-of select="$person/personal_information[start_date le current() and current() le end_date]"/>
<xsl:copy-of select="$person/employment_information[start_date le current() and current() le end_date]"/>
<xsl:copy-of select="$person/employment_information/job_information[start_date le current() and current() le end_date]"/>
-->
</Person>
</xsl:for-each-group>
</xsl:copy>
</xsl:for-each>
</queryCompoundEmployeeResponse>
</xsl:template>
<xsl:template match="StartDate">
<xsl:variable name="sDate" select="." as="xs:date"/>
<xsl:copy-of select="$sDate - 1*xs:dayTimeDuration('P1D')"/>
</xsl:template>
</xsl:stylesheet>
I need something like following-sibling::(.)[index+1]. It gives me the End date in first Person. But next one is still empty.
我做错了什么? 另外,我该如何修改它,让每个部分都有单独的模板?
提前致谢!
当您执行 xsl:for-each-group
时,您将被置于组中第一项的上下文中。从此上下文中,您的表达式 following-sibling::StartDate
选择组的第一个 StartDate 在原始 XML 文档 中的以下兄弟姐妹 - 不在当前组中。而且您当然不能使用任何轴到达下一组的第一项 - 这才是您真正想要的。
也许这样试试:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/queryCompoundEmployeeResponse">
<queryCompoundEmployeeResponse>
<xsl:for-each select="CompoundEmployee">
<xsl:copy>
<xsl:variable name="start-dates">
<xsl:for-each-group select="Start_Dates/StartDate" group-by=".">
<xsl:copy-of select="."/>
</xsl:for-each-group>
</xsl:variable>
<xsl:for-each select="$start-dates/StartDate">
<Person>
<xsl:copy-of select="."/>
<xsl:variable name="next" select="following-sibling::StartDate[1]"/>
<EndDate>
<xsl:value-of select="if ($next) then xs:date($next) - xs:dayTimeDuration('P1D') else '9999-12-31'"/>
</EndDate>
</Person>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
</queryCompoundEmployeeResponse>
</xsl:template>
</xsl:stylesheet>
注意:这是一个快速草稿;它可能会被精简一点——也许是这样的:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/queryCompoundEmployeeResponse">
<queryCompoundEmployeeResponse>
<xsl:for-each select="CompoundEmployee">
<xsl:copy>
<xsl:variable name="start-dates" select="distinct-values(Start_Dates/StartDate)"/>
<xsl:for-each select="$start-dates">
<Person>
<StartDate>
<xsl:value-of select="."/>
</StartDate>
<xsl:variable name="i" select="position()"/>
<EndDate>
<xsl:value-of select="if ($i != last()) then xs:date($start-dates[$i+ 1]) - xs:dayTimeDuration('P1D') else '9999-12-31'"/>
</EndDate>
</Person>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
</queryCompoundEmployeeResponse>
</xsl:template>
</xsl:stylesheet>