XSLT 1.0 按多个元素分组
XSLT 1.0 grouping by multiple elements
关于这个主题,我找到了各种答案,但到目前为止我找不到解决方案。
我输入了 XML 结构如下:
<RootNode>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM11</ITEMELEMENT1>
<ITEMELEMENT2>ITEM21</ITEMELEMENT2>
<ITEMELEMENT3>ITEM31</ITEMELEMENT3>
<ITEMELEMENT4>ITEM41</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM21</ITEMELEMENT1>
<ITEMELEMENT2>ITEM22</ITEMELEMENT2>
<ITEMELEMENT3>ITEM23</ITEMELEMENT3>
<ITEMELEMENT4>ITEM24</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABD</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD21</HEADELEMENT1>
<HEADELEMENT2>HEAD22</HEADELEMENT2>
<HEADELEMENT3>HEAD23</HEADELEMENT3>
<HEADELEMENT4>HEAD24</HEADELEMENT4>
<ITEMELEMENT1>ITEM31</ITEMELEMENT1>
<ITEMELEMENT2>ITEM32</ITEMELEMENT2>
<ITEMELEMENT3>ITEM33</ITEMELEMENT3>
<ITEMELEMENT4>ITEM34</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>002</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD31</HEADELEMENT1>
<HEADELEMENT2>HEAD32</HEADELEMENT2>
<HEADELEMENT3>HEAD33</HEADELEMENT3>
<HEADELEMENT4>HEAD34</HEADELEMENT4>
<ITEMELEMENT1>ITEM41</ITEMELEMENT1>
<ITEMELEMENT2>ITEM42</ITEMELEMENT2>
<ITEMELEMENT3>ITEM43</ITEMELEMENT3>
<ITEMELEMENT4>ITEM44</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM51</ITEMELEMENT1>
<ITEMELEMENT2>ITEM52</ITEMELEMENT2>
<ITEMELEMENT3>ITEM53</ITEMELEMENT3>
<ITEMELEMENT4>ITEM54</ITEMELEMENT4>
</record>
</RootNode>
转换的结果应该是这样的:
<ResultXml>
<record>
<header>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM11</ITEMELEMENT1>
<ITEMELEMENT2>ITEM21</ITEMELEMENT2>
<ITEMELEMENT3>ITEM31</ITEMELEMENT3>
<ITEMELEMENT4>ITEM41</ITEMELEMENT4>
</item>
<item>
<ITEMELEMENT1>ITEM21</ITEMELEMENT1>
<ITEMELEMENT2>ITEM22</ITEMELEMENT2>
<ITEMELEMENT3>ITEM23</ITEMELEMENT3>
<ITEMELEMENT4>ITEM24</ITEMELEMENT4>
</item>
<item>
<ITEMELEMENT1>ITEM51</ITEMELEMENT1>
<ITEMELEMENT2>ITEM52</ITEMELEMENT2>
<ITEMELEMENT3>ITEM53</ITEMELEMENT3>
<ITEMELEMENT4>ITEM54</ITEMELEMENT4>
</item>
</record>
<record>
<header>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABD</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD21</HEADELEMENT1>
<HEADELEMENT2>HEAD22</HEADELEMENT2>
<HEADELEMENT3>HEAD23</HEADELEMENT3>
<HEADELEMENT4>HEAD24</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM31</ITEMELEMENT1>
<ITEMELEMENT2>ITEM32</ITEMELEMENT2>
<ITEMELEMENT3>ITEM33</ITEMELEMENT3>
<ITEMELEMENT4>ITEM34</ITEMELEMENT4>
</item>
</record>
<record>
<header>
<KEYELEMENT1>002</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD31</HEADELEMENT1>
<HEADELEMENT2>HEAD32</HEADELEMENT2>
<HEADELEMENT3>HEAD33</HEADELEMENT3>
<HEADELEMENT4>HEAD34</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM41</ITEMELEMENT1>
<ITEMELEMENT2>ITEM42</ITEMELEMENT2>
<ITEMELEMENT3>ITEM43</ITEMELEMENT3>
<ITEMELEMENT4>ITEM44</ITEMELEMENT4>
</item>
</record>
</ResultXml>
对于 KEYELEMENT1、KEYELEMENT2 和 KEYELEMENT3 中的每个不同值,我必须在结果中创建一个记录。其他 header 字段相同,并转换为具有关键字段的 header 元素。项目应映射到具有相同键的记录下。
我用这样的方法尝试了 Muenchian 方法:
<xsl:key name="keyfields" match="record" use="concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3)"/>
<xsl:template match="/">
<ResultXml>
<xsl:apply-templates select="record[generate-id() = generate-id(key('keyfields',concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3))[1])]" mode="header"/>
</ResultXml>
</xsl:template>
<xsl:template match="record" mode="header">
<record>
<header>
<KEYELEMENT1><xsl:value-of select="KEYELEMENT1"/></KEYELEMENT1>
<KEYELEMENT2><xsl:value-of select="KEYELEMENT2"/></KEYELEMENT2>
<KEYELEMENT3><xsl:value-of select="KEYELEMENT3"/></KEYELEMENT3>
<HEADELEMENT1><xsl:value-of select="HEADELEMENT1"/></HEADELEMENT1>
<HEADELEMENT2><xsl:value-of select="HEADELEMENT2"/></HEADELEMENT2>
<HEADELEMENT3><xsl:value-of select="HEADELEMENT3"/></HEADELEMENT3>
<HEADELEMENT4><xsl:value-of select="HEADELEMENT4"/></HEADELEMENT4>
</header>
</record>
</xsl:template>
但我什至无法生成 header 记录。
任何帮助将不胜感激。
如果您将第一个模板匹配项从 /
更改为 /*
(或 RootNode
),您将获得正确的组。
之后,只需将项目分组为 4 组即可。一种方法是在谓词中使用 mod
。
举个例子。我在我的 Muenchian 分组中使用 count()
而不是 generate-id()
,但是这两种方式都可以完成。
示例...
XML 输入
<RootNode>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM11</ITEMELEMENT1>
<ITEMELEMENT2>ITEM21</ITEMELEMENT2>
<ITEMELEMENT3>ITEM31</ITEMELEMENT3>
<ITEMELEMENT4>ITEM41</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM21</ITEMELEMENT1>
<ITEMELEMENT2>ITEM22</ITEMELEMENT2>
<ITEMELEMENT3>ITEM23</ITEMELEMENT3>
<ITEMELEMENT4>ITEM24</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABD</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD21</HEADELEMENT1>
<HEADELEMENT2>HEAD22</HEADELEMENT2>
<HEADELEMENT3>HEAD23</HEADELEMENT3>
<HEADELEMENT4>HEAD24</HEADELEMENT4>
<ITEMELEMENT1>ITEM31</ITEMELEMENT1>
<ITEMELEMENT2>ITEM32</ITEMELEMENT2>
<ITEMELEMENT3>ITEM33</ITEMELEMENT3>
<ITEMELEMENT4>ITEM34</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>002</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD31</HEADELEMENT1>
<HEADELEMENT2>HEAD32</HEADELEMENT2>
<HEADELEMENT3>HEAD33</HEADELEMENT3>
<HEADELEMENT4>HEAD34</HEADELEMENT4>
<ITEMELEMENT1>ITEM41</ITEMELEMENT1>
<ITEMELEMENT2>ITEM42</ITEMELEMENT2>
<ITEMELEMENT3>ITEM43</ITEMELEMENT3>
<ITEMELEMENT4>ITEM44</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM51</ITEMELEMENT1>
<ITEMELEMENT2>ITEM52</ITEMELEMENT2>
<ITEMELEMENT3>ITEM53</ITEMELEMENT3>
<ITEMELEMENT4>ITEM54</ITEMELEMENT4>
</record>
</RootNode>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="keyfields" match="record"
use="concat(KEYELEMENT1,'|',KEYELEMENT2,'|',KEYELEMENT3)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<ResultXml>
<xsl:for-each
select="record[count(.|key('keyfields',concat(KEYELEMENT1,'|',KEYELEMENT2,'|',KEYELEMENT3))[1])=1]">
<record>
<header>
<xsl:apply-templates
select="*[starts-with(local-name(), 'KEYELEMENT') or starts-with(local-name(), 'HEADELEMENT')]"/>
</header>
<xsl:for-each select="key('keyfields',concat(KEYELEMENT1,'|',KEYELEMENT2,'|',KEYELEMENT3))/*[starts-with(local-name(),'ITEMELEMENT')][position() mod 4 = 1]">
<item>
<xsl:apply-templates
select=".|following-sibling::*[starts-with(local-name(),'ITEMELEMENT')][position() >= 1 and 4 > position()]"/>
</item>
</xsl:for-each>
</record>
</xsl:for-each>
</ResultXml>
</xsl:template>
</xsl:stylesheet>
输出
<ResultXml>
<record>
<header>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM11</ITEMELEMENT1>
<ITEMELEMENT2>ITEM21</ITEMELEMENT2>
<ITEMELEMENT3>ITEM31</ITEMELEMENT3>
<ITEMELEMENT4>ITEM41</ITEMELEMENT4>
</item>
<item>
<ITEMELEMENT1>ITEM21</ITEMELEMENT1>
<ITEMELEMENT2>ITEM22</ITEMELEMENT2>
<ITEMELEMENT3>ITEM23</ITEMELEMENT3>
<ITEMELEMENT4>ITEM24</ITEMELEMENT4>
</item>
<item>
<ITEMELEMENT1>ITEM51</ITEMELEMENT1>
<ITEMELEMENT2>ITEM52</ITEMELEMENT2>
<ITEMELEMENT3>ITEM53</ITEMELEMENT3>
<ITEMELEMENT4>ITEM54</ITEMELEMENT4>
</item>
</record>
<record>
<header>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABD</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD21</HEADELEMENT1>
<HEADELEMENT2>HEAD22</HEADELEMENT2>
<HEADELEMENT3>HEAD23</HEADELEMENT3>
<HEADELEMENT4>HEAD24</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM31</ITEMELEMENT1>
<ITEMELEMENT2>ITEM32</ITEMELEMENT2>
<ITEMELEMENT3>ITEM33</ITEMELEMENT3>
<ITEMELEMENT4>ITEM34</ITEMELEMENT4>
</item>
</record>
<record>
<header>
<KEYELEMENT1>002</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD31</HEADELEMENT1>
<HEADELEMENT2>HEAD32</HEADELEMENT2>
<HEADELEMENT3>HEAD33</HEADELEMENT3>
<HEADELEMENT4>HEAD34</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM41</ITEMELEMENT1>
<ITEMELEMENT2>ITEM42</ITEMELEMENT2>
<ITEMELEMENT3>ITEM43</ITEMELEMENT3>
<ITEMELEMENT4>ITEM44</ITEMELEMENT4>
</item>
</record>
</ResultXml>
Muenchiann 分组 在 XSLT 1.0 中需要一些有序的方法
并谨慎使用一些 分组习语 .
我们必须从创建 key 开始,对记录进行分组,在本例中为
关键元素 1 / ...2 / ...3.
然后主模板(匹配RootNode)应用"group"模板
到每组的第一条记录。
record
的 "group" 模板:
- 打印开始
record
标签,
- 打印
head
元素填充 KEY... 和 HEAD...
源元素,
- 调用"normal"模板给当前组的所有成员,
- 最后,打印结束
record
标签。
record
的 "normal" 模板打印 item
元素已填充
使用 ITEM... 个源元素。
您最不需要的是身份模板。
所以整个脚本如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="recs" match="record"
use="concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3)"/>
<xsl:template match="RootNode">
<ResultXml>
<!-- Apply "group" template to the first record in group -->
<xsl:apply-templates select="record[generate-id() = generate-id(
key('recs', concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3))
[1])]" mode="group"/>
</ResultXml>
</xsl:template>
<!-- "Group" template for record -->
<xsl:template match="record" mode="group">
<record>
<head>
<xsl:copy-of select="*[starts-with(name(), 'KEY') or starts-with(name(), 'HEAD')]"/>
</head>
<!-- Apply "normal" template to all members of the current group -->
<xsl:apply-templates select="key('recs',
concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3))"/>
</record>
</xsl:template>
<!-- "Normal" template for record -->
<xsl:template match="record">
<item>
<xsl:copy-of select="*[starts-with(name(), 'ITEM')]"/>
</item>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
</xsl:template>
</xsl:stylesheet>
有关工作示例,请参阅 http://xsltfiddle.liberty-development.net/6qM2e2k
关于这个主题,我找到了各种答案,但到目前为止我找不到解决方案。
我输入了 XML 结构如下:
<RootNode>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM11</ITEMELEMENT1>
<ITEMELEMENT2>ITEM21</ITEMELEMENT2>
<ITEMELEMENT3>ITEM31</ITEMELEMENT3>
<ITEMELEMENT4>ITEM41</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM21</ITEMELEMENT1>
<ITEMELEMENT2>ITEM22</ITEMELEMENT2>
<ITEMELEMENT3>ITEM23</ITEMELEMENT3>
<ITEMELEMENT4>ITEM24</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABD</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD21</HEADELEMENT1>
<HEADELEMENT2>HEAD22</HEADELEMENT2>
<HEADELEMENT3>HEAD23</HEADELEMENT3>
<HEADELEMENT4>HEAD24</HEADELEMENT4>
<ITEMELEMENT1>ITEM31</ITEMELEMENT1>
<ITEMELEMENT2>ITEM32</ITEMELEMENT2>
<ITEMELEMENT3>ITEM33</ITEMELEMENT3>
<ITEMELEMENT4>ITEM34</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>002</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD31</HEADELEMENT1>
<HEADELEMENT2>HEAD32</HEADELEMENT2>
<HEADELEMENT3>HEAD33</HEADELEMENT3>
<HEADELEMENT4>HEAD34</HEADELEMENT4>
<ITEMELEMENT1>ITEM41</ITEMELEMENT1>
<ITEMELEMENT2>ITEM42</ITEMELEMENT2>
<ITEMELEMENT3>ITEM43</ITEMELEMENT3>
<ITEMELEMENT4>ITEM44</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM51</ITEMELEMENT1>
<ITEMELEMENT2>ITEM52</ITEMELEMENT2>
<ITEMELEMENT3>ITEM53</ITEMELEMENT3>
<ITEMELEMENT4>ITEM54</ITEMELEMENT4>
</record>
</RootNode>
转换的结果应该是这样的:
<ResultXml>
<record>
<header>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM11</ITEMELEMENT1>
<ITEMELEMENT2>ITEM21</ITEMELEMENT2>
<ITEMELEMENT3>ITEM31</ITEMELEMENT3>
<ITEMELEMENT4>ITEM41</ITEMELEMENT4>
</item>
<item>
<ITEMELEMENT1>ITEM21</ITEMELEMENT1>
<ITEMELEMENT2>ITEM22</ITEMELEMENT2>
<ITEMELEMENT3>ITEM23</ITEMELEMENT3>
<ITEMELEMENT4>ITEM24</ITEMELEMENT4>
</item>
<item>
<ITEMELEMENT1>ITEM51</ITEMELEMENT1>
<ITEMELEMENT2>ITEM52</ITEMELEMENT2>
<ITEMELEMENT3>ITEM53</ITEMELEMENT3>
<ITEMELEMENT4>ITEM54</ITEMELEMENT4>
</item>
</record>
<record>
<header>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABD</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD21</HEADELEMENT1>
<HEADELEMENT2>HEAD22</HEADELEMENT2>
<HEADELEMENT3>HEAD23</HEADELEMENT3>
<HEADELEMENT4>HEAD24</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM31</ITEMELEMENT1>
<ITEMELEMENT2>ITEM32</ITEMELEMENT2>
<ITEMELEMENT3>ITEM33</ITEMELEMENT3>
<ITEMELEMENT4>ITEM34</ITEMELEMENT4>
</item>
</record>
<record>
<header>
<KEYELEMENT1>002</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD31</HEADELEMENT1>
<HEADELEMENT2>HEAD32</HEADELEMENT2>
<HEADELEMENT3>HEAD33</HEADELEMENT3>
<HEADELEMENT4>HEAD34</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM41</ITEMELEMENT1>
<ITEMELEMENT2>ITEM42</ITEMELEMENT2>
<ITEMELEMENT3>ITEM43</ITEMELEMENT3>
<ITEMELEMENT4>ITEM44</ITEMELEMENT4>
</item>
</record>
</ResultXml>
对于 KEYELEMENT1、KEYELEMENT2 和 KEYELEMENT3 中的每个不同值,我必须在结果中创建一个记录。其他 header 字段相同,并转换为具有关键字段的 header 元素。项目应映射到具有相同键的记录下。
我用这样的方法尝试了 Muenchian 方法:
<xsl:key name="keyfields" match="record" use="concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3)"/>
<xsl:template match="/">
<ResultXml>
<xsl:apply-templates select="record[generate-id() = generate-id(key('keyfields',concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3))[1])]" mode="header"/>
</ResultXml>
</xsl:template>
<xsl:template match="record" mode="header">
<record>
<header>
<KEYELEMENT1><xsl:value-of select="KEYELEMENT1"/></KEYELEMENT1>
<KEYELEMENT2><xsl:value-of select="KEYELEMENT2"/></KEYELEMENT2>
<KEYELEMENT3><xsl:value-of select="KEYELEMENT3"/></KEYELEMENT3>
<HEADELEMENT1><xsl:value-of select="HEADELEMENT1"/></HEADELEMENT1>
<HEADELEMENT2><xsl:value-of select="HEADELEMENT2"/></HEADELEMENT2>
<HEADELEMENT3><xsl:value-of select="HEADELEMENT3"/></HEADELEMENT3>
<HEADELEMENT4><xsl:value-of select="HEADELEMENT4"/></HEADELEMENT4>
</header>
</record>
</xsl:template>
但我什至无法生成 header 记录。 任何帮助将不胜感激。
如果您将第一个模板匹配项从 /
更改为 /*
(或 RootNode
),您将获得正确的组。
之后,只需将项目分组为 4 组即可。一种方法是在谓词中使用 mod
。
举个例子。我在我的 Muenchian 分组中使用 count()
而不是 generate-id()
,但是这两种方式都可以完成。
示例...
XML 输入
<RootNode>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM11</ITEMELEMENT1>
<ITEMELEMENT2>ITEM21</ITEMELEMENT2>
<ITEMELEMENT3>ITEM31</ITEMELEMENT3>
<ITEMELEMENT4>ITEM41</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM21</ITEMELEMENT1>
<ITEMELEMENT2>ITEM22</ITEMELEMENT2>
<ITEMELEMENT3>ITEM23</ITEMELEMENT3>
<ITEMELEMENT4>ITEM24</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABD</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD21</HEADELEMENT1>
<HEADELEMENT2>HEAD22</HEADELEMENT2>
<HEADELEMENT3>HEAD23</HEADELEMENT3>
<HEADELEMENT4>HEAD24</HEADELEMENT4>
<ITEMELEMENT1>ITEM31</ITEMELEMENT1>
<ITEMELEMENT2>ITEM32</ITEMELEMENT2>
<ITEMELEMENT3>ITEM33</ITEMELEMENT3>
<ITEMELEMENT4>ITEM34</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>002</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD31</HEADELEMENT1>
<HEADELEMENT2>HEAD32</HEADELEMENT2>
<HEADELEMENT3>HEAD33</HEADELEMENT3>
<HEADELEMENT4>HEAD34</HEADELEMENT4>
<ITEMELEMENT1>ITEM41</ITEMELEMENT1>
<ITEMELEMENT2>ITEM42</ITEMELEMENT2>
<ITEMELEMENT3>ITEM43</ITEMELEMENT3>
<ITEMELEMENT4>ITEM44</ITEMELEMENT4>
</record>
<record>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
<ITEMELEMENT1>ITEM51</ITEMELEMENT1>
<ITEMELEMENT2>ITEM52</ITEMELEMENT2>
<ITEMELEMENT3>ITEM53</ITEMELEMENT3>
<ITEMELEMENT4>ITEM54</ITEMELEMENT4>
</record>
</RootNode>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="keyfields" match="record"
use="concat(KEYELEMENT1,'|',KEYELEMENT2,'|',KEYELEMENT3)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<ResultXml>
<xsl:for-each
select="record[count(.|key('keyfields',concat(KEYELEMENT1,'|',KEYELEMENT2,'|',KEYELEMENT3))[1])=1]">
<record>
<header>
<xsl:apply-templates
select="*[starts-with(local-name(), 'KEYELEMENT') or starts-with(local-name(), 'HEADELEMENT')]"/>
</header>
<xsl:for-each select="key('keyfields',concat(KEYELEMENT1,'|',KEYELEMENT2,'|',KEYELEMENT3))/*[starts-with(local-name(),'ITEMELEMENT')][position() mod 4 = 1]">
<item>
<xsl:apply-templates
select=".|following-sibling::*[starts-with(local-name(),'ITEMELEMENT')][position() >= 1 and 4 > position()]"/>
</item>
</xsl:for-each>
</record>
</xsl:for-each>
</ResultXml>
</xsl:template>
</xsl:stylesheet>
输出
<ResultXml>
<record>
<header>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD11</HEADELEMENT1>
<HEADELEMENT2>HEAD12</HEADELEMENT2>
<HEADELEMENT3>HEAD13</HEADELEMENT3>
<HEADELEMENT4>HEAD14</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM11</ITEMELEMENT1>
<ITEMELEMENT2>ITEM21</ITEMELEMENT2>
<ITEMELEMENT3>ITEM31</ITEMELEMENT3>
<ITEMELEMENT4>ITEM41</ITEMELEMENT4>
</item>
<item>
<ITEMELEMENT1>ITEM21</ITEMELEMENT1>
<ITEMELEMENT2>ITEM22</ITEMELEMENT2>
<ITEMELEMENT3>ITEM23</ITEMELEMENT3>
<ITEMELEMENT4>ITEM24</ITEMELEMENT4>
</item>
<item>
<ITEMELEMENT1>ITEM51</ITEMELEMENT1>
<ITEMELEMENT2>ITEM52</ITEMELEMENT2>
<ITEMELEMENT3>ITEM53</ITEMELEMENT3>
<ITEMELEMENT4>ITEM54</ITEMELEMENT4>
</item>
</record>
<record>
<header>
<KEYELEMENT1>001</KEYELEMENT1>
<KEYELEMENT2>ABD</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD21</HEADELEMENT1>
<HEADELEMENT2>HEAD22</HEADELEMENT2>
<HEADELEMENT3>HEAD23</HEADELEMENT3>
<HEADELEMENT4>HEAD24</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM31</ITEMELEMENT1>
<ITEMELEMENT2>ITEM32</ITEMELEMENT2>
<ITEMELEMENT3>ITEM33</ITEMELEMENT3>
<ITEMELEMENT4>ITEM34</ITEMELEMENT4>
</item>
</record>
<record>
<header>
<KEYELEMENT1>002</KEYELEMENT1>
<KEYELEMENT2>ABC</KEYELEMENT2>
<KEYELEMENT3>EFG</KEYELEMENT3>
<HEADELEMENT1>HEAD31</HEADELEMENT1>
<HEADELEMENT2>HEAD32</HEADELEMENT2>
<HEADELEMENT3>HEAD33</HEADELEMENT3>
<HEADELEMENT4>HEAD34</HEADELEMENT4>
</header>
<item>
<ITEMELEMENT1>ITEM41</ITEMELEMENT1>
<ITEMELEMENT2>ITEM42</ITEMELEMENT2>
<ITEMELEMENT3>ITEM43</ITEMELEMENT3>
<ITEMELEMENT4>ITEM44</ITEMELEMENT4>
</item>
</record>
</ResultXml>
Muenchiann 分组 在 XSLT 1.0 中需要一些有序的方法 并谨慎使用一些 分组习语 .
我们必须从创建 key 开始,对记录进行分组,在本例中为 关键元素 1 / ...2 / ...3.
然后主模板(匹配RootNode)应用"group"模板 到每组的第一条记录。
record
的 "group" 模板:
- 打印开始
record
标签, - 打印
head
元素填充 KEY... 和 HEAD... 源元素, - 调用"normal"模板给当前组的所有成员,
- 最后,打印结束
record
标签。
record
的 "normal" 模板打印 item
元素已填充
使用 ITEM... 个源元素。
您最不需要的是身份模板。
所以整个脚本如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="recs" match="record"
use="concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3)"/>
<xsl:template match="RootNode">
<ResultXml>
<!-- Apply "group" template to the first record in group -->
<xsl:apply-templates select="record[generate-id() = generate-id(
key('recs', concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3))
[1])]" mode="group"/>
</ResultXml>
</xsl:template>
<!-- "Group" template for record -->
<xsl:template match="record" mode="group">
<record>
<head>
<xsl:copy-of select="*[starts-with(name(), 'KEY') or starts-with(name(), 'HEAD')]"/>
</head>
<!-- Apply "normal" template to all members of the current group -->
<xsl:apply-templates select="key('recs',
concat(KEYELEMENT1, '|', KEYELEMENT2, '|', KEYELEMENT3))"/>
</record>
</xsl:template>
<!-- "Normal" template for record -->
<xsl:template match="record">
<item>
<xsl:copy-of select="*[starts-with(name(), 'ITEM')]"/>
</item>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
</xsl:template>
</xsl:stylesheet>
有关工作示例,请参阅 http://xsltfiddle.liberty-development.net/6qM2e2k