2009-06-03 80 views
1

我想应用一个XSL样式表来计算以前的唯一“ROLE”节点,并将ROLE/@名称,PERM/@ perfrom的输出格式和当前节点之前的唯一ROLE节点。
这是从this question的延续,但复杂一点。我相信Muenchian方法是实现这个最好的方法,因为这个文件的长度会很大。XSL:从子节点计数以前的唯一兄弟姐妹

我有以下XML(关于长度抱歉)

<?xml version="1.0" encoding="utf-8" ?> 
<ROLEACTIONINFO> 
    <ROLE name="TESTER"> 
    <ACTIONINFO> 
     <PERMINFO> 
     <PERM type="PT0" field="ALL" permfrom="PERM1565"/> 
     </PERMINFO> 
    </ACTIONINFO> 
    </ROLE> 
    <ROLE name="PARENT1"> 
    <ACTIONINFO> 
    </ACTIONINFO> 
    </ROLE> 
    <ROLE name="PARENT1"> 
    <ACTIONINFO> 
     <PERMINFO> 
     <PERM type="PT8" field="ALL" permfrom="PERM1"/> 
     </PERMINFO> 
    </ACTIONINFO> 
    </ROLE> 
    <ROLE name="PARENT1"> 
    <ACTIONINFO> 
     <PERMINFO> 
     <PERM type="PT7" field="ALL" permfrom="PERM2"/> 
     <PERM type="PT7" field="ALL" permfrom="PERM54"/> 
     </PERMINFO> 
    </ACTIONINFO> 
    </ROLE> 
    <ROLE name="PARENT2"> 
    <ACTIONINFO> 
     <PERMINFO> 
     <PERM type="PT6" field="ALL" permfrom="PERM1"/> 
     </PERMINFO> 
    </ACTIONINFO> 
    </ROLE> 
    <ROLE name="PARENT2"> 
    <ACTIONINFO> 
     <PERMINFO> 
     <PERM type="PT5" field="ALL" permfrom="PERM2"/> 
     </PERMINFO> 
    </ACTIONINFO> 
    </ROLE> 
    <ROLE name="PARENT3"> 
    <ACTIONINFO> 
     <PERMINFO> 
     <PERM type="PT2" field="ALL" permfrom="PERM44"/> 
     </PERMINFO> 
    </ACTIONINFO> 
    </ROLE> 
</ROLEACTIONINFO> 

这里是一个版本XSL片我已经玩用:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:template match="text()"/> 

    <xsl:key name="kRole" match="ROLE[ACTIONINFO/PERMINFO/PERM]" use="@name" /> 

    <xsl:template match="PERM"> 
    <xsl:variable name="roles-so-far" select="ancestor::ROLE | ancestor::ROLE/preceding-sibling::ROLE[ACTIONINFO/PERMINFO/PERM]"/> 
    <!-- Only select the first instance of each ROLE name --> 
    <xsl:variable name="roles-so-far-unique"    
        select="$roles-so-far[generate-id(ancestor::ROLE) = generate-id(key('kRole',ancestor::ROLE/@name)[1])]"/> 
    <xsl:apply-templates select="ancestor::ROLE/@name"/> 
    <xsl:text>&#x9;</xsl:text> 
    <xsl:apply-templates select="@permfrom"/> 
    <xsl:text>&#x9;</xsl:text> 
    <xsl:value-of select="count($roles-so-far-unique)"/> 
    <!-- linefeed --> 
    <xsl:text>&#xA;</xsl:text> 
    </xsl:template> 

</xsl:stylesheet> 

这里是所期望的输出:

TESTER PERM1565 1 
PARENT1 PERM1 2 
PARENT1 PERM2 2 
PARENT1 PERM54 2 
PARENT2 PERM1 3 
PARENT2 PERM2 3 
PARENT3 PERM44 4 

下面是实际(不正确)输出:

TESTER PERM1565 1 
PARENT1 PERM1 2 
PARENT1 PERM2 3 
PARENT1 PERM54 3 
PARENT2 PERM1 4 
PARENT2 PERM2 5 
PARENT3 PERM44 6 

在此先感谢。

+0

你确定第三个“PARENT1”有两个,而第一个没有?男人,你从哪里得到这个输入数据...? :)无论如何,我现在会假设计数是平等的,你希望它们平衡。如果这是您的错字,我的解决方案将变得更简单。 – Tomalak 2009-06-03 19:12:58

+0

我发布了一个更改后的解决方案。检查出来,我想这就是你要找的。 – Tomalak 2009-06-04 10:19:56

回答

1

这正好从每一个<PERM>,服用根据<ROLE>和计数它独特的前辈:

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 

    <xsl:output method="text" /> 

    <xsl:variable name="TAB" select="'&#x09;'" /> 
    <xsl:variable name="LF" select="'&#x0A;'" /> 

    <xsl:key name="kRole" match="ROLE" use="@name" /> 

    <xsl:template match="/"> 
    <xsl:apply-templates select="//PERM" /> 
    </xsl:template> 

    <xsl:template match="PERM"> 
    <xsl:variable name="vThisRole" select="ancestor::ROLE[1]" /> 
    <xsl:variable name="vPrecedingRoles" select=" 
     ($vThisRole | $vThisRole/preceding-sibling::ROLE) 
    " /> 
    <xsl:variable name="vUniquePrecedingRoles" select=" 
     $vPrecedingRoles[count(. | key('kRole', ./@name)[1]) = 1] 
    " /> 
    <xsl:value-of select=" 
     concat(
     $vThisRole/@name, $TAB, 
     @permfrom, $TAB, 
     count($vUniquePrecedingRoles), $LF 
    ) 
    " /> 
    </xsl:template> 

</xsl:stylesheet> 

输出:

 
TESTER PERM1565  1 
PARENT1 PERM1 2 
PARENT1 PERM2 2 
PARENT1 PERM54 2 
PARENT2 PERM1 3 
PARENT2 PERM2 3 
PARENT3 PERM44 4 

你正在处理的XML是一个非常糟糕的形状,如果你问我。至少事实上,任何与安全有关的事物都是用“先前唯一名称的计数”来表示的,而不是一个正确的数据结构,这让我挠了挠头。 ;-)你有可能改变输入吗?