2015-09-22 7 views
1

У меня есть XML, как следует,XSLT - Группировка, анализируя значения атрибутов

<doc> 
    <section> 
     <p id="main">aa</p> 
     <p id="main">bb</p> 
     <p id="main">cc</p> 
     <p id="para1">dd</p> 
     <p id="st_main">ee</p> 
     <p id="st_chap">ff</p> 
     <p id="st_chap">gg</p> 
     <p id="st_main">hh</p> 
     <p id="main">ii</p> 
     <p id="main">cc</p> 
     <p id="para2">xx</p> 
     <p id="main">yy</p> 
     <p id="main">cc</p> 
    </section> 
</doc> 

Мои требования

1) группировка <p> по атрибуту пара и добавить отдельный раздел для каждой <p> группы.

2) определить <p> группы узлов, которые идентификатор атрибута, начиная с st поместить <st_start> и <st_end> в начале и конце на группе

SO мой желаемый результат есть,

<doc> 
    <section> 
     <p id="main">aa</p> 
     <p id="main">bb</p> 
     <p id="main">cc</p> 
    </section> 
    <section type="para1"> 
     <p id="para1">dd</p> 
     <ss_start/> 
     <p id="st_main">ee</p> 
     <p id="st_chap">ff</p> 
     <p id="st_chap">gg</p> 
     <p id="st_main">hh</p> 
     <ss_end/> 
     <p id="main">ii</p> 
     <p id="main">cc</p> 
    </section> 
    <section type="para2"> 
     <p id="para2">xx</p> 
     <p id="main">yy</p> 
     <p id="main">cc</p> 
    </section> 
</doc> 

Мой XSL для достижения эта задача следующая,

<xsl:template match="section"> 
     <xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]"> 
      <section> 
       <xsl:if test="current-group()[1][not(@id='main')]"> 
        <xsl:attribute name="type" select="current-group()[1]/@id"/> 
       </xsl:if> 
       <xsl:for-each-group select="current-group()" group-adjacent="@id"> 
        <xsl:if test="starts-with(current-grouping-key(),'st')"> 
         <ss_start/> 
        </xsl:if>    
        <xsl:apply-templates select="current-group()"/> 
        <xsl:if test="starts-with(current-grouping-key(),'st')"> 
         <ss_end/> 
        </xsl:if> 
       </xsl:for-each-group> 
      </section> 
     </xsl:for-each-group> 
    </xsl:template> 

Этот xsl дает мне следующий результат,

<doc> 
    <section> 
     <p id="main">aa</p> 
     <p id="main">bb</p> 
     <p id="main">cc</p> 
    </section> 
    <section type="para1"> 
     <p id="para1">dd</p> 
     <ss_start/> 
     <p id="st_main">ee</p> 
     <ss_end/> 
     <ss_start/> 
     <p id="st_chap">ff</p> 
     <p id="st_chap">gg</p> 
     <ss_end/> 
     <ss_start/> 
     <p id="st_main">hh</p> 
     <ss_end/> 
     <p id="main">ii</p> 
     <p id="main">cc</p> 
    </section> 
    <section type="para2"> 
     <p id="para2">xx</p> 
     <p id="main">yy</p> 
     <p id="main">cc</p> 
    </section> 
</doc> 

Как вы можете видеть, что это добавляет <ss_start/> и <ss_end/> отдельно для <p id="st_main"> и <p id="st_chap">. но мне нужно идентифицировать последовательные элементы <p>, которые имеют attr id, начиная с st и охватывают эти узлы на <ss_start/> и <ss_end/>.

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

ответ

2

Если вы просто используете

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 

<xsl:output indent="yes"/> 

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

<xsl:template match="section"> 
     <xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]"> 
      <section> 
       <xsl:if test="current-group()[1][not(@id='main')]"> 
        <xsl:attribute name="type" select="current-group()[1]/@id"/> 
       </xsl:if> 
       <xsl:for-each-group select="current-group()" group-adjacent="starts-with(@id, 'st_')"> 
        <xsl:if test="current-grouping-key()"> 
         <ss_start/> 
        </xsl:if>    
        <xsl:apply-templates select="current-group()"/> 
        <xsl:if test="current-grouping-key()"> 
         <ss_end/> 
        </xsl:if> 
       </xsl:for-each-group> 
      </section> 
     </xsl:for-each-group> 
</xsl:template> 

</xsl:stylesheet> 

, то вы получите выходной сигнал

<doc> 
    <section> 
     <p id="main">aa</p> 
     <p id="main">bb</p> 
     <p id="main">cc</p> 
    </section> 
    <section type="para1"> 
     <p id="para1">dd</p> 
     <ss_start/> 
     <p id="st_main">ee</p> 
     <p id="st_chap">ff</p> 
     <p id="st_chap">gg</p> 
     <p id="st_main">hh</p> 
     <ss_end/> 
     <p id="main">ii</p> 
     <p id="main">cc</p> 
    </section> 
    <section type="para2"> 
     <p id="para2">xx</p> 
     <p id="main">yy</p> 
     <p id="main">cc</p> 
    </section> 
</doc> 
2

Это, вероятно, ваше простое решение ...

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

<xsl:output indent="yes" encoding="utf-8" omit-xml-declaration="yes" /> 
<xsl:strip-space elements="*" /> 

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

<xsl:template match="section"> 
    <xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]"> 
    <section> 
     <xsl:apply-templates select="current-group()[1]/@id" mode="section-type" /> 
     <xsl:apply-templates select="current-group()" /> 
    </section> 
    </xsl:for-each-group> 
</xsl:template> 

<xsl:template match="@id[starts-with(., 'para')]" mode="section-type"> 
    <xsl:attribute name="type" select="." /> 
</xsl:template> 

<xsl:template match="@*" mode="section-type" /> 

<xsl:template match="p[starts-with(@id, 'st')] 
         [not(starts-with(preceding-sibling::p[1]/@id, 'st'))]"> 
    <ss_start /> 
    <xsl:next-match /> 
</xsl:template> 

<xsl:template match="p[starts-with(@id, 'st')] 
         [not(starts-with(following-sibling::p[1]/@id, 'st'))]"> 
    <xsl:next-match /> 
    <ss_end/> 
</xsl:template> 

</xsl:stylesheet> 
Смежные вопросы