如何在XSLT 2.0中无需多<for-each>循环完成指定XML转换
解决方案:按指定顺序分组输出XML元素(XSLT 2.0)
要满足严格的输出顺序要求,无需用单个<xsl:for-each>遍历所有person节点,而是分三次筛选并处理对应类别的节点,就能保证输出顺序完全符合要求,顺利通过Schema校验。
核心思路
按照输出要求的顺序(friend组 → foe组 → neutral组),依次筛选对应类别的person节点,分别转换为目标元素。无论归类规则简单或复杂,都可以通过这种方式固定输出顺序。
实现代码(基础版)
假设归类规则为:Jon、Bill属于friend;Sam属于foe;Tim、Tom属于neutral,直接在筛选条件中指定:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/people"> <people> <!-- 输出friend组 --> <xsl:for-each select="person[name = ('Jon', 'Bill')]"> <friend> <xsl:copy-of select="name"/> </friend> </xsl:for-each> <!-- 可选:添加空行分隔组 --> <xsl:text>

</xsl:text> <!-- 输出foe组 --> <xsl:for-each select="person[name = 'Sam']"> <foe> <xsl:copy-of select="name"/> </foe> </xsl:for-each> <xsl:text>

</xsl:text> <!-- 输出neutral组 --> <xsl:for-each select="person[name = ('Tim', 'Tom')]"> <neutral> <xsl:copy-of select="name"/> </neutral> </xsl:for-each> </people> </xsl:template> </xsl:stylesheet>
进阶版(复杂规则复用)
如果归类规则更复杂(比如涉及正则、多条件判断),可以将规则封装为函数或模板,提升代码复用性:
方式1:使用自定义函数
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="http://example.com/custom"> <xsl:output method="xml" indent="yes"/> <xsl:namespace-alias stylesheet-prefix="my" result-prefix=""/> <!-- 定义类别判断函数 --> <xsl:function name="my:getCategory" as="xs:string"> <xsl:param name="name" as="xs:string"/> <xsl:choose> <xsl:when test="$name = ('Jon', 'Bill')">friend</xsl:when> <xsl:when test="$name = 'Sam'">foe</xsl:when> <xsl:otherwise>neutral</xsl:otherwise> </xsl:choose> </xsl:function> <xsl:template match="/people"> <people> <xsl:for-each select="person[my:getCategory(name) = 'friend']"> <friend> <xsl:copy-of select="name"/> </friend> </xsl:for-each> <xsl:text>

</xsl:text> <xsl:for-each select="person[my:getCategory(name) = 'foe']"> <foe> <xsl:copy-of select="name"/> </foe> </xsl:for-each> <xsl:text>

</xsl:text> <xsl:for-each select="person[my:getCategory(name) = 'neutral']"> <neutral> <xsl:copy-of select="name"/> </neutral> </xsl:for-each> </people> </xsl:template> </xsl:stylesheet>
方式2:使用模板模式(更符合XSLT设计思想)
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/people"> <people> <xsl:apply-templates select="person[name = ('Jon', 'Bill')]" mode="friend"/> <xsl:text>

</xsl:text> <xsl:apply-templates select="person[name = 'Sam']" mode="foe"/> <xsl:text>

</xsl:text> <xsl:apply-templates select="person[name = ('Tim', 'Tom')]" mode="neutral"/> </people> </xsl:template> <!-- 匹配friend类别的person节点 --> <xsl:template match="person" mode="friend"> <friend> <xsl:copy-of select="name"/> </friend> </xsl:template> <!-- 匹配foe类别的person节点 --> <xsl:template match="person" mode="foe"> <foe> <xsl:copy-of select="name"/> </foe> </xsl:template> <!-- 匹配neutral类别的person节点 --> <xsl:template match="person" mode="neutral"> <neutral> <xsl:copy-of select="name"/> </neutral> </xsl:template> </xsl:stylesheet>
效果验证
上述代码转换后,输出的XML结构和顺序完全符合目标要求,能够通过Schema校验。
内容的提问来源于stack exchange,提问作者TheUltimateHack
相关产品推荐
相关产品推荐

