2015-01-15 78 views
0

我有一个像下面XSLT gouping问题

<XYZ> 
<Name>abc</Name> 
<Year>1984</Year> 
<Model>qwe</Model> 
<Name>abc</Name> 
<Year>1987</Year> 
<Model>qwe</Model> 
<Name>qweqr</Name> 
<Year>1977</Year> 
<Model>tryet</Model> 
</XYZ> 

需要被转化为 <XYZ> <Name>abc</Name> <Year>1984</Year> <Year>1987</Year> <Model>qwe</Model> <Name>qweqr</Name> <Year>1977</Year> <Model>tryet</Model> </XYZ>

这里名称可以被视为关键

+0

XSLT的哪个版本? –

+0

你想如何输出模型?你甚至想要模型分组? –

+0

@ user2317758如果有帮助,请考虑通过选中答案接受答案。 –

回答

0

使用XSLT 1.0,这是可以做到的XML使用Muenchian分组和以下XSLT:

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" /> 
<xsl:strip-space elements="*"/> 
<xsl:key name="names" match="Name" use="text()"/> 
<xsl:key name="models" match="Model" use="text()"/> 
    <xsl:template match="XYZ"> 
    <XYZ> 
    <xsl:for-each select="//Name[generate-id()=generate-id(key('names',text())[1])]"> 
     <xsl:variable name="current" select="."/> 
     <xsl:apply-templates select="."/> 
     <xsl:apply-templates select="//Name[.=$current]/following-sibling::Year[1]"/> 
     <xsl:for-each select="//Name[.=$current]/following-sibling::Model[1] 
          [generate-id()=generate-id(key('models',text())[1])]"> 
     <xsl:apply-templates select="."/> 
     </xsl:for-each> 
     </xsl:for-each> 
    </XYZ> 
    </xsl:template> 
    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 
</xsl:transform> 

结果:

<XYZ> 
<Name>abc</Name> 
<Year>1984</Year> 
<Year>1987</Year> 
<Model>qwe</Model> 
<Name>qweqr</Name> 
<Year>1977</Year> 
<Model>tryet</Model> 
</XYZ> 

YearModel重复的节点被移除,因为只有唯一值在xsl:for-each选自:

<xsl:for-each select="//Name[generate-id()=generate-id(key('names',text())[1])]"> 

独特Name被复制,然后所有具有年在前Name与目前唯一的值Name

<xsl:apply-templates select="//Name[.=$current]/following-sibling::Year[1]"/> 

然后,对应的唯一Model节点被复制与第二xsl:for-each只选择唯一以下Model节点:

<xsl:for-each select="//Name[.=$current]/following-sibling::Model[1] 
         [generate-id()=generate-id(key('models',text())[1])]"> 

由于有#2已经有很多答案为XSLT使用Muenchian法分组,我只是建议的详细解释在Jeni Tennison的文章http://www.jenitennison.com/xslt/grouping/muenchian.xml中。对于XSLT分组可以看看http://www.dpawson.co.uk/xsl/sect2/N4486.html

更新

作为附加参考:作为建议的评论,这不会在不同name值重复model值的情况下工作。继调整XSLT

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8 indent="yes" /> 
<xsl:strip-space elements="*"/> 
<xsl:key name="names" match="Name" use="text()"/> 
    <xsl:template match="XYZ"> 
    <XYZ> 
     <xsl:for-each select="//Name[generate-id()=generate-id(key('names',text())[1])]"> 
     <xsl:variable name="current" select="."/> 
     <xsl:apply-templates select="."/> 
     <xsl:apply-templates select="//Name[.=$current]/following-sibling::Year[1]"/> 
     <xsl:for-each select="//Name[.=$current]/following-sibling::Model[1] 
           [not(.= preceding-sibling::Name[.=$current] 
           /preceding-sibling::Name[.=$current] 
           /following-sibling::Model)]"> 
      <xsl:apply-templates select="."/> 
     </xsl:for-each> 
     </xsl:for-each> 
    </XYZ> 
    </xsl:template> 
    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 
</xsl:transform> 

作品在OP提供以及示例XML示例XML中的注释建议 - 只可选多岁,独特model值唯一name值的name,但同样model可以也被列为不同的name

+0

我不认为这个代码适用于所有场景,因为'Model'上的分组是在文档中所有具有相同值的'Model'上完成的。试试这个XML输入:' \t ABC \t \t QWE \t qweqr \t 1977年 \t QWE ' –

+0

@LingamurthyCS谢谢您考虑这一点。只需在第二个版本中进行调整,以便为不同的“名称”值重复使用“模型”值。但是我不得不承认,如果OP会提及哪些值可能有重复,那么OP会更容易,因为OP中提供的示例并不十分清楚。 –

+0

是的,我同意你的看法。感觉你的方式有点微妙。我已经发布了我的尝试.. –

0

我认为你可以使用这个样式表,它使用键选择YearModel(组模型也根据自己的名称,然后用他们的价值),根据他们的前面Name(后分组名称):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output method="xml" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="Name" match="Name" use="."/> 
<xsl:key name="Year" match="Year" use="preceding::Name[1]"/> 
<xsl:key name="Model" match="Model" use="preceding::Name[1]"/> 

<xsl:template match="XYZ"> 
    <xsl:copy> 
     <xsl:for-each select="Name[count(. | key('Name', .)[1]) = 1]"> 
      <xsl:copy-of select="."/> 
      <xsl:copy-of select="key('Year', .)"/> 
      <xsl:copy-of select="key('Model', .)[not(. = preceding::Model[preceding::Name[1] = current()])]"/> 
     </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet>