2016-10-26 1 views
1

Я пытаюсь переструктурировать xml-данные в группы и подгруппы. Я смог заставить его работать, но мой код должен включать что-то, что выглядит (по крайней мере, для меня) как обходной путь. Вот мои файлы примеров:xslt gmuenchian grouping с подгруппами

data.xml:

<data> 
    <record Group="g1" SubGroup="sg1">Record 1</record> 
    <record Group="g2" SubGroup="sg1">Record 2</record> 
    <record Group="g1" SubGroup="sg1">Record 3</record> 
    <record Group="g2" SubGroup="sg1">Record 4</record> 
    <record Group="g2" SubGroup="sg2">Record 5</record> 
    <record Group="g1" SubGroup="sg2">Record 6</record> 
</data> 

Stylesheet.xsl:

<?xml version="1.0" encoding="UTF-8"?> 

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

    <xsl:output method="xml" version="1.0" indent="yes" encoding="UTF-8"/> 

    <xsl:key name="Group" match="record" use="@Group" /> 
    <xsl:key name="SubGroup" match="record" use="@SubGroup" /> 

    <xsl:template match="/data"> 
     <xsl:variable name="Records" select="record"/> 

     <data> 
      <xsl:for-each select="$Records[generate-id(.)=generate-id(key('Group',@Group)[1])]"> 
       <xsl:sort select="@Group"/> 
       <xsl:variable name="Group" select="@Group"/> 

       <xsl:call-template name="Group"> 
        <xsl:with-param name="Records" select="$Records[@Group = $Group]"/> 
        <xsl:with-param name="Group" select="$Group"/> 
       </xsl:call-template> 
      </xsl:for-each> 
     </data> 
    </xsl:template> 

    <xsl:template name="Group"> 
     <xsl:param name="Records"/> 
     <xsl:param name="Group"/> 

     <group name="{$Group}"> 
      <xsl:for-each select="$Records[generate-id(.)=generate-id(key('SubGroup',@SubGroup)[1])]"> 
<!-- this works: <xsl:for-each select="$Records[generate-id(.)=generate-id(key('SubGroup',@SubGroup)[@Group = $Group][1])]"> --> 
       <xsl:sort select="@SubGroup"/> 
       <xsl:variable name="SubGroup" select="@SubGroup"/> 

       <xsl:call-template name="SubGroup"> 
        <xsl:with-param name="Records" select="$Records[@SubGroup = $SubGroup]"/> 
        <xsl:with-param name="Group" select="$Group"/> 
        <xsl:with-param name="SubGroup" select="$SubGroup"/> 
       </xsl:call-template> 
      </xsl:for-each> 
     </group> 
    </xsl:template> 

    <xsl:template name="SubGroup"> 
     <xsl:param name="Records"/> 
     <xsl:param name="Group"/> 
     <xsl:param name="SubGroup"/> 

     <subgroup name="{$SubGroup}"> 
      <xsl:for-each select="$Records"> 
       <xsl:copy-of select="."/> 
      </xsl:for-each> 
     </subgroup> 
    </xsl:template> 

</xsl:stylesheet> 

Это выход генерируется:

<?xml version="1.0" encoding="UTF-8"?> 
<data> 
    <group name="g1"> 
    <subgroup name="sg1"> 
     <record Group="g1" SubGroup="sg1">Record 1</record> 
     <record Group="g1" SubGroup="sg1">Record 3</record> 
    </subgroup> 
    </group> 
    <group name="g2"> 
    <subgroup name="sg2"> 
     <record Group="g2" SubGroup="sg2">Record 5</record> 
    </subgroup> 
    </group> 
</data> 

, но это выход , Я хочу иметь:

