如何使用XSLT将属性转换为标记并避免重复?

首先,我在这里度过了很多时间,经常在这里给出答案。 但是现在我面临着一个新的话题 – XSLT – 现在我真的需要帮助。

好的,我遇到的问题是将我从Excel接收到的XML文件转换为XFA格式的文件。 Excel只支持平面数据,但这不符合我的XFA表单的date层次结构。

这里是我从Excel收到的数据:

<Accounts> <Account Category="001" Region="AAA" Name="dolor" Value="123" Type="A" Rating="1,25"/> <Account Category="001" Region="AAA" Name="sit amet" Value="134" Type="A" Rating="1,25"/> <Account Category="004" Region="BBB" Name="consetetur" Value="434" Type="A" Rating="1,25"/> <Account Category="002" Region="AAA" Name="sadipscing" Value="84" Type="A" Rating="1,25"/> <Account Category="007" Region="ZZZ" Name="elitr" Value="33" Type="A" Rating="1,25"/> <Account Category="004" Region="CCC" Name="aliquyam" Value="6" Type="A" Rating="1,25"/> <Account Category="001" Region="BBB" Name="ipsum" Value="34" Type="A" Rating="1,25"/> <Account Category="003" Region="ZZZ" Name="lorem" Value="75" Type="A" Rating="2.87"/> </Accounts> 

这就是我想要改变它的方式:

 <Accounts> <Category name="001"> <Region name="AAA"> <Account Name="dolor" Value="123" Type="A" Rating="1,25"/> <Account Name="sit amet" Value="134" Type="A" Rating="1,25"/> </Region> <Region name="BBB"> <Account Name="ipsum" Value="34" Type="A" Rating="1,25"/> </Region> </Category> <Category name="002"> <Region name="BBB"> <Account Name="sadipscing" Value="84" Type="A" Rating="1,25"/> </Region> </Category> <Category name="003"> <Region name="ZZZ"> <Account Name="lorem" Value="75" Type="A" Rating="2.87"/> </Region> </Category> ... </Accounts> 

我已经花了几天时间,但是我唯一能做的就是为这个分类创build新的标签而不需要重复。 这是我目前的XSLT文件。

 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" /> <xsl:variable name="Root" select="Accounts" /> <xsl:variable name="CategoryList" select="$Root/Account[not(@Category=following::Account/@Category)]" /> <xsl:template match="/"> <Accounts> <xsl:for-each select="$CategoryList"> <xsl:variable name="varCategory" select="./@Category" /> <Category> <xsl:value-of select="$varCategory"/> </Category> </xsl:for-each> </Accounts> </xsl:template> </xsl:stylesheet> 

任何帮助是受欢迎的。

您不会说如果您使用XSLT 1.0或XSLT 2.0。

这是一个多层次的sorting,对于XSLT 1.0,我告诉我的学生更容易使用基于variables的分组方法编写。

对于XSLT 2.0,使用可用的构造很容易完成。

