0

首先我知道这个问题:XSLT: Loop selections two elements at 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 的四个节点并循环遍历每组四个节点,以便我可以将数据操作到一个输出行中。

解决这个问题的最佳方法是什么?

4

3 回答 3

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 只是简化了您的结构。

于 2012-08-29T08:42:49.570 回答
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. 身份规则“按原样”复制选择执行它的每个节点。

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

  3. 还有一个模板覆盖了每个node元素的标识模板。此模板匹配每个node元素,但将被选中执行(优先于前一个模板),仅适用于与前一个模板不匹配的节点 - 即任何node不是其父级的4k+1st 子级的元素。node之所以如此,是因为这个模板没有前一个模板那么具体。

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

于 2012-08-29T11:53:52.157 回答
0

如果您可以保证相同 id 的节点将始终像这样相邻,那么

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

将匹配每个 id 的第一个节点(从技术上讲,任何 id 与其之前的节点不同的节点,如果有的话),并且在该模板中您可以使用它following-sibling::来查找其他节点,或者简单地在顶部定义一个键level 然后使用它来提取具有相同 id 的所有节点。

于 2012-08-29T08:38:45.467 回答