Xml XSLT可以有效地重新排列或重组节点

Xml XSLT可以有效地重新排列或重组节点,xml,xslt,xpath,Xml,Xslt,Xpath,我正在尝试重新排列一组XML节点以进行进一步处理。 基本思想是,我需要使用高效的XSLT处理更改节点的分组 我的输入结构是: <all_nodes> <student> <math> <record> <detail1/> <detail2/> </record> </math> <science>

我正在尝试重新排列一组XML节点以进行进一步处理。 基本思想是,我需要使用高效的XSLT处理更改节点的分组

我的输入结构是:

<all_nodes>
  <student>
    <math>
      <record>
        <detail1/>
        <detail2/>
      </record>
    </math>
    <science>
      <record>
        <detail1/>
        <detail2/>
      </record>
    </science>
    <history>
      <record>
        <detail1/>
        <detail2/>
      </record>
    </history>
  </student>
  <student>
    <math>
      <record>
        <detail1/>
        <detail2/>
      </record>
    </math>
    <science>
      <record>
        <detail1/>
        <detail2/>
      </record>
    </science>
    <history>
      <record>
        <detail1/>
        <detail2/>
      </record>
    </history>
  </student>
</all_nodes>
通过使用以下代码,我能够实现所需的输出,但是我认为可能有更好的方法。 你能建议我如何改进代码吗

<xsl:template match="/">
    <xsl:call-template name="math"/>
    <xsl:call-template name="science"/>
    <xsl:call-template name="history"/>
</xsl:template>

<xsl:template name="math">
    <xsl:element name="math">
        <xsl:apply-templates select="//math/record" />
    </xsl:element>
</xsl:template>

<xsl:template name="science">
    <xsl:element name="science">
        <xsl:apply-templates select="//science/record" />
    </xsl:element>
</xsl:template>

<xsl:template name="history">
    <xsl:element name="history">
        <xsl:apply-templates select="//history/record" />
    </xsl:element>
</xsl:template>

<xsl:template match="record">
    <xsl:copy-of select="."/>
</xsl:template>


谢谢大家!

如果它总是只有三个已知的主题,那么你可以很简单地这样做:

[deleted]
编辑:实际上,使用密钥不太可能带来显著的优势,所以为什么不让它变得更简单:

XSLT1.0

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

<xsl:template match="/all_nodes">
    <xsl:copy>
        <math>
            <xsl:copy-of select="student/math/record"/>
        </math>
        <science>
            <xsl:copy-of select="student/science/record"/>
        </science>
        <history>
            <xsl:copy-of select="student/history/record"/>
        </history>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

一个更通用的实现,使用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 indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/*">
        <xsl:copy>            
            <xsl:for-each-group select="*/*/*" group-by="local-name(..)">
                <xsl:element name="{current-grouping-key()}">
                    <xsl:copy-of select="current-group()"/>
                </xsl:element>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>


您使用的是哪个版本的XSLT?第一条注释-当名称固定时,您不需要使用
,只需使用文本
。“数学、科学和历史”是一个详尽的列表吗?我使用的是XSLT 2.0版。目前的假设是,我可能有一个不确定数量的主题。现在有几个主题,但我需要出于安全考虑,假设将来可能会添加或删除一些主题——这也是我当前代码中的缺陷。那么,Mads Hansen为您提供了XSLT 2.0的答案,您将在这里找到XSLT1.0的答案:这很有效,谢谢!但是,我是否应该关注性能方面的通配符?代码可能必须处理数千个学生节点。不,性能不应受到影响,但您可以尝试指定元素名称并比较执行时间以确保。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/*">
        <xsl:copy>            
            <xsl:for-each-group select="*/*/*" group-by="local-name(..)">
                <xsl:element name="{current-grouping-key()}">
                    <xsl:copy-of select="current-group()"/>
                </xsl:element>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>