2017-04-24 15 views
0

我已经问过这个问题,并且我带了一个错误的示例列表,导致了无用的答案。然后我认为我已经找到了解决方案,但它导致了错误的结果。所以让我再问一次。排序列表,并用xslt清除XML文件中的重复项NEW

开始XML是一个列表至极包含其中有包含不同不同属性不同元素很多出现次数。 实施例XML:

<attributes> 
     <para role="tocmain1"/> 
     <para role="tocmain1"/> 
     <other style="fix"/> 
     <other style="fix1"/> 
     <para role="tocmain2"/> 
     <para role="tocmain2"/> 
     <para role="tocmain2"/> 
     <para role="tocmain3"/> 
     <para role="tocmain3"/> 
     <para language="de"/> 
     <para language="de"/> 
     <para role="tocmain3"/> 
</attributes> 

结果应该是只包含一个发生每个音素+属性+值组合并应在按字母顺序的顺序进行排序的列表:1.元素的字母顺序,2。字母顺序的属性,3.字母顺序的值。

实施例的结果:

<attributes> 
    <other style="fix"/> 
    <other style="fix1"/> 
    <para language="de"/> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/>  
</attributes> 

现在,我使用被连续地执行的两个XLST和问题是,所得到的列表是不完全的:元件+属性+值的一些组合被丢失。问题位于第一个模板中,因为我按属性值进行了分组,并且仅采用第一个事件。可能是相同的属性值与不同的属性一起使用。在这些情况下,第二次发生是缺失的。任何基于属性+值组合的可能性?

1. XSLT(分组和消除重复项):

<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:apply-templates select="@*"/>   
     <xsl:for-each-group select="*" group-by="@*"> 
     <xsl:sort select="@*"/> 
     <xsl:apply-templates select="current-group()[1]"/>   
     </xsl:for-each-group>      
    </xsl:copy> 
    </xsl:template>  
</xsl:stylesheet> 

2. XSLT(按字母顺序排序):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="/"> 
     <attributes> 
      <xsl:for-each select="attributes/node()">     
       <xsl:sort select="name()" order="ascending"/> 
       <xsl:sort select="name(@*)" order="ascending"/>     
       <xsl:sort select="@*" order="ascending"/>     
       <xsl:copy-of select="."/>     
      </xsl:for-each> 
     </attributes> 
    </xsl:template>   
</xsl:stylesheet> 

任何帮助是非常欢迎,并在第一个误导性的问题,对不起尝试!

+0

我不得不添加我的xslt片段作为图像,因为每一次尝试格式化他们,stackoverflow将接受并显示它们失败:( – rena

+0

您准确使用哪个XSLT处理器? –

+0

格式使用方法http://stackoverflow.com/问题/ 10412776/display-xslt-with-xslt – ThomasRS

回答

1

假设XSLT 3.0由撒克逊9.7 PE或EE或AltovaXML 2017所支持的可以简单地使用复合键:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:math="http://www.w3.org/2005/xpath-functions/math" 
    exclude-result-prefixes="xs math" 
    version="3.0"> 

    <xsl:output indent="yes"/> 

    <xsl:template match="/*"> 
     <xsl:copy> 
      <xsl:for-each-group select="*" group-by="node-name(), node-name(@*[1]), @*[1]" composite="yes"> 
       <xsl:sort select="string(current-grouping-key()[1])"/> 
       <xsl:sort select="string(current-grouping-key()[2])"/> 
       <xsl:copy-of select="."/> 
      </xsl:for-each-group> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

随着XSLT 2.0可使用嵌套for-each-group小号

<xsl:template match="/*"> 
    <xsl:copy> 
     <xsl:for-each-group select="*" group-by="node-name(.)"> 
      <xsl:sort select="string(current-grouping-key())"/> 
      <xsl:for-each-group select="current-group()" group-by="node-name(@*[1])"> 
       <xsl:sort select="string(current-grouping-key())"/>     
       <xsl:for-each-group select="current-group()" group-by="@*[1]"> 
        <xsl:copy-of select="."/> 
       </xsl:for-each-group> 
      </xsl:for-each-group> 
     </xsl:for-each-group> 
    </xsl:copy> 
</xsl:template> 

或使用例如使用字符串连接创建的组合键group-by="concat(node-name(), '|', node-name(@*[1]), '|', @*[1])"

这些建议假定元素可以有不同的属性,但每个元素只有一个属性。

+0

非常感谢Martin Honnen!您的解决方案完美工作(我使用了xslt 2.0版本)。顺便说一下,在我预先生成的列表中,每个元素只有一个属性,但在原始xml中,一个元素可以具有多个属性。 – rena