2014-12-04 4 views
0

ввода:Группировка сгруппированных данных

<persons> 
    <person name="John" role="Writer"/> 
    <person name="John" role="Poet"/> 
    <person name="Jacob" role="Writer"/> 
    <person name="Jacob" role="Poet"/> 
    <person name="Joe" role="Poet"/> 
</persons> 

Ожидаемый результат:

<groups> 
    <group roles="Wriet, Poet" persons="John, Jacob"/> 
    <group roles="Poet" persons="Joe"/> 
</groups> 

Как и в приведенном выше примере, я в первую очередь необходимо сгруппировать по именам человека и найти роли каждого. Если у нескольких человек есть один и тот же набор ролей (например, как Джон, так и Джейкоб являются писателями и поэтами), мне нужно сгруппировать по каждому набору ролей и перечислить имена людей.

я могу сделать это для первого уровня группировки с использованием метода Muenchian или EXSLT set:distinct т.д.

<groups> 
    <group roles="Wriet, Poet" persons="John"/> 
    <group roles="Wriet, Poet" persons="Jacob"/> 
    <group roles="Poet" persons="Joe"/> 
</groups> 

Выше был преобразован с помощью XSLT 1.0 и EXSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sets="http://exslt.org/sets" extension-element-prefixes="sets"> 
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/> 
    <xsl:key name="persons-by-name" match="person" use="@name"/> 
    <xsl:template match="persons"> 
     <groups> 
      <xsl:for-each select="sets:distinct(person/@name)"> 
       <group> 
        <xsl:attribute name="persons"><xsl:value-of select="."/></xsl:attribute> 
        <xsl:attribute name="roles"> 
         <xsl:for-each select="key('persons-by-name', .)"> 
          <xsl:value-of select="@role"/> 
          <xsl:if test="position()!=last()"><xsl:text>, </xsl:text></xsl:if> 
         </xsl:for-each> 
        </xsl:attribute> 
       </group> 
      </xsl:for-each> 
     </groups> 
    </xsl:template> 
</xsl:stylesheet> 

Тем не менее, мне нужно помогите понять, как группироваться по сгруппированным ролям.

Если решение XSLT 1.0 недоступно, вы можете рекомендовать подход XSLT 2.0.

+1

Можете ли вы показать XSLT вы в настоящее время используете, чтобы получить свой текущий результат? Благодаря! –

+0

@TimC Конечно, добавлена ​​версия EXSLT в моем вопросе. – Somu

ответ

1

Попробуйте это так?

XSLT 1,0
(используя EXSLT набор узлов() и различные() функции)

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:exsl="http://exslt.org/common" 
xmlns:set="http://exslt.org/sets" 
extension-element-prefixes="exsl set"> 
<xsl:output method="xml" encoding="UTF-8" indent="yes" /> 

<xsl:key name="person-by-name" match="person" use="@name" /> 
<xsl:key name="person-by-roles" match="person" use="@roles" /> 

<xsl:variable name="distinct-persons"> 
    <xsl:for-each select="set:distinct(/persons/person/@name)"> 
     <person name="{.}"> 
      <xsl:attribute name="roles"> 
       <xsl:for-each select="key('person-by-name', .)/@role"> 
        <xsl:sort/> 
        <xsl:value-of select="." /> 
        <xsl:if test="position()!=last()"> 
         <xsl:text>, </xsl:text> 
        </xsl:if> 
       </xsl:for-each> 
      </xsl:attribute> 
     </person> 
    </xsl:for-each> 
</xsl:variable> 

<xsl:template match="/"> 
    <groups> 
     <xsl:for-each select="set:distinct(exsl:node-set($distinct-persons)/person/@roles)"> 
      <group roles="{.}"> 
       <xsl:attribute name="names"> 
        <xsl:for-each select="key('person-by-roles', .)/@name"> 
         <xsl:value-of select="." /> 
         <xsl:if test="position()!=last()"> 
          <xsl:text>, </xsl:text> 
         </xsl:if> 
        </xsl:for-each> 
       </xsl:attribute> 
      </group> 
     </xsl:for-each> 
    </groups> 
</xsl:template> 


</xsl:stylesheet> 

Результат:

<?xml version="1.0" encoding="UTF-8"?> 
<groups> 
    <group roles="Poet, Writer" names="John, Jacob"/> 
    <group roles="Poet" names="Joe"/> 
</groups> 
+0

Очень хорошо работает с 'xalan-j 2.7.2. Интерпретирующий процессор, но не с процессором XSLTC. Также не работает с процессором xalan по умолчанию с Java 1.7.0_71 или 1.8.0_25. – Somu

+0

Это не удивительно. –

1

Я сделал то же самое, что и вы, а затем сделал шаг дальше и снова сгруппировался. Теперь я получаю следующий вывод с входом:

<?xml version="1.0" encoding="UTF-8"?> 
<groups> 
    <group roles="Writer,Poet" persons="John,Jacob"/> 
    <group roles="Poet" persons="Joe"/> 
</groups> 

Это XSLT 2,0

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns="" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:avintis="http://www.avintis.com/esb" exclude-result-prefixes="#all" version="2.0"> 
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/> 

    <xsl:template match="/persons"> 
     <groups> 
      <xsl:variable name="persons" select="."/> 

      <!-- create a temporary variable containing all roles of a person --> 
      <xsl:variable name="roles"> 
       <xsl:for-each select="distinct-values(person/@name)"> 
        <xsl:sort select="."/> 
        <xsl:variable name="name" select="."/> 
        <xsl:element name="group"> 
         <xsl:attribute name="roles"> 
          <!-- sort the roles of each person --> 
          <xsl:variable name="rolesSorted"> 
           <xsl:for-each select="$persons/person[@name=$name]"> 
            <xsl:sort select="@role"/> 
            <xsl:copy-of select="."/> 
           </xsl:for-each> 
          </xsl:variable> 
          <xsl:value-of select="string-join($rolesSorted/person/@role,',')"/> 
         </xsl:attribute> 
         <xsl:attribute name="persons" select="."/> 
        </xsl:element> 
       </xsl:for-each> 
      </xsl:variable> 

      <!-- now loop again over all roles of the persons and group persons having the same roles --> 
      <xsl:for-each select="distinct-values($roles/group/@roles)"> 
       <xsl:element name="group"> 
        <xsl:variable name="name" select="."/> 
        <xsl:attribute name="roles" select="$name"/> 
        <xsl:attribute name="persons"> 
         <xsl:value-of select="string-join($roles/group[@roles=$name]/@persons,',')"/> 
        </xsl:attribute> 
       </xsl:element> 
      </xsl:for-each> 
     </groups> 
    </xsl:template> 

    <xsl:template match="*|text()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="*|text()|@*"/> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

Роли получают также сортируются - так независимо от порядка ввода ролей и лиц.

+1

Красивые. Получение результата первой группировки в переменную помещает меня на правильный путь. Благодаря! Я, однако, принимаю ответ @ michael.hor257k, когда он дал решение XSLT 1.0. – Somu