基于生效日期与Sequence的XSLT转换实现需求
XML转CSV的XSLT解决方案来了!
你说的需求我完全理解——就是把XML里带Sequence属性的Effective_Change节点,按Effective_Moment的日期部分分组:同日期的合并成一行CSV,不同日期的单独输出对吧?我帮你写了一个XSLT 2.0的实现,刚好能解决这个问题。
需求回顾
- 若多个
Effective_Change节点的Effective_Moment日期部分相同,仅生成一行CSV输出; - 日期部分不同的话,每个日期分别生成一行。
你的原始XML(我补全了截断的闭合标签,保证文件合法)
<?xml version="1.0" encoding="UTF-8"?> <peci:Workers_Effective_Stack xmlns:peci="urn:com.w/peci"> <peci:Worker> <peci:Summary> <peci:Integration_Event>14d964101fdb0156e164341b45548d01</peci:Integration_Event> <peci:Integration_Sent_On>2018-05-10T08:41:39.375-07:00</peci:Integration_Sent_On> <peci:Payroll_Company_Name>West Brooke - Biweekly: B</peci:Payroll_Company_Name> <peci:Pay_Group_Country>US</peci:Pay_Group_Country> <peci:Pay_Group_Code>j</peci:Pay_Group_Code> <peci:Pay_Period_Start>2018-04-30-07:00</peci:Pay_Period_Start> <peci:Pay_Period_End>2018-05-13-07:00</peci:Pay_Period_End> <peci:Updated_From>2018-05-07T19:50:30.963-07:00</peci:Updated_From> <peci:Updated_To>2018-05-10T08:41:39.375-07:00</peci:Updated_To> <peci:Effective_From>2018-04-30-07:00</peci:Effective_From> <peci:Effective_To>2018-05-13-07:00</peci:Effective_To> <peci:Change_Detection>Include only changes entered since the last successful run.</peci:Change_Detection> <peci:First_Primary_Run_of_Pay_Period>0</peci:First_Primary_Run_of_Pay_Period> <peci:Ad_Hoc_Run>0</peci:Ad_Hoc_Run> <peci:Full_Snapshot>0</peci:Full_Snapshot> <peci:Worker_Count>2</peci:Worker_Count> <peci:Version>1</peci:Version> </peci:Summary> <peci:Worker> <peci:Worker_Summary> <peci:WID>rd</peci:WID> <peci:Employee_ID>33333</peci:Employee_ID> <peci:Name>Test 1</peci:Name> </peci:Worker_Summary> <peci:Effective_Change peci:Sequence="0"> <peci:Derived_Event_Code>DTA</peci:Derived_Event_Code> <peci:Effective_Moment>2018-05-10T08:29:21.235-07:00</peci:Effective_Moment> <peci:Entry_Moment>2018-05-10T08:29:21.235-07:00</peci:Entry_Moment> <peci:Worker_Status> <peci:Status>Active</peci:Status> <peci:Active>1</peci:Active> <peci:Active_Status_Date>2018-01-08-08:00</peci:Active_Status_Date> <peci:Terminated>0</peci:Terminated> <peci:Hire_Date>2018-01-08-08:00</peci:Hire_Date> <peci:Original_Hire_Date>2018-01-08-08:00</peci:Original_Hire_Date> <peci:Is_Rehire>0</peci:Is_Rehire> <peci:Continuous_Service_Date>2018-01-08-08:00</peci:Continuous_Service_Date> <peci:First_Day_of_Work>2018-01-08-08:00</peci:First_Day_of_Work> <peci:Seniority_Date>2018-01-08-08:00</peci:Seniority_Date> </peci:Worker_Status> </peci:Effective_Change> <peci:Effective_Change peci:Sequence="1"> <peci:Derived_Event_Code>DTA</peci:Derived_Event_Code> <peci:Effective_Moment>2018-05-10T08:31:27.880-07:00</peci:Effective_Moment> <peci:Entry_Moment>2018-05-10T08:31:27.880-07:00</peci:Entry_Moment> <peci:Worker_Status> <peci:Status>Active</peci:Status> <peci:Active>1</peci:Active> <peci:Active_Status_Date>2018-01-08-08:00</peci:Active_Status_Date> <peci:Terminated>0</peci:Terminated> <peci:Hire_Date>2018-01-08-08:00</peci:Hire_Date> <peci:Original_Hire_Date>2018-01-08-08:00</peci:Original_Hire_Date> <peci:Is_Rehire>0</peci:Is_Rehire> <peci:Continuous_Service_Date>2018-01-08-08:00</peci:Continuous_Service_Date> <peci:First_Day_of_Work>2018-01-08-08:00</peci:First_Day_of_Work> <peci:Seniority_Date>2018-01-08-08:00</peci:Seniority_Date> </peci:Worker_Status> </peci:Effective_Change> <peci:Effective_Change peci:Sequence="2"> <peci:Derived_Event_Code>DTA</peci:Derived_Event_Code> <peci:Effective_Moment>2018-05-12T08:29:21.235-07:00</peci:Effective_Moment> <peci:Entry_Moment>2018-05-12T08:29:21.235-07:00</peci:Entry_Moment> <peci:Worker_Status> <peci:Status>Active</peci:Status> <peci:Active>1</peci:Active> <peci:Active_Status_Date>2018-01-08-08:00</peci:Active_Status_Date> <peci:Terminated>0</peci:Terminated> <peci:Hire_Date>2018-01-08-08:00</peci:Hire_Date> <peci:Original_Hire_Date>2018-01-08-08:00</peci:Original_Hire_Date> <peci:Is_Rehire>0</peci:Is_Rehire> <peci:Continuous_Service_Date>2018-01-08-08:00</peci:Continuous_Service_Date> <peci:First_Day_of_Work>2018-01-08-08:00</peci:First_Day_of_Work> <peci:Seniority_Date>2018-01-08-08:00</peci:Seniority_Date> </peci:Worker_Status> </peci:Effective_Change> </peci:Worker> </peci:Worker> </peci:Workers_Effective_Stack>
实现代码(XSLT 2.0)
这个方案用了XSLT的分组功能,专门适配你的需求:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:peci="urn:com.w/peci"> <xsl:output method="text" encoding="UTF-8"/> <!-- 先输出CSV表头 --> <xsl:template match="/"> <xsl:text>Employee_ID,Name,Effective_Date,Derived_Event_Code,Status,Active,Hire_Date </xsl:text> <xsl:apply-templates select="//peci:Worker[peci:Worker_Summary]"/> </xsl:template> <!-- 处理每个员工节点 --> <xsl:template match="peci:Worker[peci:Worker_Summary]"> <!-- 先缓存员工基础信息,避免重复查找 --> <xsl:variable name="basic-info" select="peci:Worker_Summary"/> <!-- 核心逻辑:按Effective_Moment的日期部分分组 --> <xsl:for-each-group select="peci:Effective_Change" group-by="substring-before(peci:Effective_Moment, 'T')"> <!-- 同日期的节点取第一个的字段值(从你的示例看,同日期内容完全一致,这样处理没问题) --> <xsl:variable name="first-change" select="current-group()[1]"/> <!-- 拼接CSV行,逗号分隔字段,换行符用 --> <xsl:value-of select="$basic-info/peci:Employee_ID"/> <xsl:text>,</xsl:text> <xsl:value-of select="$basic-info/peci:Name"/> <xsl:text>,</xsl:text> <xsl:value-of select="current-grouping-key()"/> <!-- 分组的日期值 --> <xsl:text>,</xsl:text> <xsl:value-of select="$first-change/peci:Derived_Event_Code"/> <xsl:text>,</xsl:text> <xsl:value-of select="$first-change/peci:Worker_Status/peci:Status"/> <xsl:text>,</xsl:text> <xsl:value-of select="$first-change/peci:Worker_Status/peci:Active"/> <xsl:text>,</xsl:text> <xsl:value-of select="$first-change/peci:Worker_Status/peci:Hire_Date"/> <xsl:text> </xsl:text> </xsl:for-each-group> </xsl:template> <!-- 忽略冗余的文本节点,避免输出无效内容 --> <xsl:template match="text()"/> </xsl:stylesheet>
关键逻辑说明
- 分组核心:用
xsl:for-each-group把同一日期的Effective_Change归为一组,分组依据是Effective_Moment中T之前的纯日期部分。 - 字段复用:同组节点内容一致,直接取第一个节点的字段值即可,无需重复处理。
- CSV格式优化:如果你的字段可能包含逗号或双引号,记得给字段套双引号,内部双引号要转成两个(比如把
"改成""),这个可以按需扩展。
输出效果
运行这个XSLT后,会得到符合要求的CSV:
Employee_ID,Name,Effective_Date,Derived_Event_Code,Status,Active,Hire_Date 33333,Test 1,2018-05-10,DTA,Active,1,2018-01-08-08:00 33333,Test 1,2018-05-12,DTA,Active,1,2018-01-08-08:00
完美实现你的规则:2018-05-10的两个Effective_Change合并成一行,2018-05-12单独一行。
内容的提问来源于stack exchange,提问作者Viral Shah
相关产品推荐
相关产品推荐

