XSLT新手求助:基于特定XML生成指定规则的转换脚本
XSLT实现按指定type提取并合并对应所有标签
我是XSLT新手,需要基于以下输入XML编写XSLT,实现提取type属性为指定值的对应的标签,并合并所有该类型之后到下一个之前的所有
输入XML
<root> <a> <b type="Test"></b> </a> <c></c> <d> </d> <e> <f>Test1</f> <f>Test2</f> </e> <e> <f>Test3</f> <f>Test4</f> </e> <e> <f>Test5</f> </e> <a> <b type="Rest"></b> </a> <c></c> <d> </d> <e> <f>Rest1</f> <f>Rest2</f> </e> <e> <f>Rest3</f> <f>Rest4</f> </e> <e> <f>Rest5</f> </e> <a> <b type="Host"></b> </a> <c></c> <d> </d> <e> <f>Hest1</f> <f>Hest2</f> </e> <e> <f>Hest3</f> <f>Hest4</f> </e> <e> <f>Hest5</f> </e> <a> <b type="Test"></b> </a> <c></c> <d> </d> <e> <f>Test6</f> <f>Test7</f> </e> <e> <f>Test8</f> <f>Test9</f> </e> <e> <f>Test10</f> </e> <a> <b type="Fest"></b> </a> <c></c> <d> </d> <e> <f>Fest1</f> <f>Fest2</f> </e> <e> <f>Fest3</f> <f>Fest4</f> </e> <e> <f>Fest5</f> </e> </root>
期望输出示例(以type="Test"为例)
<b type="Test"></b> <f>Test1</f> <f>Test2</f> <f>Test3</f> <f>Test4</f> <f>Test5</f> <f>Test6</f> <f>Test7</f> <f>Test8</f> <f>Test9</f> <f>Test10</f>
解决方案
方案1:XSLT 1.0版本(兼容大多数处理器)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 按<b>的type属性分组,快速定位目标type的<b> --> <xsl:key name="b-by-type" match="a/b" use="@type"/> <!-- 将每个<f>关联到它前面最近的<a>,通过唯一ID建立映射 --> <xsl:key name="f-for-a" match="f" use="generate-id(preceding-sibling::a[1])"/> <xsl:template match="/root"> <!-- 这里替换为你需要提取的type值,比如'Test'、'Rest' --> <xsl:variable name="target-type" select="'Test'"/> <!-- 输出第一个匹配目标type的<b>(同type的<b>结构一致,只需输出一次) --> <xsl:copy-of select="key('b-by-type', $target-type)[1]"/> <!-- 遍历所有目标type的<a>,取出每个<a>对应的所有<f> --> <xsl:for-each select="a[b/@type = $target-type]"> <xsl:copy-of select="key('f-for-a', generate-id(.))"/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
方案2:XSLT 2.0+版本(语法更简洁)
如果你的XSLT处理器支持2.0及以上版本(比如Saxon),可以用for-each-group简化代码:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/root"> <!-- 替换为目标type值 --> <xsl:variable name="target-type" select="'Test'"/> <!-- 输出目标type的<b>标签 --> <xsl:copy-of select="a[b/@type = $target-type]/b[1]"/> <!-- 以<a>为分组起点,把root下的节点分成多个组 --> <xsl:for-each-group select="*" group-starting-with="a"> <!-- 如果当前组的<a>匹配目标type,输出组内所有<f> --> <xsl:if test="current-group()[1]/b/@type = $target-type"> <xsl:copy-of select="current-group()//f"/> </xsl:if> </xsl:for-each-group> </xsl:template> </xsl:stylesheet>
使用说明
- 修改代码中
target-type变量的取值,即可切换提取不同type对应的内容; - 使用XSLT处理器(如Saxon、Xalan)运行该XSLT文件,输入你的XML,就能得到期望的输出。
内容的提问来源于stack exchange,提问作者User_Earth_005
相关产品推荐
相关产品推荐

