2010-10-12 2 views
-1

Okay ребята, я думаю, что это хитрый ...Как создать список HTML из плоского файла XML с помощью XSLT

Я ищу чистый способ сделать следующие действия с помощью XSLT:

Преобразовать эту источник:

<para>blah blah</para> 
<list>num1</list> 
<list>num2</list> 
<list>num3</list> 
<para>blah blah</para> 
<list>num1</list> 
<list>num2</list> 
<para>blah blah blah blah blah</para> 

К этому выходу:

<p>blah blah</p> 
<ol> 
<li>num1</li> 
<li>num2</li> 
<li>num3</li> 
</ol> 
<p>blah blah</p> 
<ol> 
<li>num1</li> 
<li>num2</li> 
</ol> 
<p>blah blah blah blah blah</p> 

Имейте в виду, я не знаю точно, как человек y <list> будет.

До сих пор у меня есть это:

<xsl:template match="para"> 
<p><xsl:value-of select="." /></p> 
</xsl:template> 

<xsl:template match="list"> 
<ol><li><xsl:value-of select="." /></li></ol> 
</xsl:template> 

Но мой результат выглядит следующим образом:

<p>blah blah</p>  
<ol><li>num1</li></ol> 
<ol><li>num2</li></ol> 
<ol><li>num3</li></ol> 
<p>blah blah</p> 
<ol><li>num1</li></ol> 
<ol><li>num2</li></ol> 
<p>blah blah blah blah blah</p> 

Я знаю, почему я получаю дублировать <ol> элементы, но я не знаю, как остановить его , Довольно мозговой тизер.

Любая помощь была бы принята с благодарностью.

+2

Многие, много дубликатов: http://stackoverflow.com/questions/3813978/wrap-certain-nodes-with-xsl http://stackoverflow.com/questions/3776789/using-xslt-to-interpret-flat-xml -into-nested-xhtml http://stackoverflow.com/questions/3831326/group-a-non-nested-xml-structure-to-a-xml-tree-structure http://stackoverflow.com/questions/3853452/группировка-similer-nodes – 2010-10-12 22:23:58

ответ

1

XSLT 2.0 имеет инструменты специально для этого вида операций:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="xml"> 
     <xsl:for-each-group select="*" group-adjacent="boolean(self::list)"> 
      <xsl:choose> 
       <xsl:when test="current-grouping-key()"> 
        <ol> 
         <xsl:apply-templates select="current-group()"/> 
        </ol> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:apply-templates select="current-group()"/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:for-each-group> 
    </xsl:template> 
    <xsl:template match="para"> 
     <p> 
      <xsl:apply-templates/> 
     </p> 
    </xsl:template> 
    <xsl:template match="list"> 
     <li> 
      <xsl:apply-templates/> 
     </li> 
    </xsl:template> 
</xsl:stylesheet> 

С этим XML:

<xml> 
    <para>blah blah</para> 
    <list>num1</list> 
    <list>num2</list> 
    <list>num3</list> 
    <para>blah blah</para> 
    <list>num1</list> 
    <list>num2</list> 
    <para>blah blah blah blah blah</para> 
</xml> 

вы получите желаемый выход:

<p>blah blah</p> 
<ol> 
    <li>num1</li> 
    <li>num2</li> 
    <li>num3</li> 
</ol> 
<p>blah blah</p> 
<ol> 
    <li>num1</li> 
    <li>num2</li> 
</ol> 
<p>blah blah blah blah blah</p> 

Вы должны читать по каждой группе по адресу http://www.w3.org/TR/xslt20/#xsl-for-each-group

+0

Спасибо! Это похоже на отличный способ сделать это. – joe

+0

+1 хороший ответ. Но я думаю, что использовать такие «шаблоны» шаблонов нехорошо. – 2010-10-13 14:30:27

0

Это преобразование:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:key name="kFollowing" match="list" 
    use="generate-id(preceding-sibling::para[1])"/> 

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

<xsl:template match="para"> 
    <p> 
    <xsl:apply-templates/> 
    </p> 
    <xsl:variable name="vFol" 
    select="key('kFollowing',generate-id())"/> 
    <xsl:if test="$vFol"> 
     <ol> 
     <xsl:apply-templates mode="copy" 
      select="key('kFollowing',generate-id())"/> 
     </ol> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="list" mode="copy"> 
    <li><xsl:value-of select="."/></li> 
</xsl:template> 
<xsl:template match="list"/> 
</xsl:stylesheet> 

при нанесении на следующий документ XML (оберточной предоставленный вход в один верхний элемент):

