1

这个问题有点与我之前的问题XSLT 1.0: using EXSLT to get element name based on 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>

4

1 回答 1

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 分组。

  2. 假设仅在名称的后缀中有数字。

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


二、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>
于 2012-09-07T13:21:53.883 回答