使用 XSLT 1.0 在 3 个级别上对数据进行分组

Grouping data on 3 levels using XSLT 1.0

我有这个 XML 文件,其中包含日期、会话和 sub-topics。我的前两个级别工作正常,但我无法正确分组第三个级别。

日期的 1 级组 一天中的所有会话都应在该日期下分组

Session_Number 上的 2 级组 具有相同编号的所有会话应分组在一起。

3 级应该在 Abstract_Title 上分组。 如果 Abstract_Title 相同,它应该出现一次,并在其下列出所有作者。

这是我的 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"/>
<xsl:strip-space elements="*"/>

<xsl:key name="sessions-by-startDate" match="session" use="startDate"/>
<xsl:key name="sessions-by-Number" match="session" use="concat(startDate, '|', Session_Number)"/>
<xsl:key name="sessions-by-Abstract" match="stamp" use="concat(startDate, '|', Session_Number, '|', Abstract_Title)"/>
<xsl:template match="sessions">
<Guide>     
<xsl:for-each select="session[generate-id() = generate-id(key('sessions-by-startDate', startDate)[1])]">
<xsl:text>
</xsl:text><SessionDay>
<startDate><xsl:value-of select="startDate"/></startDate>

 <xsl:for-each select="key('sessions-by-startDate', startDate)[generate-id() = generate-id(key('sessions-by-Number', concat(startDate, '|', Session_Number))[1])]">
 <sessions>
 <xsl:apply-templates select="startTime"/>
 <xsl:apply-templates select="Session_Number" />
 <xsl:apply-templates select="Session_Title"/><xsl:text>
 </xsl:text><TopicTitle>Topics &amp; Faculty</TopicTitle>

 <xsl:for-each select="key('sessions-by-Number', concat(startDate, '|', Session_Number))">


 <xsl:for-each
 select="key('sessions-by-Number', concat(startDate, '|', Session_Number))[count(. | key('sessions-by-Abstract', concat(startDate, '|', Session_Number, '|', Abstract_Title))[1]) = 1]">
 <xsl:sort select="Abstract_Title"/>
 <xsl:text>
 </xsl:text><session>  
 <xsl:apply-templates select="Abstract_Title"/>

 <xsl:for-each select="key('sessions-by-Abstract', concat(startDate, '|', Session_Number, '|', Abstract_Title))">
 <xsl:apply-templates select="Author_LastName"/>
 </xsl:for-each>
 </session>  
 </xsl:for-each>


 </xsl:for-each>
 </sessions>

 </xsl:for-each>
 </SessionDay> 
 </xsl:for-each>
 </Guide>    
 </xsl:template>

<xsl:template match="startDate">
<startDate><xsl:value-of select="."/></startDate></xsl:template>

<xsl:template match="Session_Title"><xsl:text>
</xsl:text><Session_Title><xsl:value-of select="."/></Session_Title>    </xsl:template>

<xsl:template match="Session_Number"><xsl:text>
Session Number </xsl:text><Session_Number><xsl:value-of select="."/>    </Session_Number></xsl:template>

<xsl:template match="Abstract_Title"><Abstract_Title><xsl:value-of select="."/>    </Abstract_Title></xsl:template>

<xsl:template match="Author_LastName">
<Author_LastName><xsl:value-of select="."/></Author_LastName></xsl:template>

</xsl:stylesheet>

这是一些示例 XML:

