如何解决XSLT 1.0:将平面结构转换为嵌套的Muenschian分组:避免创建虚假副本
我是XSLT的初学者,通过示例和项目研究来学习。目前,我正在从平面创建分组的嵌套结构。
考虑此示例xml输入:
<root>
<a>First text</a>
<b>Text</b>
<c>More text in c tag</c>
<d>There is even d tag</d>
<a>Another "a" test.</a>
<b>ěščřžýáíéúů</b>
<b>More b tags</b>
<c>One followed by c tag</c>
<a>Last a tag</a>
<b>This time only with b tag,but this goes on and on</b>
</root>
这个XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" method="xml" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:output method="xml" encoding="utf-8"/>
<xsl:key name="groupA" match="b|c|d" use="generate-id(preceding-sibling::a[1])" />
<xsl:key name="groupB" match="c|d" use="generate-id(preceding-sibling::b[1])"/>
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root">
<wrapperTest>
<xsl:apply-templates/>
</wrapperTest>
</xsl:template>
<xsl:template match="root">
<xsl:apply-templates select="@*|a"/>
<xsl:apply-templates select="@*|b"/>
</xsl:template>
<xsl:template match="a">
<xsl:copy>
<xsl:apply-templates select="key('groupA',generate-id())" />
</xsl:copy>
</xsl:template>
<xsl:template match="b">
<xsl:copy>
<xsl:apply-templates select="key('groupB',generate-id())" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
预期输出为:
<wrapperTest>
<a>First text
<b>Text
<c>More text in c tag</c>
<d>There is even d tag</d>
</b>
</a>
<a>Another "a" test.
<b>ěščřžýáíéúů</b>
<b>More b tags
<c>One followed by c tag</c>
</b>
</a>
<a>Last a tag
<b>This time only with b tag,but this goes on and on</b>
</a>
</wrapperTest>
在创建的转换中,创建的副本过多,我也不知道为什么。我想我遇到的问题本质上是基本的,但我无法弄清楚。
解决方案的唯一限制是,它最好应在XSLT 1.0中使用(因为该项目已与python
合并到lxml
脚本中)。在极端情况下,当XSLT 1.0无法实现这一点时,我可以适应最新的saxon
版本,从而消除了任何限制...
我已经查看了答案here,here和其他答案,但是其中大多数都使用XSLT 2.0或对于初学者来说非常复杂。
最后说明:理想情况下,提议的解决方案应具有可扩展性,因为我项目的最终形式也应按标签<c>
进行分组,如下所示:
<wrapperTest>
<a>First text
<b>Text
<c>More text in c tag
<d>There is even d tag</d>
</c>
</b>
</a>
<a>Another "a" test.
<b>ěščřžýáíéúů</b>
<b>More b tags
<c>One followed by c tag</c>
</b>
</a>
<a>Last a tag
<b>This time only with b tag,but this goes on and on</b>
</a>
</wrapperTest>
我会很乐意做练习。
解决方法
怎么样:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="b" match="b" use="generate-id(preceding-sibling::a[1])" />
<xsl:key name="cd" match="c|d" use="generate-id(preceding-sibling::b[1])"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root">
<wrapperTest>
<xsl:apply-templates select="a"/>
</wrapperTest>
</xsl:template>
<xsl:template match="a">
<xsl:copy>
<xsl:apply-templates/>
<xsl:apply-templates select="key('b',generate-id())" />
</xsl:copy>
</xsl:template>
<xsl:template match="b">
<xsl:copy>
<xsl:apply-templates/>
<xsl:apply-templates select="key('cd',generate-id())" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
,
适用于所有级别的递归XSLT 2/3 for-each-group group-starting-with
<xsl:function name="mf:wrap" as="node()*">
<xsl:param name="input" as="node()*"/>
<xsl:for-each-group select="$input" group-starting-with="node()[node-name() = node-name($input[1])]">
<xsl:copy>
<xsl:sequence select="node(),mf:wrap(tail(current-group()))"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="root">
<xsl:copy>
<xsl:sequence select="mf:wrap(*)"/>
</xsl:copy>
</xsl:template>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。