XML/XSL - 用于在组内嵌套组的 Muenchian 方法

XML/XSL - Muenchian method for nesting groups within groups

我正在处理 XSL 样式表,学生按以下顺序分组:

学院->级别->系->主任->专业->学生

所以基本上结构是 "groups within groups"。如果以下内容有意义,请告诉我。如果您需要说明,请告诉我!

这是我正在尝试转换的原始 XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dataroot>
    <student>
        <name_sort>Doe, John</name_sort>
        <name>John Doe</name>
        <level>Undergrad</level>
        <concentration>Studio Art</concentration>
        <college>College 1</college>
        <department>Department 1</department>
       <chair>Chair Name</chair>
    </student>
    <student>
        <name_sort>James, Lisa</name_sort>
        <name>Lisa James</name>
        <level>Undergrad</level>
        <concentration>Studio Art</concentration>
        <college>College 1</college>
        <department>Department 1</department>
       <chair>Chair Name</chair>
    </student>
<dataroot>

XML 使用 XSL 样式表的输出:

<Root>

<!-- Group by College -->

<college>College 1</college>

<!-- Group by Level -->

<level>Undergraduate</level>

<!-- Group by Department -->

<department>Department 1</department>

<!-- Group by Chair -->

<chair>Chair Name</chair>

 <!-- Group by Concentration -->

<concentration>Studio Art</concentration>

<!-- List Students with matching concentration under parent groups -->

<student>
    <name>John Doe</name>
</student>

<student>
    <name>Lisa James</name>
</student>

<!-- Repeat loop -->

</Root>

这是我的尝试,但学生没有正确分组。一些 "undegraduate" 的学生出现在 "graduate" 下,一些集中组重复...

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- Keys for grouping -->
<xsl:key name="colleges" match="student" use="college"/>
<xsl:key name="levels" match="student" use="level"/>
<xsl:key name="departments" match="student" use="department"/>
<xsl:key name="chairs" match="student" use="chair"/>
<xsl:key name="concentrations" match="student" use="concentration"/>

<xsl:template match="/dataroot">
    <Root>
        <xsl:for-each select="student[generate-id() = generate-id(key('colleges', college)[1])]">
            <xsl:sort select="college" order="ascending"/>

            <xsl:for-each select="key('colleges', college)[generate-id() = generate-id(key('levels', level)[1])]">
                <xsl:sort select="level" order="ascending"/>

                <college><xsl:value-of select="college"/></college>
                <xsl:text>&#xd;</xsl:text>

                <level><xsl:value-of select="level"/> degree recipients</level>
                <xsl:text>&#xd;</xsl:text>

                <xsl:for-each select="key('levels', level)[generate-id() = generate-id(key('departments', department)[1])]">
                    <xsl:sort select="department" order="ascending"/>
                    <department><xsl:value-of select="department"/></department>
                    <xsl:text>&#xd;</xsl:text>

                    <xsl:for-each select="key('departments', department)[generate-id() = generate-id(key('chairs', chair)[1])]">
                        <xsl:sort select="chair" order="ascending"/>
                        <chair><xsl:value-of select="chair"/></chair>
                        <xsl:text>&#xd;</xsl:text>

                        <xsl:for-each select="key('chairs', chair)[generate-id() = generate-id(key('concentrations', concentration)[1])]">
                            <xsl:sort select="concentration" order="ascending"/>
                            <concentration><xsl:value-of select="concentration"/></concentration>
                            <xsl:text>&#xd;</xsl:text>

                            <xsl:for-each select="key('concentrations', concentration)">
                                <xsl:sort select="name_sort" order="ascending"/>
                                <student>
                                    <name><xsl:value-of select="name"/></name>
                                    <xsl:text>&#xd;</xsl:text>
                                </student>
                            </xsl:for-each>
                        </xsl:for-each>
                    </xsl:for-each>
                </xsl:for-each>
            </xsl:for-each>
        </xsl:for-each>
    </Root>
</xsl:template>

谁能帮帮我?

使用 XSLT 2 或 3 可以很容易地嵌套 xsl:for-each-group 您尝试使用 xsl:for-each 的方式,但是对于 XSLT 1 和 Muenchian 分组,您需要让第二级键包含第一级级别键,例如

<xsl:key name="colleges" match="student" use="college"/>
<xsl:key name="levels" match="student" use="concat(college, '|', level)"/>

并使用例如

 <xsl:for-each select="key('colleges', college)[generate-id() = generate-id(key('levels', concat(college, '|', level))[1])]">

然后你需要对第三级密钥使用相同的方法

<xsl:key name="departments" match="student" use="concat(department, '|', college, '|', level)"/>

 <xsl:for-each select="key('levels', concat(college, '|', level))[generate-id() = generate-id(key('departments', concat(department, '|', college, '|', level))[1])]">

等等。

考虑使用单个键连接所有需要的父分组。无需多个嵌套 for:each 调用。 运行 需要在 <xsl:apply-templates> 内排序。但是,如果您有很多分组,您将需要一个分组容器元素作为根元素。下面使用 <students> 和调整后的 XML 进行演示。

XML

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dataroot>
    <student>
        <name_sort>Doe, John</name_sort>
        <name>John Doe</name>
        <level>Undergrad</level>
        <concentration>Studio Art</concentration>
        <college>College 1</college>
        <department>Department 1</department>
       <chair>Chair Name</chair>
    </student>
    <student>
        <name_sort>James, Lisa</name_sort>
        <name>Lisa James</name>
        <level>Undergrad</level>
        <concentration>Economics</concentration>
        <college>College 1</college>
        <department>Department 1</department>
       <chair>Chair Name</chair>
    </student>
    <student>
        <name_sort>Doe, Jane</name_sort>
        <name>Jane Doe</name>
        <level>Undergrad</level>
        <concentration>Economics</concentration>
        <college>College 1</college>
        <department>Department 1</department>
       <chair>Chair Name</chair>
    </student>
</dataroot>

XSLT

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

  <!-- single key for grouping -->
  <xsl:key name="concatkey" match="student" use="concat(college, level, department, chair, concentration)"/>

  <xsl:template match="/dataroot">
    <root>
      <xsl:apply-templates select="student[generate-id() = generate-id(key('concatkey', 
                                               concat(college, level, department, chair, concentration)))]"/>
    </root>
  </xsl:template>

  <xsl:template match="student">
    <students>
      <xsl:copy-of select="college"/>
      <xsl:copy-of select="level"/>
      <xsl:copy-of select="department"/>
      <xsl:copy-of select="chair"/>
      <xsl:copy-of select="concentration"/>

      <xsl:for-each select="key('concatkey', concat(college, level, department, chair, concentration))">
        <student><xsl:copy-of select="name"/></student>
      </xsl:for-each>
    </students>
  </xsl:template>

 </xsl:stylesheet>

输出 XSLT Fiddle DEMO

<?xml version="1.0" encoding="utf-8"?>
<root>
  <students>
    <college>College 1</college>
    <level>Undergrad</level>
    <department>Department 1</department>
    <chair>Chair Name</chair>
    <concentration>Economics</concentration>
    <student>
      <name>Lisa James</name>
    </student>
    <student>
      <name>Jane Doe</name>
    </student>
  </students>
  <students>
    <college>College 1</college>
    <level>Undergrad</level>
    <department>Department 1</department>
    <chair>Chair Name</chair>
    <concentration>Studio Art</concentration>
    <student>
      <name>John Doe</name>
    </student>
  </students>
</root>