<t> 
    <para>blah blah</para> 
    <list>num1</list> 
    <list>num2</list> 
    <list>num3</list> 
    <para>blah blah</para> 
    <list>num1</list> 
    <list>num2</list> 
    <para>blah blah blah blah blah</para> 
</t> 

производит нужное, правильное:

<t> 
    <p>blah blah</p> 
    <ol> 
     <li>num1</li> 
     <li>num2</li> 
     <li>num3</li> 
    </ol> 
    <p>blah blah</p> 
    <ol> 
     <li>num1</li> 
     <li>num2</li> 
    </ol> 
    <p>blah blah blah blah blah</p> 
</t> 

UPDATE: ОП указал в комментарии, что теперь он хочет решение, в котором любой не- list элемент может разграничить группу смежных list братьев и сестер.

Вот решение измененному вопрос:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="kFollowing" match="list" 
    use="generate-id(preceding-sibling::*[not(self::list)][1])"/> 

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

<xsl:template match="*[not(self::list) and following-sibling::*[1][self::list]]"> 
    <xsl:call-template name="identity"/> 
    <xsl:variable name="vFol" 
    select="key('kFollowing',generate-id())"/> 
    <xsl:if test="$vFol"> 
     <ol> 
     <xsl:apply-templates mode="copy" 
      select="key('kFollowing',generate-id())"/> 
     </ol> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="list" mode="copy"> 
    <li><xsl:value-of select="."/></li> 
</xsl:template> 
<xsl:template match="list"/> 
</xsl:stylesheet> 

Когда это преобразование применяется на следующий документ XML (Обратите внимание, что разделительные элементы имеют в настоящее время случайные имена):

<t> 
    <bara>blah blah</bara> 
    <list>num1</list> 
    <list>num2</list> 
    <list>num3</list> 
    <vara>blah blah</vara> 
    <list>num1</list> 
    <list>num2</list> 
    <dara>blah blah blah blah blah</dara> 
</t> 

Требуется, правильный результат получается:

<t> 
    <bara>blah blah</bara> 
    <ol> 
     <li>num1</li> 
     <li>num2</li> 
     <li>num3</li> 
    </ol> 
    <vara>blah blah</vara> 
    <ol> 
     <li>num1</li> 
     <li>num2</li> 
    </ol> 
    <dara>blah blah blah blah blah</dara> 
</t> 
2

Этот XSLT 1.0 таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="node()"> 
     <xsl:apply-templates select="node()[1]|following-sibling::node()[1]"/> 
    </xsl:template> 
    <xsl:template match="para"> 
     <p> 
      <xsl:value-of select="."/> 
     </p> 
     <xsl:apply-templates select="following-sibling::node()[1]"/> 
    </xsl:template> 
    <xsl:template match="list[preceding-sibling::node()[1][not(self::list)]]"> 
     <ol> 
      <xsl:call-template name="makeList"/> 
     </ol> 
     <xsl:apply-templates select="following-sibling::node() 
               [not(self::list)][1]"/> 
    </xsl:template> 
    <xsl:template match="list" name="makeList"> 
     <li> 
      <xsl:value-of select="."/> 
     </li> 
     <xsl:apply-templates select="following-sibling::node()[1] 
               [self::list]"/> 
    </xsl:template> 
</xsl:stylesheet> 

Выход:

<p>blah blah</p> 
<ol> 
     <li>num1</li> 
     <li>num2</li> 
     <li>num3</li> 
</ol> 
<p>blah blah</p> 
<ol> 
     <li>num1</li> 
     <li>num2</li> 
</ol> 
<p>blah blah blah blah blah</p> 

Примечание: Мелкозернистая ВТП.

Редактировать: Компактный код.

+0

Спасибо за помощь, это возможный подход. Но трудно ли поддерживать этот подход? Потому что мне нужно будет добавить следующий сингл на каждый элемент верхнего уровня, в котором я совпадаю. – joe

+0

@joe: Эта таблица стилей имеет четыре правила: мелкозернистый обход по умолчанию, правило для 'p', правило для' ol' и правило для 'li'. Итак, это трансформация от одного к одному. Я не вижу проблемы * с трудом в обслуживании. Вы спросили Димитрия: * Что делать, если у меня есть элемент H1 перед списком *. Ну, вы должны объявить waht, чтобы сделать с «H1». Теперь это обходит. Итак, два решения: скопируйте все, что вы не хотите преобразовывать, или добавьте правило для 'H1'. – 2010-10-13 12:57:26

+0

Что я говорю, если я добавлю

. Мне придется поместить в совпадение. – joe