XSLT 1.0多值截取问题:拆分Location元素为独立PL元素
解决XSLT拆分Location内容为独立PL元素的问题
问题回顾
你需要把输入的:
<Location>Wing: ; Room: A; Bed: NAH; Group: 195;</Location>
拆分为:
<PL.1>Wing: ;</PL.1> <PL.2>Room: A;</PL.2> <PL.3>Bed: NAH;</PL.3> <PL.4>Group: 195;</PL.4>
之前用substring-before/substring-after的方法没处理好分隔符和空格的问题,导致输出异常。下面分XSLT版本给出正确实现:
方法1:XSLT 2.0及以上(推荐,更简洁)
利用XSLT 2.0自带的tokenize()函数,直接按"; "(分号+空格)拆分字符串,然后循环生成对应元素:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="Location"> <!-- 按"; "拆分文本,过滤空项 --> <xsl:for-each select="tokenize(., '; ')[normalize-space(.) != '']"> <!-- 生成PL.n元素,n是当前循环的位置 --> <xsl:element name="PL.{position()}"> <!-- 拼接回分号,确保格式和输入一致 --> <xsl:value-of select="concat(., ';')"/> </xsl:element> </xsl:for-each> </xsl:template> </xsl:stylesheet>
逻辑说明
tokenize(., '; '):把Location的文本按"; "分割成多个片段,比如第一个片段是Wing:,第二个是Room: A,以此类推。[normalize-space(.) != '']:过滤掉拆分后可能出现的空字符串(比如原文本末尾的分号可能导致的空项)。concat(., ';'):给每个拆分后的片段补回分号,保证输出内容和预期一致。PL.{position()}:动态生成元素名称,position()会返回当前循环的序号(1、2、3、4)。
方法2:XSLT 1.0(兼容旧版本)
XSLT 1.0没有tokenize(),需要用递归模板来实现字符串拆分:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 匹配Location元素,启动递归拆分 --> <xsl:template match="Location"> <xsl:call-template name="split-location"> <xsl:with-param name="text" select="."/> <xsl:with-param name="index" select="1"/> </xsl:call-template> </xsl:template> <!-- 递归拆分模板 --> <xsl:template name="split-location"> <xsl:param name="text"/> <xsl:param name="index"/> <!-- 找到第一个"; "的位置 --> <xsl:variable name="delimiter" select="'; '"/> <xsl:variable name="pos" select="string-length(substring-before($text, $delimiter)) + 1"/> <xsl:if test="normalize-space($text) != ''"> <!-- 处理当前片段:如果有分隔符,取前面的部分;否则取全部文本 --> <xsl:variable name="current-part"> <xsl:choose> <xsl:when test="contains($text, $delimiter)"> <xsl:value-of select="substring-before($text, $delimiter)"/> </xsl:when> <xsl:otherwise> <!-- 处理最后一个片段,去掉末尾多余的分号(如果有的话) --> <xsl:value-of select="substring($text, 1, string-length($text)-1)"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <!-- 生成PL元素 --> <xsl:element name="PL.{$index}"> <xsl:value-of select="concat($current-part, ';')"/> </xsl:element> <!-- 递归处理剩余文本 --> <xsl:if test="contains($text, $delimiter)"> <xsl:call-template name="split-location"> <xsl:with-param name="text" select="substring-after($text, $delimiter)"/> <xsl:with-param name="index" select="$index + 1"/> </xsl:call-template> </xsl:if> </xsl:if> </xsl:template> </xsl:stylesheet>
逻辑说明
- 递归模板
split-location每次处理一段文本,找到第一个"; "的位置,截取前面的内容作为当前PL元素的内容。 - 处理最后一段时,因为原文本末尾有分号,所以需要去掉最后一个字符(分号)再补回来,保证格式正确。
- 每次递归后
index加1,生成对应的PL序号。
测试结果
两种方法都能输出你预期的XML结构,完美解决之前substring-before/substring-after处理不当导致的空元素和内容缺失问题。
内容的提问来源于stack exchange,提问作者mevorahde
相关产品推荐
相关产品推荐

