【问题标题】:XSLT grouping on multiple keys using Muenchian method使用 Muenchian 方法对多个键进行 XSLT 分组
【发布时间】:2012-06-02 15:15:45
【问题描述】:

这是输入文件。

所有这些块都包裹在<allocfile> 标签中,但没有出现,不知道为什么?所有这些块都包裹在顶级元素<xml>中。

<XML>
  <AllocFile>
    <alc>1</alc>
    <No>11/10</No>
    <DT>20090401</DT> 
    <G_H>147</G_H>
    <FUN>125487</FUN>
    <oH>11</oH>
    <y>9</y>
    <AMOUNT>8000000</AMOUNT>
    <Code>033195</Code>
    <hd1>1234</hd1>
  </AllocFile>
  <AllocFile>
    <alc>2</alc>
    <No>14/10</No>
    <DT>20090401</DT>
    <G_H>147</G_H>
    <FUN>125487</FUN>
    <oH>11</oH>
    <y>9</y>
    <AMOUNT>8400000</AMOUNT>
    <Code>033195</Code>
    <hd1>1234</hd1>
  </AllocFile>
  <AllocFile>
    <alc>3</alc>
    <No>74/10</No>
    <DT>20090401</DT>
    <G_H>147</G_H>
    <FUN>125487</FUN>
    <oH>11</oH>
    <y>9</y>
    <AMOUNT>8740000</AMOUNT>
    <Code>033195</Code>
    <hd1>1234</hd1>
  </AllocFile>
  <AllocFile>
    <alc>2</alc>
    <No>74/10</No>
    <DT>20090401</DT>
    <G_H>117</G_H>
    <FUN>125487</FUN>
    <oH>19</oH>
    <y>9</y>
    <AMOUNT>74512</AMOUNT>
    <Code>033118</Code>
    <hd1>1234</hd1>
  </AllocFile>
  <AllocFile>
    <alc>3</alc>
    <No>14/10</No>
    <DT>20090401</DT>
    <G_H>117</G_H>
    <FUN>125487</FUN>
    <oH>19</oH>
    <y>9</y>
    <AMOUNT>986541</AMOUNT>
    <Code>033147</Code>
    <hd1>1234</hd1>
  </AllocFile> 
</XML>

输出是

<Header1>
  <Hd1>1234</Hd1>
  <CodeHeader>
    <Code>033195</Code>
    <Header2>
      <G_H>147</G_H>
      <FUN>125487</FUN>
      <oH>11</oH>
      <y>9</y>
      <allocheader>
        <alc>1</alc>
        <No>11/10</No>
        <DT>20090401</DT>
        <AMOUNT>8000000</AMOUNT>
      </allocheader>
      <allocheader>
        <alc>2</alc>
        <No>14/10</No>
        <DT>20090401</DT>
        <AMOUNT>8400000</AMOUNT>
      </allocheader>
      <allocheader>
        <alc>3</alc>
        <No>74/10</No>
        <DT>20090401</DT>
        <AMOUNT>8740000</AMOUNT>
      </allocheader>
    </Header2>
  </CodeHeader>
  <CodeHeader>
        <Code>033118</Code>
        <Header2>
      <G_H>117</G_H>
      <FUN>125487</FUN>
         <oH>19</oH>
            <y>9</y>
             <allocheader>
             <alc>2</alc>
             <No>74/10</No>
             <DT>20090401</DT>
             <AMOUNT>74512</AMOUNT>
           </allocheader>
       </Header2>
    </codeHeader>
   <CodeHeader>
        <Code>033147</Code>
           <Header2>
          <G_H>117</G_H>
          <FUN>125487</FUN>
          <oH>19</oH>
          <y>9</y>
         <allocheader>
           <alc>3</alc>
            <No>14/10</No>
            <DT>20090401</DT>
            <AMOUNT>986541</AMOUNT>
          </allocheader>
         </Header2>
      </CodeHeader>
</Header1>

输入文件需要在多个key的基础上进行排序和分组。我继续使用concat 函数和 Muenchian 方法,但从网络上并没有太多帮助。我正在使用 XSLT 1.0。

