2009-06-03 2 views
1

Я хочу применить таблицу стилей XSL, которая подсчитывает предыдущие уникальные узлы «ROLE» и выплескивает следующий формат вывода ROLE/@ name, 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

+0

Я опубликовал измененное решение. Проверьте это, я думаю, это то, что вы ищете. – Tomalak

ответ

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, вы имеете дело с в довольно плохой форме, если Спроси меня. По крайней мере, тот факт, что что-либо связанное с безопасностью выражение выражается «количеством предшествующих уникальных имен» вместо правильной структуры данных, заставляет меня почесывать голову. ;-) Есть ли шанс изменить вход?

+0

Это вариант ответа на вопрос предшественника: http://stackoverflow.com/questions/941662/xsl-counting-previous-unique-siblings/944544#944544. Более обширное объяснение там. – Tomalak

+0

Непосредственно я не могу изменить ввод или вывод. (Да, это некрасиво). Вход поступает из какой-то унаследованной системы, и вывод отправляется в систему с полки. XML на самом деле является шагом вперед по сравнению с выходом с разделителями TAB :) По крайней мере, я могу проверить форматы datalengths/character и т. Д. С данными XML, используя XSD, прежде чем я выгружаю его в файл TAB. Я не уверен, что рабочая форма узла ROLE будет делать трюк, но я дам вам знать. Еще раз спасибо – Jay

+0

Итак, чтобы повторить мой вопрос ... Вы действительно хотите, чтобы эти две сбалансированные или есть какая-то другая логика распределения ROLE-PERM? – Tomalak

Смежные вопросы