<?xml version="1.0" encoding="UTF-8"?> 
<data> 
    <group name="g1"> 
    <subgroup name="sg1"> 
     <record Group="g1" SubGroup="sg1">Record 1</record> 
     <record Group="g1" SubGroup="sg1">Record 3</record> 
    </subgroup> 
    <subgroup name="sg2"> 
     <record Group="g1" SubGroup="sg2">Record 6</record> 
    </subgroup> 
    </group> 
    <group name="g2"> 
    <subgroup name="sg1"> 
     <record Group="g2" SubGroup="sg1">Record 2</record> 
     <record Group="g2" SubGroup="sg1">Record 4</record> 
    </subgroup> 
    <subgroup name="sg2"> 
     <record Group="g2" SubGroup="sg2">Record 5</record> 
    </subgroup> 
    </group> 
</data> 

Проблема заключается в каждом цикле в tempalte с именем «Группа». Кажется, что функция key() не работает с узлами, содержащимися в $ Records, но и во всем входном XML-файле.

Я получаю идентичные результаты с помощью xsltproc и с саксоном, поэтому я не думаю, что это ошибка в моем процессоре xslt. Кажется, что я не совсем понял, как работает key().

Если я добавлю дополнительный селектор [@Group = $Group] в вывод key(), я получу ожидаемый результат.

Может кто-нибудь объяснить, что происходит и почему нужен дополнительный селектор [@Group = $Group].

Марио

+0

Тот же вопрос решается здесь: http://stackoverflow.com/questions/39793149/xslt-template-doesnt-apply-on-direct-child-nodes/39793718 – uL1

ответ

1

Если вы хотите сделать суб-группировку, вам нужно использовать каскадный ключ как основной группы и подгрупп

<xsl:key name="SubGroup" match="record" use="concat(@Group,'|', @SubGroup)" /> 

Тогда просто использовать его в том же как и раньше, с конкатенацией

<xsl:for-each select="$Records[generate-id(.)=generate-id(key('SubGroup',concat(@Group,'|', @SubGroup))[1])]"> 

Попробуйте XSLT (который я также упрощенный использовать ключ при вызове ваших именованных шаблонов с записями)

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

    <xsl:output method="xml" version="1.0" indent="yes" encoding="UTF-8"/> 

    <xsl:key name="Group" match="record" use="@Group" /> 
    <xsl:key name="SubGroup" match="record" use="concat(@Group,'|', @SubGroup)" /> 

    <xsl:template match="/data"> 
     <data> 
      <xsl:for-each select="record[generate-id(.)=generate-id(key('Group',@Group)[1])]"> 
       <xsl:sort select="@Group"/> 

       <xsl:call-template name="Group"> 
        <xsl:with-param name="Records" select="key('Group',@Group)"/> 
       </xsl:call-template> 
      </xsl:for-each> 
     </data> 
    </xsl:template> 

    <xsl:template name="Group"> 
     <xsl:param name="Records"/> 

     <group name="{@Group}"> 
      <xsl:for-each select="$Records[generate-id(.)=generate-id(key('SubGroup',concat(@Group,'|', @SubGroup))[1])]"> 
       <xsl:sort select="@SubGroup"/> 

       <xsl:call-template name="SubGroup"> 
        <xsl:with-param name="Records" select="key('SubGroup',concat(@Group,'|', @SubGroup))"/> 
       </xsl:call-template> 
      </xsl:for-each> 
     </group> 
    </xsl:template> 

    <xsl:template name="SubGroup"> 
     <xsl:param name="Records"/> 
     <subgroup name="{@SubGroup}"> 
      <xsl:for-each select="$Records"> 
       <xsl:copy-of select="."/> 
      </xsl:for-each> 
     </subgroup> 
    </xsl:template> 

</xsl:stylesheet> 
+0

Большое спасибо за ваш ответ. Ваше использование клавиш и concat() и key() для выбора параметра действительно круто. Но я все еще не понимаю, почему я должен учитывать @Group во внутреннем цикле, поскольку '$ Records' уже был сокращен, чтобы включать только записи текущей группы. –

+0

@MarioKlebsch Поскольку, как вы правильно поняли, клавиши (в XSLT 1.0) работают по всему документу. –

+0

@ michael.hor257k Как вы сказали, я подвел итоги правильно, но до сих пор я не знал об этом. Большое спасибо. –

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