分组规则

  • 文件中的所有节点都有&lt;hd1&gt;,值为1234..,这将成为第一个键组,并在输出中显示为&lt;Header1&gt;

    • 分组的第二个键是节点代码。具有相同值的节点被组合在一起。显示为。代码头
  • 第二个key是节点组G_HFUNoHy。如果所有这些都具有相同的节点值,则它们将组合在一起。它在输出中显示为&lt;Header2&gt;

  • 在节点 &lt;alc&gt;&lt;No&gt;&lt;DT&gt;&lt;AMOUNT&gt; 上不会发生分组。它们在每个组中都有不同的值。

【问题讨论】:

  • 提供的所需输出不是格式良好的 XML 文档 -- 请正确。
  • 在 o/p xml 末尾添加了 标签,使其成为格式良好的 xml 文档
  • @Manks:您需要在任何代码示例前面加上四个空格才能显示出来。我已经为你做了这个,所以它现在应该都能正确显示了!
  • 您说“文件中的所有节点都将具有值为 1234 的 &lt;hd1&gt;”?会一直这样吗?如果&lt;hd1&gt; 包含另一个值会怎样?如果它们都相同,则您并没有真正按它们进行分组,而只需要一个键。
  • 我已经更新了我当前的答案以应对扩展的要求

标签: xml xslt xslt-1.0 xslt-grouping muenchian-grouping


【解决方案1】:

如果 hd1 元素始终为 '1234',那么您并没有真正按它们进行分组,但如果是这样,您将定义一个简单的键

<xsl:key name="header1" match="AllocFile" use="hd1" />

对于第二个键,您需要考虑 Code 元素

<xsl:key name="header2" match="AllocFile" use="concat(hd1, '|', Code)" />

然后对于最后一个键,您将定义一个更复杂的键来处理所有元素

<xsl:key name="header3" 
   match="AllocFile" 
   use="concat(hd1 '|', Code, '|', G_H, '|', FUN, '|', oH, '|', y)" />

请注意使用“管道”字符作为分隔符。选择一个在任何选定元素中都不会出现的分隔符很重要。

然后,要查找不同的 header1 元素,您将查找首先出现在 header1 键中的元素

<xsl:apply-templates 
   select="AllocFile[generate-id() = generate-id(key('header1', hd1)[1])]" 
   mode="header1" />

要在每个 header1 元素中找到不同的 Code 元素,您可以执行以下操作

<xsl:apply-templates 
   select="key('header1', hd1)
     [generate-id() = generate-id(key('header2', concat(hd1, '|', Code))[1])]" 
   mode="header2" /> 

最后,在每个代码组中,要找到不同的“header3”元素,您需要在第三个键中查找第一个元素

<xsl:apply-templates 
 select="key('header2', concat(hd1, '|', Code))
    [generate-id() = 
     generate-id(key('header3', concat(hd1, '|', Code, '|', G_H, '|', FUN, '|', oH, '|', y))[1])]" 
 mode="header3" /> 

这是完整的 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:key name="header1" match="AllocFile" use="hd1"/>
   <xsl:key name="header2" match="AllocFile" use="concat(hd1, '|', Code)"/>
   <xsl:key name="header3" match="AllocFile" use="concat(hd1, '|', Code, '|', G_H, '|', FUN, '|', oH, '|', y)"/>

   <xsl:template match="/XML">
      <xsl:apply-templates select="AllocFile[generate-id() = generate-id(key('header1', hd1)[1])]" mode="header1"/>
   </xsl:template>

   <xsl:template match="AllocFile" mode="header1">
      <Header1>
         <Hd1>
            <xsl:value-of select="hd1"/>
         </Hd1>
         <xsl:apply-templates select="key('header1', hd1)[generate-id() = generate-id(key('header2', concat(hd1, '|', Code))[1])]" mode="header2"/>
      </Header1>
   </xsl:template>

   <xsl:template match="AllocFile" mode="header2">
      <CodeHeader>
         <xsl:copy-of select="Code"/>
         <xsl:apply-templates select="key('header2', concat(hd1, '|', Code))[generate-id() = generate-id(key('header3', concat(hd1, '|', Code, '|', G_H, '|', FUN, '|', oH, '|', y))[1])]" mode="header3"/>
      </CodeHeader>
   </xsl:template>

   <xsl:template match="AllocFile" mode="header3">
      <Header2>
         <xsl:copy-of select="G_H|FUN|oH|y"/>
         <xsl:apply-templates select="key('header3', concat(hd1, '|', Code, '|', G_H, '|', FUN, '|', oH, '|', y))"/>
      </Header2>
   </xsl:template>

   <xsl:template match="AllocFile">
      <allocheader>
         <xsl:copy-of select="alc|No|DT|AMOUNT"/>
      </allocheader>
   </xsl:template>
