【问题标题】:Hierarchy of an XML via XSL transformation通过 XSL 转换的 XML 层次结构
【发布时间】:2020-11-15 13:21:40
【问题描述】:

关于 XML/XSL 的一个小问题。

我有以下 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>

我想像这样分层这个 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>

这可能吗? 如果是这样,要应用的 XSL 转换是什么(仅限 XSLT 1.0)

谢谢, 弗洛伦特

喝咖啡会妨碍你入睡。另一方面,睡觉会阻止你喝咖啡。

【问题讨论】:

标签: xml xslt


【解决方案1】:

在 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>

对于 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>

【讨论】:

  • 非常感谢马丁。不幸的是,我不能应用 XLST 2,我需要 XSLT 1.0 中的解决方案(我在我的初始请求中添加了这个精度)
  • @FlorentBignier,我已经为 XSLT 1 添加了一个示例,尽管知道您是哪个平台而您无法访问 XSLT 2 或 3 并且 Saxon 可用于 Java,这会很有趣, .NET、C/C++、Python、JavaScript 和 Node.js。
【解决方案2】:

我找到了解决办法:

<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>

如果有人知道 Muenchian 方法并且可以告诉我如何转置这个 XSLT...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-05
    • 2016-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-23
    • 1970-01-01
    相关资源
    最近更新 更多