XSLT循环 - 一次四个节点

时间:2012-08-29 08:27:21

标签: xslt loops muenchian-grouping

首先,我知道这个问题:XSLT: Loop selecting two elements at a time

但是由于元素结构,我没有发现它工作,或者我只是使用mod(两者之一)失败了。

<input>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
</input>

我有以下XML格式,它具有以下结构: - 相同ID的节点将始终组合在一起 - 一个ID总会有四个节点

我希望能够一次选择一个ID的四个节点并遍历每组四个节点,这样我就可以将数据操作到一个输出行。

最好的方法是什么?

3 个答案:

答案 0 :(得分:1)

这个XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:key name="keyByID" match="node" use="id"/>

<xsl:template match="/">
    <output>
        <xsl:apply-templates/>
    </output>
</xsl:template>

<xsl:template match="input">
    <xsl:for-each select="node[generate-id()=generate-id(key('keyByID',id)[1])]">
        <block>
            <id>
                <xsl:value-of select="id"/>
            </id>
            <value>
                <xsl:value-of select="value"/>
            </value>
        </block>
    </xsl:for-each>
</xsl:template>


</xsl:stylesheet>

应用于您的输入XML:

<?xml version="1.0" encoding="UTF-8"?>
<input>
<node>
    <id>1</id>
    <value>3</value>
</node>
<node>
    <id>1</id>
    <value>3</value>
</node>
<node>
    <id>1</id>
    <value>3</value>
</node>
<node>
    <id>1</id>
    <value>3</value>
</node>
<node>
    <id>2</id>
    <value>4</value>
</node>
<node>
    <id>2</id>
    <value>4</value>
</node>
<node>
    <id>2</id>
    <value>4</value>
</node>
<node>
    <id>2</id>
    <value>4</value>
</node>
</input>

给出了这个分组的输出XML:

<?xml version="1.0" encoding="UTF-8"?>
<output>
<block>
    <id>1</id>
    <value>3</value>
</block>
<block>
    <id>2</id>
    <value>4</value>
</block>
</output>

输出按<id>分组。那是你在找什么?我不确定。这个Muenchian Grouping只是简化了你的结构。

祝你好运, 彼得

答案 1 :(得分:1)

由于node元素保证总是以4为一组,所以可以通过一个非常简单的转换生成所需的输出,该转换不使用任何分组方法(例如Muenchian或兄弟姐妹比较)并且可能更有效

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*" name="identity">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="node">
  <sample>
   <xsl:call-template name="identity"/>
  </sample>
 </xsl:template>
 <xsl:template match="node[not(position() mod 4 = 1)]"/>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<input>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
</input>

产生了想要的正确结果

<input>
   <sample>
      <node>
         <id>1</id>
         <value>3</value>
      </node>
   </sample>
   <sample>
      <node>
         <id>2</id>
         <value>4</value>
      </node>
   </sample>
</input>

<强>解释

  1. identity rule 按“原样”复制选择执行它的每个节点。

  2. 另一个模板会覆盖每个node元素的标识模板,该元素是其父级的4k+1 st node子元素。此模板生成包装元素(sample),然后按名称​​调用标识模板将自身复制到输出。

  3. 另一个模板会覆盖每个node元素的标识模板。此模板与每个node元素匹配,但它将被选择执行(优先于之前的模板),仅适用于与之前模板不匹配的节点 - 适用于任何不是{a}}元素的node元素其父母的4k+1 st node孩子。之所以这样,是因为此模板不太具体而不是之前的模板。

  4. 上面讨论的模板3没有正文,这有效地从输出中“删除”匹配的node元素。

答案 2 :(得分:0)

如果你可以保证相同id的节点总是像那样相邻,那么

<xsl:template match="node[not(preceding-sibling::node[1]/id = id])">

将匹配每个id的第一个节点(技术上任何id与之前的节点不同的节点,如果有的话),并且在该模板中你可以使用{{1找到其他人,或者只是在顶层定义一个键然后用它来提取具有相同id的所有节点。