</xsl:stylesheet>

请注意在模板匹配上使用 mode 属性来区分所有匹配 AllocFile 元素的多个模板。

当应用于您的示例 XML 时,将输出以下内容

<Header1>
   <Hd1>1234</Hd1>
   <CodeHeader>
      <Code>033195</Code>
      <Header2>
         <G_H>147</G_H>
         <FUN>125487</FUN>
         <oH>11</oH>
         <y>9</y>
         <allocheader>
            <alc>1</alc>
            <No>11/10</No>
            <DT>20090401</DT>
            <AMOUNT>8000000</AMOUNT>
         </allocheader>
         <allocheader>
            <alc>2</alc>
            <No>14/10</No>
            <DT>20090401</DT>
            <AMOUNT>8400000</AMOUNT>
         </allocheader>
         <allocheader>
            <alc>3</alc>
            <No>74/10</No>
            <DT>20090401</DT>
            <AMOUNT>8740000</AMOUNT>
         </allocheader>
      </Header2>
   </CodeHeader>
   <CodeHeader>
      <Code>033118</Code>
      <Header2>
         <G_H>117</G_H>
         <FUN>125487</FUN>
         <oH>19</oH>
         <y>9</y>
         <allocheader>
            <alc>2</alc>
            <No>74/10</No>
            <DT>20090401</DT>
            <AMOUNT>74512</AMOUNT>
         </allocheader>
      </Header2>
   </CodeHeader>
   <CodeHeader>
      <Code>033147</Code>
      <Header2>
         <G_H>117</G_H>
         <FUN>125487</FUN>
         <oH>19</oH>
         <y>9</y>
         <allocheader>
            <alc>3</alc>
            <No>14/10</No>
            <DT>20090401</DT>
            <AMOUNT>986541</AMOUNT>
         </allocheader>
      </Header2>
   </CodeHeader>
</Header1>

如果您确实有不同的 hd1 元素,除了 '1234' 之外,您最终会得到多个 Header1 元素,因此您的输出将不是格式正确的 XML .通过修改与文档元素匹配的初始模板,将它们包装在根元素中就足够简单了。

<xsl:template match="/XML">
   <Root>
      <xsl:apply-templates select="AllocFile[generate-id() = generate-id(key('header1', hd1)[1])]" mode="header1" />
   </Root>
</xsl:template>

【讨论】:

  • 提供的答案很棒,但是我错过了我现在添加的分组规则,请问您还需要对 xslt 进行哪些修改。我尝试为代码头添加一个键,并在头 1 匹配中添加了一个节点 xsl:应用模板 corr。到代码头。但它给了我编译错误。
  • 您能否进一步扩展您的问题,因为我不太确定新要求。你看,我的答案中显示的输出当前与您问题中的预期输出相匹配。谢谢!
  • 这是完全正确的,但我的观点是,如果存在具有多个 值的节点,如何进行分组。我对 XSL 所做的更改是 1. 定义了一个键 <key name="CodeHeader" match="AllocFile" use="concat(hd1, '|', Code)"></key> 和 2. 并添加了 <xsl :apply-templates select="key('header1', hd1)[generate-id() = generate-id(key('CodeHeader', concat(hd1, '|',Code))[1])]"></xsl> 并删除了 <copy-of select="Code"></copy-of> 语句。但是出了点问题,它没有给出所需的输出。
  • 您能否修改您的输入样本以显示有多个 &lt;code&gt; 值的情况?可以出现的&lt;code&gt; 值的数量会有限制吗?
  • 我已经更改了最后两个 块的代码值。没有限制,因此所有这些块可以不同(最坏情况),也可以相同(最好情况)。
猜你喜欢
  • 2015-07-30
  • 1970-01-01
  • 2014-08-07
  • 2017-11-13
  • 1970-01-01
  • 1970-01-01
  • 2015-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多