请求协助修正XSLT映射:按/NEW LINE/拆分生成Instruction段
XSLT拆分InstructionText为独立Instruction段的解决方案
问题说明
需要将XML中包含关键词/NEW LINE/的InstructionText子段内容拆分为多个独立的Instruction段,同时保留原XML的其他结构和属性,但现有XSLT代码无法实现需求。
输入XML
<?xml version="1.0" encoding="UTF-8"?> <TIM> <SBDH> <FIELD1>132</FIELD1> </SBDH> <TI> <TIC> <Instruction> <InstructionText languageCode="EN">20</InstructionText> </Instruction> <Instruction> <InstructionText languageCode="EN">234</InstructionText> </Instruction> <Instruction> <InstructionText languageCode="EN">456 /NEW LINE/ 789 /NEW LINE/ 910/NEW LINE/</InstructionText> </Instruction> </TIC> </TI> </TIM>
期望输出XML
<?xml version="1.0" encoding="UTF-8"?> <TIM> <SBDH> <FIELD1>132</FIELD1> </SBDH> <TI> <TIC> <Instruction> <InstructionText languageCode="EN">20</InstructionText> </Instruction> <Instruction> <InstructionText languageCode="EN">234</InstructionText> </Instruction> <Instruction> <InstructionText languageCode="EN">456</InstructionText> </Instruction> <Instruction> <InstructionText languageCode="EN">789</InstructionText> </Instruction> <Instruction> <InstructionText languageCode="EN">910</InstructionText> </Instruction> </TIC> </TI> </TIM>
当前错误的XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"> <xsl:template match="/"> <xsl:for-each select="//InstructionText"> <xsl:for-each select="tokenize(string(InstructionText), '/NEW LINE/')"> <InstructionText> <InstructionText><xsl:value-of select="."/></InstructionText> </InstructionText> </xsl:for-each> </xsl:for-each> </xsl:template> </xsl:stylesheet>
问题分析
- 结构丢失:原代码仅处理
InstructionText节点,完全丢弃了原XML的其他层级结构(如TIM、SBDH、TI、TIC等)。 - 节点嵌套错误:生成了嵌套的
InstructionText节点,不符合期望输出的Instruction包裹InstructionText的结构。 - 上下文错误:在
xsl:for-each select="//InstructionText"内部,string(InstructionText)应改为string(.),当前节点本身就是InstructionText。 - 空值未过滤:原文本末尾的
/NEW LINE/会导致tokenize生成空字符串,最终产生空内容的Instruction节点。
修正后的XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"> <!-- 身份模板:复制所有未被特殊匹配的节点和属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 匹配需要拆分的Instruction节点 --> <xsl:template match="Instruction"> <!-- 拆分InstructionText的内容 --> <xsl:variable name="splitTexts" select="tokenize(InstructionText, '/NEW LINE/')"/> <!-- 遍历拆分后的非空文本 --> <xsl:for-each select="$splitTexts[normalize-space(.) != '']"> <Instruction> <InstructionText> <!-- 复制原InstructionText的所有属性 --> <xsl:copy-of select="../InstructionText/@*"/> <!-- 输出去除首尾空格的文本内容 --> <xsl:value-of select="normalize-space(.)"/> </InstructionText> </Instruction> </xsl:for-each> </xsl:template> </xsl:stylesheet>
代码说明
- 身份模板:确保原XML中所有不需要修改的节点和属性都被完整复制,保留原有结构。
- 匹配Instruction节点:专门处理需要拆分的
Instruction节点,避免影响其他节点。 - tokenize拆分:使用
tokenize按/NEW LINE/拆分文本,并用normalize-space(.) != ''过滤空字符串。 - 保留属性:通过
xsl:copy-of复制原InstructionText的属性(如languageCode),保证输出的完整性。
内容的提问来源于stack exchange,提问作者Padd T
相关产品推荐
相关产品推荐

