如何用XSLT从XML父标签与子标签取值并转换为CSV
别担心,新手刚接触XSLT时遇到这种节点层级的问题太正常啦!你的核心困扰其实是XSLT的上下文节点切换——当你用<xsl:for-each select="//PayDetails">时,当前的上下文变成了PayDetails节点,直接访问StaffNumber自然找不到,因为它在PayDetails的父节点Payslip里。
这里给你两种简单的解决思路,根据你的需求选就行:
思路1:在子节点循环中通过相对路径获取父节点数据
如果你需要以PayDetails为单位生成CSV行,可以在循环PayDetails时,用../(表示当前节点的父节点)或者ancestor::Payslip(表示向上找到最近的Payslip祖先节点)来获取StaffNumber:
修改后的XSLT示例:
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" > <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> <xsl:template match="/"> Worker,Pay_Group,Pay_Period_End_Date,Payment_Date,Net_Amount,Gross_Amount,Currency,Ck_Number,Display_Date <xsl:for-each select="//Payslip//PayDetails"> <!-- 用../StaffNumber获取父节点Payslip下的StaffNumber --> <xsl:value-of select="concat(../StaffNumber,',','PAY_GROUP',',','2017-09-24-00:00',',','2017-09-27-00:00',',',AmountNet,',','AmountGross',',','AUD',',','393',',','SLP000393_',../StaffNumber,'.pdf',',','
')"/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
思路2:嵌套循环,先遍历父节点再遍历子节点
如果每个Payslip下可能有多个PayDetails,想要把父节点的公共数据(比如StaffNumber)和每个子节点的独有数据(比如AmountNet)结合生成多行CSV,更推荐用嵌套循环:
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" > <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> <xsl:template match="/"> Worker,Pay_Group,Pay_Period_End_Date,Payment_Date,Net_Amount,Gross_Amount,Currency,Ck_Number,Display_Date <!-- 先循环父节点Payslip,保存上下文 --> <xsl:for-each select="//Payslip"> <!-- 循环当前Payslip下的PayDetails --> <xsl:for-each select="PayDetails"> <!-- 此时直接用StaffNumber就能拿到父节点的内容,因为外层循环的上下文还是Payslip --> <xsl:value-of select="concat(StaffNumber,',','PAY_GROUP',',','2017-09-24-00:00',',','2017-09-27-00:00',',',AmountNet,',','AmountGross',',','AUD',',','393',',','SLP000393_',StaffNumber,'.pdf',',','
')"/> </xsl:for-each> </xsl:for-each> </xsl:template> </xsl:stylesheet>
这个思路更清晰,也更容易扩展——比如你之后要遍历ComponentDetails,直接在PayDetails的循环里再嵌套一层就好,还能轻松拿到StaffNumber、AmountNet和ComponentType这些跨层级的数据。
另外提个小细节:如果XML里有空标签(比如<Sex/>),你可以用normalize-space()来处理,避免CSV里出现多余的逗号,比如concat(normalize-space(Sex), ','),这样空值会变成空字符串,CSV格式更规范。
内容的提问来源于stack exchange,提问作者venus
相关产品推荐
相关产品推荐