两种解决scheme都在这里

 T:\ftemp>type mxps.xml <Accounts> <Account Category="001" Region="AAA" Name="dolor" Value="123" Type="A" Rating="1,25"/> <Account Category="001" Region="AAA" Name="sit amet" Value="134" Type="A" Rating="1,25"/> <Account Category="004" Region="BBB" Name="consetetur" Value="434" Type="A" Rating="1,25"/> <Account Category="002" Region="AAA" Name="sadipscing" Value="84" Type="A" Rating="1,25"/> <Account Category="007" Region="ZZZ" Name="elitr" Value="33" Type="A" Rating="1,25"/> <Account Category="004" Region="CCC" Name="aliquyam" Value="6" Type="A" Rating="1,25"/> <Account Category="001" Region="BBB" Name="ipsum" Value="34" Type="A" Rating="1,25"/> <Account Category="003" Region="ZZZ" Name="lorem" Value="75" Type="A" Rating="2.87"/> </Accounts> T:\ftemp>call xslt mxps.xml mxps.xsl <?xml version="1.0" encoding="utf-8"?> <Accounts> <Category name="001"> <Region name="AAA"> <Account Name="dolor" Value="123" Type="A" Rating="1,25"/> <Account Name="sit amet" Value="134" Type="A" Rating="1,25"/> </Region> <Region name="BBB"> <Account Name="ipsum" Value="34" Type="A" Rating="1,25"/> </Region> </Category> <Category name="002"> <Region name="AAA"> <Account Name="sadipscing" Value="84" Type="A" Rating="1,25"/> </Region> </Category> <Category name="003"> <Region name="ZZZ"> <Account Name="lorem" Value="75" Type="A" Rating="2.87"/> </Region> </Category> <Category name="004"> <Region name="BBB"> <Account Name="consetetur" Value="434" Type="A" Rating="1,25"/> </Region> <Region name="CCC"> <Account Name="aliquyam" Value="6" Type="A" Rating="1,25"/> </Region> </Category> <Category name="007"> <Region name="ZZZ"> <Account Name="elitr" Value="33" Type="A" Rating="1,25"/> </Region> </Category> </Accounts> T:\ftemp>type mxps.xsl <?xml version="1.0" encoding="US-ASCII"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output indent="yes"/> <xsl:template match="Accounts"> <Accounts> <xsl:variable name="accounts" select="Account"/> <xsl:for-each select="$accounts"> <xsl:sort select="@Category"/> <xsl:if test="generate-id(.)= generate-id($accounts[@Category=current()/@Category][1])"> <Category name="{@Category}"> <xsl:variable name="categories" select="$accounts[@Category=current()/@Category]"/> <xsl:for-each select="$categories"> <xsl:sort select="@Region"/> <xsl:if test="generate-id(.)= generate-id($categories[@Region=current()/@Region][1])"> <Region name="{@Region}"> <xsl:for-each select="$categories[@Region=current()/@Region]"> <xsl:sort select="@Name"/> <Account> <xsl:copy-of select="@Name"/> <xsl:copy-of select="@Value"/> <xsl:copy-of select="@Type"/> <xsl:copy-of select="@Rating"/> </Account> </xsl:for-each> </Region> </xsl:if> </xsl:for-each> </Category> </xsl:if> </xsl:for-each> </Accounts> </xsl:template> </xsl:stylesheet> T:\ftemp>call xslt2 mxps.xml mxps2.xsl <?xml version="1.0" encoding="UTF-8"?> <Accounts> <Category name="001"> <Region name="AAA"> <Account Name="dolor" Value="123" Type="A" Rating="1,25"/> <Account Name="sit amet" Value="134" Type="A" Rating="1,25"/> </Region> <Region name="BBB"> <Account Name="ipsum" Value="34" Type="A" Rating="1,25"/> </Region> </Category> <Category name="002"> <Region name="AAA"> <Account Name="sadipscing" Value="84" Type="A" Rating="1,25"/> </Region> </Category> <Category name="003"> <Region name="ZZZ"> <Account Name="lorem" Value="75" Type="A" Rating="2.87"/> </Region> </Category> <Category name="004"> <Region name="BBB"> <Account Name="consetetur" Value="434" Type="A" Rating="1,25"/> </Region> <Region name="CCC"> <Account Name="aliquyam" Value="6" Type="A" Rating="1,25"/> </Region> </Category> <Category name="007"> <Region name="ZZZ"> <Account Name="elitr" Value="33" Type="A" Rating="1,25"/> </Region> </Category> </Accounts> T:\ftemp>type mxps2.xsl <?xml version="1.0" encoding="US-ASCII"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output indent="yes"/> <xsl:template match="Accounts"> <Accounts> <xsl:for-each-group select="Account" group-by="@Category"> <xsl:sort select="@Category"/> <Category name="{@Category}"> <xsl:for-each-group select="current-group()" group-by="@Region"> <xsl:sort select="@Region"/> <Region name="{@Region}"> <xsl:for-each select="current-group()"> <xsl:sort select="@Name"/> <Account> <xsl:copy-of select="@Name,@Value,@Type,@Rating"/> </Account> </xsl:for-each> </Region> </xsl:for-each-group> </Category> </xsl:for-each-group> </Accounts> </xsl:template> </xsl:stylesheet> T:\ftemp>rem Done!