xml - 使用 Muenchian 方法对多个键进行 XSLT 分组

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

这是输入文件。

所有这些 block 都包含在 <allocfile> 中没有出现的标签,不知道为什么?所有这些 block 都包含在顶级元素 <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>

输入文件需要根据多个键进行排序和分组。我继续使用 concat功能和 Muenchian 方法,但从网络上没有太大帮助。我正在使用 XSLT 1.0。

分组规则

  • 文件中的所有节点都有<hd1>具有值 1234..这成为第一组按键并在输出中显示为 <Header1>

    • 分组的第二个键是节点代码。具有相同值的节点被组合在一起。显示为。代码头
  • 第二个键是节点组 G_H , FUN , oH , y .如果所有这些都具有相同的节点值,它们就会组合在一起。它在输出中显示为 <Header2>

  • 节点上没有分组 <alc> , <No> , <DT> , <AMOUNT> .他们在每个群体中都有不同的值(value)观。

最佳答案

如果 hd1 元素始终为“1234”,那么您实际上并没有按它们分组,但如果是,您会像这样定义一个简单的键

<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)" />

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

然后,要查找不同的 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>

关于xml - 使用 Muenchian 方法对多个键进行 XSLT 分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10863491/

相关文章:

java - 如何根据另一个 View 的位置设置 View 宽度?

html - 将字符对象转换为 HTML

javascript - 为什么XSLT在IE10中添加换行符(回车符)

html - XSL - 对于每个不工作

XSLT 拆分输出文件 - muenchian 分组

java - NestedScrollView 内的 ViewPager 内的 RecyclerView - 效果不佳

java - 验证 XSD 本身

xml - 使用 XSLT 匹配 XML 文档中的任何节点,即使我不知道节点的名称

java - 如何接受 docx 中的修订/跟踪更改 (ins/del)?

xslt - if 条件与字符串长度