我有一个具有以下结构的XML:
<building>
<employee>
<zone>1</zone>
<system>A</system>
<name>Jhon</name>
</employee>
<employee>
<zone>1</zone>
<system>A</system>
<name>Paul</name>
</employee>
<employee>
<zone>1</zone>
<system>B</system>
<name>Matt</name>
</employee>
<employee>
<zone>2</zone>
<system>A</system>
<name>Bob</name>
</employee>
<employee>
<zone>2</zone>
<system>A</system>
<name>Peter</name>
</employee>
</building>
员工按区域和系统升序排序。
如何使用以下格式重构XML?:
<building>
<block>
<employee>
<zone>1</zone>
<system>A</system>
<name>Jhon</name>
</employee>
<employee>
<zone>1</zone>
<system>A</system>
<name>Paul</name>
</employee>
</block>
<block>
<employee>
<zone>1</zone>
<system>B</system>
<name>Matt</name>
</employee>
</block>
<block>
<employee>
<zone>2</zone>
<system>A</system>
<name>Bob</name>
</employee>
<employee>
<zone>2</zone>
<system>A</system>
<name>Peter</name>
</employee>
</block>
</building>
分组条件是按区域和系统划分的(对于那些共享同一区域和同一系统的员工)。
我尝试使用XSLT和XQuery没有任何成功。
答案 0 :(得分:3)
当您需要对&#34; 2条件&#34;进行分组时,您可以组合这些条件来创建复合键。
使用分隔符是个好主意,这样您就可以获得准确的密钥。可以使用concat()
(XPath 1.0或2.0)或string-join()
(仅限XPath 2.0)进行组合。
以下是一些例子。您会注意到在所有3个中我基本上使用相同的东西来创建分组键:concat(zone,'|',system)
XSLT 1.0(或2.0)(Muenchian分组)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="employeeByBlock" match="employee" use="concat(zone,'|',system)"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:for-each select="employee[count(.|key('employeeByBlock',concat(zone,'|',system))[1])=1]">
<xsl:sort select="zone"/>
<xsl:sort select="system" data-type="text"/>
<block>
<xsl:apply-templates select="key('employeeByBlock',concat(zone,'|',system))">
<xsl:sort select="name" data-type="text"/>
</xsl:apply-templates>
</block>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XSLT 2.0 (xsl:for-each-group
)
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:for-each-group select="employee" group-by="concat(zone,'|',system)">
<xsl:sort select="zone"/>
<xsl:sort select="system" data-type="text"/>
<block>
<xsl:apply-templates select="current-group()">
<xsl:sort select="name" data-type="text"/>
</xsl:apply-templates>
</block>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XQuery 3.0 (group by
)
xquery version "3.0";
<building>{
for $employee in /building/employee
let $zone := $employee/zone
let $system := $employee/system
group by $zone, $system
order by $zone, $system
return
<block>{
for $x in $employee
order by $x/name
return $x
}</block>
}</building>
这三个例子都产生相同的输出*:
<building>
<block>
<employee>
<zone>1</zone>
<system>A</system>
<name>Jhon</name>
</employee>
<employee>
<zone>1</zone>
<system>A</system>
<name>Paul</name>
</employee>
</block>
<block>
<employee>
<zone>1</zone>
<system>B</system>
<name>Matt</name>
</employee>
</block>
<block>
<employee>
<zone>2</zone>
<system>A</system>
<name>Bob</name>
</employee>
<employee>
<zone>2</zone>
<system>A</system>
<name>Peter</name>
</employee>
</block>
</building>
*使用Saxon 6.5.5测试XSLT 1.0。使用Saxon-HE 9.5测试XSLT 2.0和XQuery。