使用父元素在 XSLT 中拆分/分组

Posted

技术标签:

【中文标题】使用父元素在 XSLT 中拆分/分组【英文标题】:Split / Group in XSLT with parent elements 【发布时间】:2021-11-24 22:30:52 【问题描述】:

我正在尝试将 XML 文档拆分为固定块。 我想将此文档拆分为 n 个消息节点,其中每个消息节点最多包含 x(此处为 2)行元素。

我的来源是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<Messages>
    <Message>
        <Control>
            <ctrl1>aaa</ctrl1>
            <ctrl2>...</ctrl2>
        </Control>
        <Body>
            <header1>bbb</header1>
            <header2>bbb</header2>
            <header3>
                <something>ccc</something>
            </header3>
            <line>
                <content>ddd</content>
            </line>
            <line>
                <content>eee</content>
            </line>
            <line>
                <content>fff</content>
            </line>
            <line>
                <content>ggg</content>
            </line>
            <line>
                <content>...</content>
            </line>
        </Body>
    </Message>
</Messages>

使用以下 XSLT,我能够创建所需的消息节点,并且还可以让 line-spit 正常工作。但我无法管理它将所有其他元素(控件、正文、标题...)复制到每个消息节点中。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="Message">
        <xsl:for-each-group select="Body/line" group-adjacent="(position() - 1) idiv 2">
            <xsl:element name="Message">
                <xsl:copy-of select="current-group()"/>
            </xsl:element>
        </xsl:for-each-group>
    </xsl:template>

</xsl:stylesheet>

当前结果:

<?xml version="1.0" encoding="UTF-8"?>
<Messages>
   <Message>
      <line>
         <content>ddd</content>
      </line>
      <line>
         <content>eee</content>
      </line>
   </Message>
   <Message>
      <line>
         <content>fff</content>
      </line>
      <line>
         <content>ggg</content>
      </line>
   </Message>
   <Message>
      <line>
         <content>...</content>
      </line>
   </Message>
</Messages>

但应该是:

<?xml version="1.0" encoding="UTF-8"?>
<Messages>
    <Message>
        <Control>
            <ctrl1>aaa</ctrl1>
            <ctrl2>...</ctrl2>
        </Control>
        <Body>
            <header1>bbb</header1>
            <header2>bbb</header2>
            <header3>
                <something>ccc</something>
            </header3>
            <line>
                <content>ddd</content>
            </line>
            <line>
                <content>eee</content>
            </line>
        </Body>
    </Message>
    <Message>
        <Control>
            <ctrl1>aaa</ctrl1>
            <ctrl2>...</ctrl2>
        </Control>
        <Body>
            <header1>bbb</header1>
            <header2>bbb</header2>
            <header3>
                <something>ccc</something>
            </header3>
            <line>
                <content>fff</content>
            </line>
            <line>
                <content>ggg</content>
            </line>
        </Body>
    </Message>
    <Message>
        <Control>
            <ctrl1>aaa</ctrl1>
            <ctrl2>...</ctrl2>
        </Control>
        <Body>
            <header1>bbb</header1>
            <header2>bbb</header2>
            <header3>
                <something>ccc</something>
            </header3>
            <line>
                <content>...</content>
            </line>
        </Body>
    </Message>
</Messages>

非常感谢!

【问题讨论】:

【参考方案1】:

如果您知道要查找的元素的名称,最简单的方法就是选择并构造它们:

   <xsl:template match="Message">
        <xsl:for-each-group select="Body/line" group-adjacent="(position() - 1) idiv 2">
            <Message>
                <xsl:copy-of select="ancestor::Message/Control"/>
                <Body>
                   <xsl:copy-of select="ancestor::Message/Body/*[not(self::line)], current-group()"/>
                </Body>
            </Message>
        </xsl:for-each-group>
    </xsl:template>

【讨论】:

以上是关于使用父元素在 XSLT 中拆分/分组的主要内容,如果未能解决你的问题,请参考以下文章

使用 xslt 1.0 从两个不同的父标签中查找不同的元素

XSLT Grouping's:将父级添加到子元素中的元素集

如何将前缀类型添加到重复父节点并使用 XSLT 选择每个元素的所有元素?

如何使用 xslt 将父节点命名空间复制到子元素?

使用 xslt 2.0 合并具有相同父属性值的元素的 xml 内容

使用 XSLT 基于父字段的嵌套分组