<?xml version="1.0" encoding="utf-8"?><sessions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<session><startDate>10/24/2015</startDate><Session_Number>92</Session_Number><Session_Title>Sleep Medicine</Session_Title><Abstract_Title>Concluding Remarks</Abstract_Title><Author_LastName>Stoller</Author_LastName></session>
<session><startDate>10/24/2015</startDate><Session_Number>92</Session_Number><Session_Title>Sleep Medicine</Session_Title><Abstract_Title>Welcome and Introduction</Abstract_Title><Author_LastName>Stoller</Author_LastName></session>
<session><startDate>10/24/2015</startDate><Session_Number>568</Session_Number><Session_Title>Hands-on Simulation</Session_Title><Abstract_Title>Airway</Abstract_Title><Author_LastName>Roth</Author_LastName></session>
<session><startDate>10/24/2015</startDate><Session_Number>568</Session_Number><Session_Title>Hands-on Simulation</Session_Title><Abstract_Title>Airway</Abstract_Title><Author_LastName>Eling</Author_LastName></session>
<session><startDate>10/24/2015</startDate><Session_Number>568</Session_Number><Session_Title>Hands-on Simulation</Session_Title><Abstract_Title>Airway</Abstract_Title><Author_LastName>Bell</Author_LastName></session>
<session><startDate>10/25/2015</startDate><Session_Number>1</Session_Number><Session_Title>Diagnosis of Lung Cancer</Session_Title><Abstract_Title>The Role of EBUS</Abstract_Title><Author_LastName>Silvestri</Author_LastName></session>
<session><startDate>10/25/2015</startDate><Session_Number>1</Session_Number><Session_Title>Diagnosis of Lung Cancer</Session_Title><Abstract_Title>Lung Cancer Staging</Abstract_Title><Author_LastName>Liberman</Author_LastName></session>
<session><startDate>10/25/2015</startDate><Session_Number>1</Session_Number><Session_Title>Diagnosis of Lung Cancer</Session_Title><Abstract_Title>Lung Cancer Staging</Abstract_Title><Author_LastName>Hong</Author_LastName></session>
<session><startDate>10/25/2015</startDate><Session_Number>9</Session_Number><Session_Title>Non-small Cell Lung Cancer??</Session_Title><Abstract_Title>Imaging </Abstract_Title><Author_LastName>Duong</Author_LastName></session>
</sessions>

结果 XML 应该如下所示:

<?xml version="1.0" encoding="utf-8"?><Guide>
<SessionDay>
<startDate>10/24/2015</startDate>
<sessions>Session Number <Session_Number>92</Session_Number>
<Session_Title>Sleep Medicine</Session_Title>    
<TopicTitle>Topics &amp; Faculty</TopicTitle>

<session><Abstract_Title>Concluding Remarks</Abstract_Title>
<Author_LastName>Stoller</Author_LastName></session>

<session><Abstract_Title>Welcome and Introduction</Abstract_Title>    
<Author_LastName>Stoller</Author_LastName></session>
</sessions>

<sessions>Session Number <Session_Number>568</Session_Number>
<Session_Title>Hands-on Simulation</Session_Title>
<TopicTitle>Topics &amp; Faculty</TopicTitle>

<session><Abstract_Title>Airway</Abstract_Title>     
<Author_LastName>Roth</Author_LastName>
<Author_LastName>Eling</Author_LastName>
<Author_LastName>Bell</Author_LastName></session>
</sessions></SessionDay>

<SessionDay><startDate>10/25/2015</startDate>
<sessions>Session Number <Session_Number>1</Session_Number>
<Session_Title>Diagnosis of Lung Cancer</Session_Title>
<TopicTitle>Topics &amp; Faculty</TopicTitle>

<session><Abstract_Title>The Role of EBUS</Abstract_Title>
<Author_LastName>Silvestri</Author_LastName></session>

<session><Abstract_Title>Lung Cancer Staging</Abstract_Title>
<Author_LastName>Liberman</Author_LastName></session>

<session><Abstract_Title>Lung Cancer Diagnosis</Abstract_Title>
<Author_LastName>Hong</Author_LastName></session></sessions>

<sessions>Session Number <Session_Number>9</Session_Number>
<Session_Title>Non-small Cell Lung Cancer??</Session_Title>
<TopicTitle>Topics &amp; Faculty</TopicTitle>

<session><Abstract_Title>Imaging</Abstract_Title>
<Author_LastName>Duong</Author_LastName></session>
</sessions></SessionDay>
</Guide>

