2012-08-24 20 views
1

我在这里看到过这个问题的一些变化,但我不确定如何将它们应用于我的情况,所以我希望也许有人能帮助我。使用属性作为关键字深化XSLT结构

我有一个格式与此类似一个扁平的XML文件:

<item id="1"/> 
<item id="1.1"/> 
<item id="1.1.1"/> 
<item id="1.1.2"/> 
<item id="1.1.2.1"/> 
<item id="1.2"/> 
<item id="1.3"/> 

我期待分层设置标签基于id属性,就像这样:

<item id="1"> 
    <item id="1.1"> 
    <item id="1.1.1"/> 
    <item id="1.1.2"> 
     <item id="1.1.2.1"/> 
    </item> 
    </item> 
    <item id="1.2"/> 
    <item id="1.3"/> 
</item> 

某些id值有两位数字(例如“1.2.3.15.1”),这使得比较它们更具挑战性。

帮助?

+0

你叫什么终止条件。你需要做的是,有一个函数,递归地调用它自己的值,如1,1.1,1.2,1.3 .. 1.nnn然后,为他们每个人再次调用1.1.1,1.1.2等。每个系列必须在您的预定义条件下结束。 –

+0

优化可以首先收集所有属性,按照您需要的顺序排列它们,然后只调用那些属性,因此您的终止不会被硬编码。 –

回答

3

选择正确的节点可能会非常棘手,但你有没有等级这个工程为您的样品输入(如果你添加一个根元素的话)

<!-- start somewhere --> 
    <xsl:template match="/root"> 
    <root> 
     <!-- select all with no . in the id --> 
     <xsl:apply-templates select="//item[string-length(translate(@id,'1234567890',''))=0]" /> 
    </root> 
    </xsl:template> 

    <xsl:template match="item"> 
    <xsl:variable name="id" select="@id"/> 
    <!-- how many . have we ? That is how deep we are and add 1 --> 
    <xsl:variable name="deep" select="string-length(translate(@id,'1234567890',''))+1" /> 
    <xsl:copy> 
     <!-- copy attribs over --> 
     <xsl:apply-templates select="@*"/> 
     <!-- select all nodes that start with our curent id, 
      select nodes that are just one level below us 
      and don't select our selfs--> 
     <xsl:apply-templates select="//item[starts-with(@id, $id) and string-length(translate(@id,'1234567890',''))=$deep and not(@id=$id)]"/> 
    </xsl:copy> 
    </xsl:template> 

    <!-- copy attribs --> 
    <xsl:template match="@*"> 
    <xsl:copy /> 
    </xsl:template> 
+0

谢谢。尽管有一个方面我必须纠正,但这一个做了诀窍。输入文件有一些带两位数字的ID(例如1.2.3.11),导致节点选择失败。我通过将ID格式化为两位数字(例如01.02.03.11)作为第一遍转换来解决此问题。 – NestorDRod

1

一,这是一个简单的XSLT 2.0解决方案(这一个后和类似的XSLT 1.0溶液如下):

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/*"> 
    <xsl:sequence select="my:grouping(*, 1)"/> 
</xsl:template> 

<xsl:function name="my:grouping" as="element()*"> 
    <xsl:param name="pNodes" as="element()*"/> 
    <xsl:param name="pLevel" as="xs:integer"/> 

    <xsl:if test="$pNodes"> 
     <xsl:for-each-group select="$pNodes" group-by="tokenize(@id, '\.')[$pLevel]"> 
     <xsl:copy> 
     <xsl:copy-of select="@*"/> 
     <xsl:sequence select=" 
      my:grouping(current-group()[tokenize(@id, '\.')[$pLevel+1]], $pLevel+1)"/> 
     </xsl:copy> 
    </xsl:for-each-group> 
    </xsl:if> 
</xsl:function> 
</xsl:stylesheet> 

当该变换被此XML文档(提供的XML片段,裹机智上施加欣单个顶部元件,使之成为良好的XML文档):

<t> 
    <item id="1"/> 
    <item id="1.1"/> 
    <item id="1.1.1"/> 
    <item id="1.1.2"/> 
    <item id="1.1.2.1"/> 
    <item id="1.2"/> 
    <item id="1.3"/> 
</t> 

有用,正确的结果产生

<item id="1"> 
    <item id="1.1"> 
     <item id="1.1.1"/> 
     <item id="1.1.2"> 
     <item id="1.1.2.1"/> 
     </item> 
    </item> 
    <item id="1.2"/> 
    <item id="1.3"/> 
</item> 

II。下面是一个类似的XSLT 1.0解决方案

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

<xsl:key name="kFollowing" match="item" 
    use="generate-id(preceding-sibling::* 
        [string-length(current()/@id) > string-length(@id) 
        and 
         starts-with(current()/@id, concat(@id, '.'))] 
         [1])"/> 

<xsl:template match="/*"> 
    <xsl:call-template name="grouping"> 
     <xsl:with-param name="pNodes" select="*"/> 
     <xsl:with-param name="pLevel" select="1"/> 
    </xsl:call-template> 
</xsl:template> 

<xsl:template name="grouping"> 
    <xsl:param name="pNodes"/> 
    <xsl:param name="pLevel" select="1"/> 

    <xsl:for-each select= 
    "$pNodes[$pLevel > string-length(@id) - string-length(translate(@id, '.', ''))]"> 
    <xsl:copy> 
    <xsl:copy-of select="@*"/> 

    <xsl:call-template name="grouping"> 
     <xsl:with-param name="pNodes" select="key('kFollowing', generate-id())"/> 
     <xsl:with-param name="pLevel" select="$pLevel+1"/> 
    </xsl:call-template> 
    </xsl:copy> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

当这个XSLT 1.0变换对同一文档(上图),同样的希望,正确的结果产生应用:

<item id="1"> 
    <item id="1.1"> 
     <item id="1.1.1"/> 
     <item id="1.1.2"> 
     <item id="1.1.2.1"/> 
     </item> 
    </item> 
    <item id="1.2"/> 
    <item id="1.3"/> 
</item> 
相关问题