简体   繁体   English

通过 XSL 转换的 XML 的层次结构

[英]Hierarchy of an XML via XSL transformation

A little question about XML/XSL.关于 XML/XSL 的一个小问题。

I have the following XML:我有以下 XML:

<Employees>
    <Employee> <ID>1</ID> <WeekID>1</WeekID> <DayID>1</DayID> <Hours>5</Hours> </Employee>
    <Employee> <ID>1</ID> <WeekID>1</WeekID> <DayID>1</DayID> <Hours>4</Hours> </Employee>
    <Employee> <ID>1</ID> <WeekID>1</WeekID> <DayID>2</DayID> <Hours>7</Hours> </Employee>
    <Employee> <ID>1</ID> <WeekID>2</WeekID> <DayID>1</DayID> <Hours>5</Hours> </Employee>
    <Employee> <ID>1</ID> <WeekID>2</WeekID> <DayID>3</DayID> <Hours>8</Hours> </Employee>
    <Employee> <ID>2</ID> <WeekID>1</WeekID> <DayID>1</DayID> <Hours>5</Hours> </Employee>
    <Employee> <ID>2</ID> <WeekID>2</WeekID> <DayID>4</DayID> <Hours>4</Hours> </Employee>
</Employees>

I want to hierarchize this XML like this:我想像这样对这个 XML 进行分层:

<Employees>
    <Employee>
        <ID>1</ID>
        <Weeks>
            <Week>
                <WeekID>1</WeekID>
                <Days>
                    <Day>
                        <DayID>1</DayID>
                        <Hours>5</Hours>
                        <Hours>4</Hours>
                    </Day>
                    <Day>
                        <DayID>2</DayID>
                        <Hours>7</Hours>
                    </Day>
                </Days>
            </Week>
            <Week>
                <WeekID>2</WeekID>
                <Days>
                    <Day>
                        <DayID>1</DayID>
                        <Hours>5</Hours>
                    </Day>
                    <Day>
                        <DayID>3</DayID>
                        <Hours>8</Hours>
                    </Day>
                </Days>
            </Week>
        </Weeks>
    </Employee>
    <Employee>
        <ID>2</ID>
        <Weeks>
            <Week>
                <WeekID>1</WeekID>
                <Days>
                    <Day>
                        <DayID>1</DayID>
                        <Hours>5</Hours>
                    </Day>
                </Days>
            </Week>
            <Week>
                <WeekID>2</WeekID>
                <Days>
                    <Day>
                        <DayID>4</DayID>
                        <Hours>4</Hours>
                    </Day>
                </Days>
            </Week>
        </Weeks>
    </Employee>
</Employees>

Is this possible?这可能吗? If so, what would be the XSL transformation to apply (with XSLT 1.0 only) ?如果是这样,要应用的 XSL 转换是什么(仅限 XSLT 1.0)

Thanks, Florent谢谢,弗洛伦特

Drinking coffee prevents you from sleeping.喝咖啡会让你无法入睡。 On the other hand, sleeping prevents you from drinking coffee.另一方面,睡眠会阻止你喝咖啡。

In XSLT 2 or later, you can simply nest three xsl:for-each-group instructions:在 XSLT 2 或更高版本中,您可以简单地嵌套三个xsl:for-each-group指令:

  <xsl:template match="Employees">
    <xsl:copy>
      <xsl:for-each-group select="Employee" group-by="ID">
        <xsl:copy>
          <xsl:copy-of select="ID"/>
          <Weeks>
            <xsl:for-each-group select="current-group()" group-by="WeekID">
              <Week>
                <xsl:copy-of select="WeekID"/>
                <Days>
                  <xsl:for-each-group select="current-group()" group-by="DayID">
                    <Day>
                      <xsl:copy-of select="DayID"/>
                      <xsl:copy-of select="current-group()/Hours"/>
                    </Day>
                  </xsl:for-each-group>
                </Days>
              </Week>
            </xsl:for-each-group>
          </Weeks>
        </xsl:copy>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

With XSLT 1, use Muenchian grouping with concatenated key values for the three levels:对于 XSLT 1,使用 Muenchian 分组和三个级别的串联键值:

  <xsl:key name="emp" match="Employee" use="ID"/>
  <xsl:key name="week" match="Employee" use="concat(ID, '|', WeekID)"/>
  <xsl:key name="day" match="Employee" use="concat(ID, '|', WeekID, '|', DayID)"/>
    
  <xsl:template match="Employees">
    <xsl:copy>
      <xsl:for-each select="Employee[generate-id() = generate-id(key('emp', ID)[1])]">
        <xsl:copy>
          <xsl:copy-of select="ID"/>
          <Weeks>
            <xsl:for-each select="key('emp', ID)[generate-id() = generate-id(key('week', concat(ID, '|', WeekID))[1])]">
              <Week>
                <xsl:copy-of select="WeekID"/>
                <Days>
                  <xsl:for-each select="key('week', concat(ID, '|', WeekID))[generate-id() = generate-id(key('day', concat(ID, '|', WeekID, '|', DayID))[1])]">
                    <Day>
                      <xsl:copy-of select="DayID"/>
                      <xsl:copy-of select="key('day', concat(ID, '|', WeekID, '|', DayID))/Hours"/>
                    </Day>
                  </xsl:for-each>
                </Days>
              </Week>
            </xsl:for-each>
          </Weeks>
        </xsl:copy>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

I found a solution:我找到了一个解决方案:

<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:template match="/Employees">
<Employees>
<xsl:for-each select="Employee">
<xsl:variable name="EmployeeID" select="ID" />
<xsl:if test="not(preceding-sibling::Employee[ID=$EmployeeID])">
<Employee>
<ID><xsl:value-of select="$EmployeeID"/></ID>
<Weeks>

<xsl:for-each select="../Employee[ID=$EmployeeID]">
<xsl:variable name="WeekID" select="WeekID" />
<xsl:if test="not(preceding-sibling::Employee[ID=$EmployeeID and WeekID=$WeekID])">
<Week>
<WeekID><xsl:value-of select="$WeekID"/>
</WeekID>
<Days>

<xsl:for-each select="../Employee[ID=$EmployeeID and WeekID=$WeekID]">
<xsl:variable name="DayID" select="DayID" />
<xsl:if test="not(preceding-sibling::Employee[ID=$EmployeeID and WeekID=$WeekID and DayID=$DayID])">
<Day>
<DayID><xsl:value-of select="$DayID"/></DayID>

<xsl:for-each select="../Employee[ID=$EmployeeID and WeekID=$WeekID and DayID=$DayID]">
<xsl:variable name="Hours" select="Hours" />
<xsl:if test="not(preceding-sibling::Employee[ID=$EmployeeID and WeekID=$WeekID and DayID=$DayID and Hours=$Hours])">
<Hours><xsl:value-of select="Hours"/></Hours>
</xsl:if>
</xsl:for-each>

</Day>
</xsl:if>
</xsl:for-each>

</Days>
</Week>
</xsl:if> 
</xsl:for-each>

</Weeks>
</Employee>
</xsl:if>         
</xsl:for-each>
</Employees>
</xsl:template>

</xsl:stylesheet>

If someone knows the Muenchian method and can tell me how to transpose this XSLT...如果有人知道 Muenchian 方法并能告诉我如何转置这个 XSLT...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM