[英]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.