XSLT 1.0:构建没有真正独特元素属性的子组

时间:2012-09-07 12:38:09

标签: xslt grouping

这个问题与我之前的问题有关XSLT 1.0: using EXSLT to get element name according to substring 我有以下XML:

<?xml version="1.0" encoding="UTF-8"?>
<GenericRecs>
<GenericRecord>
    <record>
        <MBH1/>
    </record>
    <record>
        <BAL1/>
    </record>
    <record>
        <MBH2/>
    </record>
    <record>
        <BAL2/>
    </record>
    <record>
        <PAY2/>
    </record>
    <record>
        <MBH3/>
    </record>
    <record>
        <BAL3/>
    </record>
    <record>
        <PAY3/>
    </record>
</GenericRecord>
</GenericRecs>

我想得到这个输出:

<?xml version="1.0" encoding="UTF-8"?>
<list>
<Card>
    <Data>MBH1</Data>
    <Data>BAL1</Data>
</Card>
<Card>
    <Data>MBH2</Data>
    <Data>BAL2</Data>
    <Data>PAY2</Data>
</Card>
<Card>
    <Data>MBH3</Data>
    <Data>BAL3</Data>
    <Data>PAY3</Data>
</Card>
</list>

在Tomalak的帮助下,我们提出了以下XSLT:

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

<xsl:template match="/">
    <list>
        <xsl:apply-templates select="//record/*[starts-with(name(), 'MBH')]"/>
    </list>
</xsl:template>

<xsl:template match="//record/*[starts-with(name(), 'MBH')]">
    <Card>
        <xsl:copy/>
    </Card> 
</xsl:template>

</xsl:stylesheet>

但这只给了我这个输出:

<?xml version="1.0" encoding="UTF-8"?>
<list>
<Card>
    <MBH1/>
</Card>
<Card>
    <MBH2/>
</Card>
<Card>
    <MBH3/>
</Card>
</list>

很容易唯一地标识<MBH>元素并列出它们。 我曾尝试使用匹配//record/*[not(starts-with(name(), 'MBH'))]的密钥,但当然会选择与之前的<MBH>无关的所有其他记录。 是否有可能获得具有该结构的所需输出? XSL如何知道下一个<MBH>元素的(变化的)元素数量? 感谢您对此提供任何帮助。

祝你好运, 彼得

1 个答案:

答案 0 :(得分:2)

此XSLT 1.0转换

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

 <xsl:key name="kByNameSuf" match="record/*"
  use="translate(name(), translate(name(),'0123456789',''),'')"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "record[generate-id(*[1])
         =
          generate-id(key('kByNameSuf',
                           translate(name(*[1]),
                                     translate(name(*[1]),'0123456789',''),'')
                          )[1]
                      )
         ]
  ">
  <Card>
    <xsl:for-each select=
     "key('kByNameSuf',
          translate(name(*[1]),
                    translate(name(*[1]),'0123456789',''),'')
                    )
     ">
       <Data><xsl:value-of select="name()"/></Data>
    </xsl:for-each>
  </Card>
 </xsl:template>
 <xsl:template match="record"/>
</xsl:stylesheet>

应用于提供的XML文档时:

<GenericRecs>
<GenericRecord>
    <record>
        <MBH1/>
    </record>
    <record>
        <BAL1/>
    </record>
    <record>
        <MBH2/>
    </record>
    <record>
        <BAL2/>
    </record>
    <record>
        <PAY2/>
    </record>
    <record>
        <MBH3/>
    </record>
    <record>
        <BAL3/>
    </record>
    <record>
        <PAY3/>
    </record>
</GenericRecord>
</GenericRecs>

生成想要的正确结果

<GenericRecs>
   <GenericRecord>
      <Card>
         <Data>MBH1</Data>
         <Data>BAL1</Data>
      </Card>
      <Card>
         <Data>MBH2</Data>
         <Data>BAL2</Data>
         <Data>PAY2</Data>
      </Card>
      <Card>
         <Data>MBH3</Data>
         <Data>BAL3</Data>
         <Data>PAY3</Data>
      </Card>
   </GenericRecord>
</GenericRecs>

<强>解释

  1. 使用Muenchian Grouping。

  2. 假设只有名字后缀的数字。

  3. 使用双翻译方法(由Michael Kay首先提出)。


  4. <强> II。 XSLT 2.0解决方案:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:template match="GenericRecord">
         <xsl:for-each-group select="*"
            group-by="replace(name(*[1]), '^.*(\d+)$', '$1')">
          <Card>
              <xsl:for-each select="current-group()">
                <Data><xsl:value-of select="name(*[1])"/></Data>
              </xsl:for-each>
          </Card>
         </xsl:for-each-group>
     </xsl:template>
    </xsl:stylesheet>