2

我在这里尝试了一些示例,但仍然无法获得正确的输出。我以前没有用过 XSLT。我想对“Detail”元素进行分组,并将所有与该组匹配的“Data”元素作为“Detail”元素的子元素。

例子:

输入

<?xml version="1.0" encoding="utf-8"?>
<File>
  <Detail type="A" group="1" >
    <Data>
      <Nr>1</Nr>
    </Data>
    <Data>
      <Nr>2</Nr>
    </Data>
  </Detail>
  <Detail type="B" group="1">
    <Data>
      <Nr>3</Nr>
    </Data>
    <Data>
      <Nr>4</Nr>
    </Data>
  </Detail>
  <Detail type="B" group="2">
    <Data>
      <Nr>5</Nr>
    </Data>
  </Detail>
  <Detail type="A" group="1">
    <Data>
      <Nr>6</Nr>
    </Data>
  </Detail>
</File>

想要的输出(“Detail type="A" group="1"> 元素组合在一起,并且所有与该组匹配的元素作为子元素)

<?xml version="1.0" encoding="utf-8"?>
<File>
  <Detail type="A" group="1" >
    <Data>
      <Nr>1</Nr>
    </Data>
    <Data>
      <Nr>2</Nr>
    </Data>
    <Data>
      <Nr>6</Nr>
    </Data>
  </Detail>
  <Detail type="B" group="1">
    <Data>
      <Nr>3</Nr>
    </Data>
    <Data>
      <Nr>4</Nr>
    </Data>
  </Detail>
  <Detail type="B" group="2">
    <Data>
      <Nr>5</Nr>
    </Data>
  </Detail>
</File>

感谢帮助 :)

4

2 回答 2

3

一、XSLT 1.0

这是一个使用面向推送的模板的解决方案,而不是<xsl:for-each>(这通常是一种更可重用的方法)。

当这个 XSLT:

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

  <xsl:key name="kDetailAttr" match="Detail" use="concat(@type, '+', @group)" />

  <xsl:template match="/*">
    <File>
      <xsl:apply-templates select="Detail[generate-id() = generate-id(key('kDetailAttr', concat(@type, '+', @group))[1])]" />
    </File>
  </xsl:template>

  <xsl:template match="Detail">
    <Detail type="{@type}" group="{@group}">
      <xsl:copy-of select="key('kDetailAttr', concat(@type, '+', @group))/Data" />
    </Detail>
  </xsl:template>

</xsl:stylesheet>

...应用于原始 XML:

<?xml version="1.0" encoding="UTF-8"?>
<File>
  <Detail type="A" group="1">
    <Data>
      <Nr>1</Nr>
    </Data>
    <Data>
      <Nr>2</Nr>
    </Data>
  </Detail>
  <Detail type="B" group="1">
    <Data>
      <Nr>3</Nr>
    </Data>
    <Data>
      <Nr>4</Nr>
    </Data>
  </Detail>
  <Detail type="B" group="2">
    <Data>
      <Nr>5</Nr>
    </Data>
  </Detail>
  <Detail type="A" group="1">
    <Data>
      <Nr>6</Nr>
    </Data>
  </Detail>
</File>

...产生了想要的结果:

<?xml version="1.0" encoding="utf-8"?>
<File>
  <Detail type="A" group="1">
    <Data>
      <Nr>1</Nr>
    </Data>
    <Data>
      <Nr>2</Nr>
    </Data>
    <Data>
      <Nr>6</Nr>
    </Data>
  </Detail>
  <Detail type="B" group="1">
    <Data>
      <Nr>3</Nr>
    </Data>
    <Data>
      <Nr>4</Nr>
    </Data>
  </Detail>
  <Detail type="B" group="2">
    <Data>
      <Nr>5</Nr>
    </Data>
  </Detail>
</File>

解释:

  • 通过正确应用Muenchian Grouping Method(这在 XSLT 1.0 中是必需的,因为它没有任何“内联”分组机制),我们可以找到唯一节点并将它们的后代分组。

二、XSLT 2.0

当这个 XSLT:

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

  <xsl:template match="/*">
    <File>
      <xsl:for-each-group select="Detail"
      group-by="concat(@type, '+', @group)">
        <Detail type="{@type}" group="{@group}">
          <xsl:copy-of select="current-group()/Data" />
        </Detail>
      </xsl:for-each-group>
    </File>
  </xsl:template>
</xsl:stylesheet>

...应用于原始 XML,产生相同的正确结果。

解释:

  • 通过正确应用 XSLT 2.0 的for-each-group元素,我们可以得到相同的结果。
于 2012-09-11T23:32:02.153 回答
1

注意:这个问题在我接受之前在垃圾箱中搁置了 6 个小时。我的答案在垃圾箱中搁置了两个小时,然后其他人将一些非必要的评论伪装成答案。


研究孟契亚群。对于这些分组问题很方便。

最重要的是<xsl:key>,它基于@type 和@group 的连接创建一个键,这里的这一行,<xsl:for-each select="File/Detail[count(. | key('details', concat(@type,'_',@group))[1]) = 1]">,它隔离了具有特定键的 Detail 节点的第一次出现,并扩展了 @group 和 @ 的特定配对类型。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     <xsl:key name="details" match="Detail" 
             use="concat(@type,'_',@group)"/>
    <xsl:template match='/'>
      <File>
        <xsl:for-each select="File/Detail[count(. | key('details', concat(@type,'_',@group))[1]) = 1]">
          <xsl:sort select="concat(@type,'_',@group)" />
          <Detail type="{@type}" group="{@group}">
            <xsl:for-each select="key('details', concat(@type,'_',@group))">
              <xsl:copy-of select="Data"/>  
           </xsl:for-each>
          </Detail>
       </xsl:for-each>
     </File>
   </xsl:template>   
</xsl:stylesheet>
于 2012-09-11T21:31:13.577 回答