0

我需要使用以下结构转换 XML

<CustomerStatements>
 <CustomerStatement>
  <Name>ABC</Name>
  <ID>1</ID>
  <Amt>10</Amt>
 </CustomerStatement>
 <CustomerStatement>
  <Name>ABC</Name>
  <ID>1</ID>
  <Amt>20</Amt>
 </CustomerStatement>
 <CustomerStatement>
  <Name>XYZ</Name>
  <ID>2</ID>
  <Amt>30</Amt>
 </CustomerStatement>
 <CustomerStatement>
  <Name>XYZ</Name>
  <ID>2</ID>
  <Amt>40</Amt>
 </CustomerStatement>
</CustomerStatements>

<Customers>
 <Customer>
  <Name>ABC</Name>
  <Id>1</Id>
  <Amounts>
   <Amount>10</Amount>
   <Amount>20</Amount>
  </Amounts>
 </Customer>
 <Customer>
  <Name>XYZ</Name>
  <Id>2</Id>
   <Amount>30</Amount>
   <Amount>40</Amount>
 </Customer>
</Customers>

我尝试使用 for 循环并将名称放入变量中以比较下一条记录中的名称,但这不起作用。谁能帮我提供一个示例 XSLT psudo 代码。

谢谢

4

1 回答 1

1

I. 当这个 XSLT 1.0 解决方案时:

<?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="kCustByNameId"
    match="CustomerStatement"
    use="concat(Name, '+', ID)" />

  <xsl:template match="/*">
    <Customers>
      <xsl:apply-templates 
        select="CustomerStatement[
          generate-id() = 
          generate-id(key('kCustByNameId', concat(Name, '+', ID))[1])]" />
    </Customers>
  </xsl:template>

  <xsl:template match="CustomerStatement">
    <Customer>
      <xsl:copy-of select="Name|ID" />
      <Amounts>
        <xsl:for-each select="key('kCustByNameId', concat(Name, '+', ID))/Amt">
          <Amount>
            <xsl:apply-templates />
          </Amount>
        </xsl:for-each>
      </Amounts>
    </Customer>
  </xsl:template>
</xsl:stylesheet>

...应用于 OP 的原始 XML:

<CustomerStatements>
  <CustomerStatement>
    <Name>ABC</Name>
    <ID>1</ID>
    <Amt>10</Amt>
  </CustomerStatement>
  <CustomerStatement>
    <Name>ABC</Name>
    <ID>1</ID>
    <Amt>20</Amt>
  </CustomerStatement>
  <CustomerStatement>
    <Name>XYZ</Name>
    <ID>2</ID>
    <Amt>30</Amt>
  </CustomerStatement>
  <CustomerStatement>
    <Name>XYZ</Name>
    <ID>2</ID>
    <Amt>40</Amt>
  </CustomerStatement>
</CustomerStatements>

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

<?xml version="1.0" encoding="UTF-8"?><Customers>
  <Customer>
    <Name>ABC</Name>
    <ID>1</ID>
    <Amounts>
      <Amount>10</Amount>
      <Amount>20</Amount>
    </Amounts>
  </Customer>
  <Customer>
    <Name>XYZ</Name>
    <ID>2</ID>
    <Amounts>
      <Amount>30</Amount>
      <Amount>40</Amount>
    </Amounts>
  </Customer>
</Customers>

这里首先要看的是Muenchian Grouping,这是 XSLT 1.0 中普遍接受的对问题进行分组的方法。

二、这是一个更紧凑的 XSLT 2.0 解决方案:

<?xml version="1.0" encoding="UTF-8"?>
<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="/*">
     <Customers>
       <xsl:for-each-group select="CustomerStatement" group-by="ID">
         <Customer>
           <xsl:copy-of select="current-group()[1]/Name|current-group()[1]/ID" />
           <Amounts>
             <xsl:for-each select="current-group()/Amt">
               <Amount>
                 <xsl:apply-templates />
               </Amount>    
             </xsl:for-each>
           </Amounts>
         </Customer>
       </xsl:for-each-group>
     </Customers>
   </xsl:template>      
</xsl:stylesheet>

在这种情况下,请注意 XSLT 2.0 对for-each-group元素的使用,这消除了对有时冗长且可能令人困惑的 Muenchian Grouping 方法的需要。

于 2012-08-23T15:24:32.183 回答