xml - XSLT 2.0:基于日期比较对 xml 节点进行分组(有效性检查)
问题描述
我对 XSLT 完全陌生,并且坚持转换 XML 的要求。我有一个如下的xml:
<CompoundEmployee>
<id>176</id>
<person>
<action>NO CHANGE</action>
<created_by>CONV_ADMIN</created_by>
<logon_user_id>10005005</logon_user_id>
<logon_user_is_active>true</logon_user_is_active>
<person_id>176</person_id>
<person_id_external>10005005</person_id_external>
<personal_information>
<end_date>9999-12-31</end_date>
<first_name>yutaka</first_name>
<first_name_previous>Robbin</first_name_previous>
<first_name_alt1>Robbin</first_name_alt1>
<start_date>2021-06-03</start_date>
</personal_information>
<personal_information>
<end_date>2021-06-02</end_date>
<first_name>wataru</first_name>
<first_name_previous>Robbin</first_name_previous>
<first_name_alt1>Robbin</first_name_alt1>
<start_date>2017-12-06</start_date>
</personal_information>
<employment_information>
<employment_id>136</employment_id>
<start_date>2017-12-06</start_date>
<user_id>10005005</user_id>
<job_information>
<action>NO CHANGE</action>
<end_date>9999-12-31</end_date>
<entry_into_group>2017-12-06</entry_into_group>
<event>5</event>
<event_reason>DATACONV</event_reason>
<excl_executive_sector>false</excl_executive_sector>
<fte>1.0</fte>
<hazard>false</hazard>
<job_code>1000039</job_code>
<location>10000069</location>
<manager_employment_id>265</manager_employment_id>
<manager_id>10005069</manager_id>
<manager_person_id>305</manager_person_id>
<manager_person_id_external>10005069</manager_person_id_external>
<start_date>2019-03-02</start_date>
</job_information>
</employment_information>
</person>
<StartDates>
<StartDate>2021-06-03</StartDate>
<StartDate>2017-12-06</StartDate>
<StartDate>2017-12-06</StartDate>
<StartDate>2019-03-02</StartDate>
</StartDates>
</CompoundEmployee>
为了便于理解,我只取父节点,如下: 源 XML 结构
|复合型员工|CE| |个人信息| CE/PI01| (开始:21 年 6 月 3 日)| (完:99 年 12 月 31 日)| |个人信息| CE/PI02 |(开始:2017 年 12 月 6 日)| (完: 2-Jun-21)| |就业信息| CE/EI01 |(开始:2017 年 12 月 6 日)| (完:无)| |职位信息| CE/EI01/JI01 |(开始: 2-Mar-19) | (完:99 年 12 月 31 日)|
根据日期范围(持续时间),结果应该有 3 条记录,如下所示:
|(开始:2017 年 12 月 6 日)| (结束:19 年 3 月 1 日)| 行政长官 | EI01 | PI01| |(开始:2019 年 3 月 2 日)| (完: 2-Jun-21)| 行政长官 | EI01 | PI02 | JI01| |(开始:21 年 6 月 3 日)| (完:99 年 12 月 31 日)| 行政长官 | EI01 | PI01 | JI01|
需求说明:
从源 XML 中,我们需要收集从最早开始日期开始的所有节点(PersonalInfo(PI)、JobInfo(JI) 等)和内部包含的字段,检查 xml 中的所有其他节点在该时间段内有效并包括该节点是否有效。因此,在源 xml 中,最早期间的开始日期是 17 年 12 月 6 日,其中一条记录结束于 21 年 6 月 2 日,其他没有 EndDate(相当于 99 年 12 月 31 日)。在此期间,EI01 & PI01 有效。第一条记录具有以下节点:<(开始:6-Dec-17 |结束:1-Mar-19)--> CE | EI01 | PI01>
添加下一个日期的记录时,应将上一个记录的结束日期更改为(下一个记录开始日期)-1。
下一个开始日期是 2-Mar-19,结束日期是 31-12-99,在此期间 EI01 | PI02 | JI01 在源 XML 中有效。因此,新记录看起来像:<(开始:2-Mar-19 | 结束:2-Jun-21)--> CE | EI01 | PI02 | JI01> 和前一个的结束日期更改为 1-Mar-19。
在每条记录中默认添加根节点 CompoundEmployee(CE) 和子字段。并且上面每个节点(JI、EI、PI)中的字段都保留在它们相应的父节点中。最终的 xml 应如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<Employees>
<CompoundEmployee>
<StartDate>6-Dec-17</StartDate>
<EndDate>1-Mar-19</EndDate>
<employment_information>
<employment_id>136</employment_id>
<start_date>2017-12-06</start_date>
<user_id>10005005</user_id>
</employment_information>
<personal_information>
<end_date>2021-06-02</end_date>
<first_name>wataru</first_name>
<first_name_previous>Robbin</first_name_previous>
<first_name_alt1>Robbin</first_name_alt1>
<start_date>2017-12-06</start_date>
</personal_information>
</CompoundEmployee>
<CompoundEmployee>
<StartDate>2-Mar-19</StartDate>
<EndDate>2-Jun-21</EndDate>
<employment_information>
<employment_id>136</employment_id>
<start_date>2017-12-06</start_date>
<user_id>10005005</user_id>
</employment_information>
<personal_information>
<end_date>2021-06-02</end_date>
<first_name>wataru</first_name>
<first_name_previous>Robbin</first_name_previous>
<first_name_alt1>Robbin</first_name_alt1>
<start_date>2017-12-06</start_date>
</personal_information>
<job_information>
<action>NO CHANGE</action>
<end_date>9999-12-31</end_date>
<entry_into_group>2017-12-06</entry_into_group>
<event>5</event>
<event_reason>DATACONV</event_reason>
<excl_executive_sector>false</excl_executive_sector>
<fte>1.0</fte>
<hazard>false</hazard>
<job_code>1000039</job_code>
<location>10000069</location>
<manager_employment_id>265</manager_employment_id>
<manager_id>10005069</manager_id>
<manager_person_id>305</manager_person_id>
<manager_person_id_external>10005069</manager_person_id_external>
<start_date>2019-03-02</start_date>
</job_information>
</CompoundEmployee>
<CompoundEmployee>
<StartDate>2-Mar-19</StartDate>
<EndDate>2-Jun-21</EndDate>
<employment_information>
<employment_id>136</employment_id>
<start_date>2017-12-06</start_date>
<user_id>10005005</user_id>
</employment_information>
<personal_information>
<end_date>9999-12-31</end_date>
<first_name>yutaka</first_name>
<first_name_previous>Robbin</first_name_previous>
<first_name_alt1>Robbin</first_name_alt1>
<start_date>2021-06-03</start_date>
</personal_information>
<job_information>
<action>NO CHANGE</action>
<end_date>9999-12-31</end_date>
<entry_into_group>2017-12-06</entry_into_group>
<event>5</event>
<event_reason>DATACONV</event_reason>
<excl_executive_sector>false</excl_executive_sector>
<fte>1.0</fte>
<hazard>false</hazard>
<job_code>1000039</job_code>
<location>10000069</location>
<manager_employment_id>265</manager_employment_id>
<manager_id>10005069</manager_id>
<manager_person_id>305</manager_person_id>
<manager_person_id_external>10005069</manager_person_id_external>
<start_date>2019-03-02</start_date>
</job_information>
</CompoundEmployee>
</Employees>
节点 PersonalInfo、EmploymentInfo 和 JobInfo 的出现次数为 0 到 Unbounded。我采取的方法分为两个步骤:
- 根据开始/结束日期的有效性对所有节点进行分组。
- 将 end_date 更改为 nextRecordStartDate-1。
对于第 1 步,我将所有 start_date 标签收集在一个单独的标签中。然后我尝试遍历所有 start_dates,然后复制任何符合条件的节点。所以直到现在,我的代码看起来像:
到目前为止我尝试过的代码如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<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" encoding="UTF-8" indent="yes" />
<xsl:template match="@*|node()">
<xsl:for-each select="/CompoundEmployee/StartDates/StartDate">
<Record>
<xsl:variable name="cDate" select="/CompoundEmployee/StartDates/xs:date(/StartDate)" />
<xsl:variable name="PIStart" select="/CompoundEmployee/person/personal_information/xs:date(start_date)" />
<xsl:variable name="PIEnd" select="/CompoundEmployee/person/personal_information/xs:date(end_date)" />
<xsl:copy-of select="/CompoundEmployee/person/personal_information[$PIStart <= $cDate and $cDate <= PIEnd]"/>
</Record>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
但这只给了我以下结果:
<?xml version="1.0" encoding="UTF-8"?>
<Record/>
<Record/>
<Record/>
<Record/>
如果可行,我可以根据条件简单地复制所有其他节点。但看起来我在比较日期时做错了什么。
任何帮助表示赞赏。如果我错过了什么,请告诉我。提前致谢!
解决方案
我在 XSLT 下面得到了这个。但我相信可能还有其他更好和优化的方法来做到这一点。
<?xml version="1.0" encoding="UTF-8"?>
<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" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<xsl:variable name="var_person" select="//person/*[not(name()='personal_information') and not(name()='phone_information') and not(name()='email_information') and not(name()='employment_information')]"></xsl:variable>
<xsl:for-each select="//StartDate">
<xsl:variable name="i" select="position()"/>
<xsl:variable name="newDate" select="replace(//StartDate[$i],'-','')"/>
<Record>
<xsl:copy-of select="//StartDate[$i]"/>
<xsl:copy-of select="$var_person"/>
<xsl:copy-of select="//CompoundEmployee/person/personal_information[replace(start_date,'-','') <= $newDate and $newDate <= replace(end_date,'-','')]"/>
<xsl:copy-of select="//CompoundEmployee/person/employment_information/job_information[replace(start_date,'-','') <= $newDate and $newDate <= replace(end_date,'-','')]"/>
<xsl:copy-of select="//CompoundEmployee/person/employment_information[(replace(start_date,'-','') <= $newDate and ($newDate <= replace(end_date,'-','') or not(end_date)))]"/>
</Record>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
推荐阅读
- java - 如何使用 Netbeans 11 正确创建资源目录
- javascript - 在移动设备上预览网页
- ios - RxSwift——MainScheduler.instance 与 MainScheduler.asyncInstance
- python - Astropy,将 Heliocenric 笛卡尔坐标转换为 RA/Dec 的问题
- java - 图片不能在GridView中显示?
- python - 如何在python代码中使用grpc文件?
- python-3.x - Python3.x:在 for 循环中读取 csv 文件中的多列
- vba - VBA使用登录下载文件不起作用
- angular - 如何在打印页面之前等待 DOM 完全加载?
- r - 使用 eulerr 包制作的旋转维恩图