XSLT转换为for循环中的多个复杂类型

时间:2012-08-23 13:52:54

标签: xslt xsd

我需要使用以下结构转换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代码。

由于

1 个答案:

答案 0 :(得分:1)

<强>予。当这个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中对问题进行分组的普遍接受的方法。

<强> II。这是一个更紧凑的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分组方法的需要。