Xml XSLT-使用最后设置的标题值将相同类型的多个标记转换为块

Xml XSLT-使用最后设置的标题值将相同类型的多个标记转换为块,xml,xslt,Xml,Xslt,我想得到一个标题之后和下一个标题之前的所有元素,这些标题由标题名括起来 我有一个如下所示的Xml: <Main> <Sec> <Header>A</Header> <Body>A1</Body> </Sec> <Sec> <Body>A2</Body> </Sec> <Sec> <Header&g

我想得到一个标题之后和下一个标题之前的所有元素,这些标题由标题名括起来

我有一个如下所示的Xml:

<Main>
  <Sec>
    <Header>A</Header>
    <Body>A1</Body>
  </Sec>
  <Sec>
    <Body>A2</Body>
  </Sec>
  <Sec>
    <Header>B</Header>
    <Body>B1</Body>
  </Sec>
  <Sec>
    <Body>B2</Body>
  </Sec>
  <Sec>
    <Body>B3</Body>
  </Sec>
</Main>

A.
A1
A2
B
地下一层
地下二层
地下三层
我想将上述Xml转换为以下格式:

<Main>
  <Sec>
    <Type1>A1</Type1>
    <Type1>A2</Type1>
    <Type2>B1</Type2>
    <Type2>B2</Type2>
    <Type2>B3</Type2>
  </Sec>
</Main>

A1
A2
地下一层
地下二层
地下三层
Type1和Type2是固定的,因此我们不需要从header标记获取标记名


我是Xml新手,不知道如何使用基本控件来实现这一点。提前感谢。

下面的XSLT 2.0解决方案用于选择所有
主体
元素,并按第一个
标题沿轴对它们进行分组

对于
Body
元素的每一组,它都使用
标题
值构造“type”元素的名称。我曾经将字母
A
B
转换为它们的代码点编号65和66,然后减去1。如果神奇公式令人困惑,或者实际数据不允许进行简单计算,则可以使用查找、if/else或
xsl:choose

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output indent="yes"/>
    
  <xsl:template match="Main">
    <xsl:copy>
      <Sec>
        <xsl:for-each-group group-by="preceding::Header[1]" select=".//Body">
          <xsl:for-each select="current-group()">
            <xsl:element name="type{string-to-codepoints(current-grouping-key()) - 64}">
              <xsl:apply-templates select="."/>
            </xsl:element>
          </xsl:for-each>
        </xsl:for-each-group>
      </Sec>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

这是一个相当标准的分组问题,答案在很大程度上取决于您使用的是XSLT1.0还是2.0+。阅读您最喜欢的XSLT教科书中的分组。我在XSLT 2.0中能够做到这一点,但事实证明我的项目需要1.0。XSLT 1.0将成为未来的COBOL:旧技术永不消亡。尽管我刚刚了解到我的项目需要XSLT 1.0,但它仍然有效。谢谢你。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output indent="yes"/>
    
  <xsl:template match="Main">
    <xsl:copy>
      <Sec>
        <xsl:apply-templates select="//Body"/>
      </Sec>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Body">       
    <xsl:element name="type{translate(preceding::Header[1], 'AB','12')}">
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
    
</xsl:stylesheet>