我当前的 XSLT 可以很好地创建前两组。但是我得到了重复的 Abstract_Title 元素。相反,它应该只有一个唯一的 Abstract_Title 元素,然后列出所有唯一的作者姓名。

我需要添加第三个密钥并生成另一个 ID。但我不确定将它插入何处或需要如何编写。任何帮助将不胜感激

您的 XSLT 存在几个问题:

1.) xsl:key name="sessions-by-Abstract" 匹配 stamp 而不是 session,所以密钥不匹配任何内容。

2.) for-each <xsl:for-each select="key('sessions-by-Number', concat(startDate, '|', Session_Number))"> 是 selecting 来自 sessions-by-Number 键的项目,然后使用来自相同键的 select 作为标准下一个 xsl:for-each,导致重复。

3.) 如果您打算在输出中插入换行符,最好使用实体而不是换行符。例如:<xsl:text>&#xA;</xsl:text>。这样,如果您的 XSLT 是代码格式的,您就不会 运行 丢失换行符或在输出中添加额外空格的风险。但是,如果您只是想更好地格式化输出 XML,使用 <xsl:output indent="yes"/> 会更容易,它会漂亮地打印(格式化和缩进)XML。

<?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" />
    <xsl:strip-space elements="*"/>

    <xsl:key name="sessions-by-startDate" match="session" use="startDate"/>
    <xsl:key name="sessions-by-Number" match="session" use="concat(startDate, '|', Session_Number)"/>
    <xsl:key name="sessions-by-Abstract" match="session" use="concat(startDate, '|', Session_Number, '|', Abstract_Title)"/>

    <xsl:template match="sessions">
        <Guide>     
            <xsl:for-each select="session[generate-id() = generate-id(key('sessions-by-startDate', startDate)[1])]">
                <xsl:text>&#xA;</xsl:text>
                <SessionDay>
                <startDate><xsl:value-of select="startDate"/></startDate>
                 <xsl:for-each select="key('sessions-by-startDate', startDate)[generate-id() = generate-id(key('sessions-by-Number', concat(startDate, '|', Session_Number))[1])]">
                     <sessions>
                         <xsl:apply-templates select="startTime"/>
                         <xsl:apply-templates select="Session_Number"/>
                         <xsl:apply-templates select="Session_Title"/>
                         <xsl:text>&#xA;</xsl:text>
                         <TopicTitle>Topics &amp; Faculty</TopicTitle>
                         <xsl:for-each
                             select="key('sessions-by-Number', concat(startDate, '|', Session_Number))[count(. | key('sessions-by-Abstract', concat(startDate, '|', Session_Number, '|', Abstract_Title))[1]) = 1]">
                             <xsl:sort select="Abstract_Title"/>
                             <xsl:text>&#xA;</xsl:text>
                             <session>
                                 <xsl:apply-templates select="Abstract_Title"/>

                                 <xsl:for-each
                                     select="key('sessions-by-Abstract', concat(startDate, '|', Session_Number, '|', Abstract_Title))">
                                     <xsl:apply-templates select="Author_LastName"/>
                                 </xsl:for-each>
                             </session>
                         </xsl:for-each>
                     </sessions>
                 </xsl:for-each>
                </SessionDay> 
            </xsl:for-each>
        </Guide>    
    </xsl:template>

    <xsl:template match="startDate">
        <startDate><xsl:value-of select="."/></startDate>
    </xsl:template>

    <xsl:template match="Session_Title">
        <xsl:text>&#xA;</xsl:text>
        <Session_Title><xsl:value-of select="."/></Session_Title>    
    </xsl:template>

    <xsl:template match="Session_Number">
        <xsl:text>Session Number </xsl:text>
        <Session_Number>
            <xsl:value-of select="."/>
        </Session_Number>
    </xsl:template>

    <xsl:template match="Abstract_Title"><Abstract_Title><xsl:value-of select="."/>    
        </Abstract_Title>
    </xsl:template>

    <xsl:template match="Author_LastName">
        <Author_LastName><xsl:value-of select="."/></Author_LastName>
    </xsl:template>

</xsl:stylesheet>