конвертировать xhtml в синтаксис вики используя xslt - PullRequest
3 голосов
/ 22 января 2009

Я хотел бы конвертировать xhtml в синтаксис dokuwiki, используя xslt .

Теперь, одна вещь, которую я не могу обдумать, это то, как обрабатывать вложенные списки. в синтаксисе докувики используется звездочка (*) для элемента списка, к которому добавляются два пробела на уровне вложения (см. синтаксис вики ).

мой вопрос: в следующем примере, как может , который соответствует списку item 2.1.1 знать о том, что это уровень вложенности , чтобы добавить нужное количество пробелов?

* list item 1
* list item 2
  * list item 2.1
    * list item 2.1.1
  * list item 2.2
  * list item 2.3
* list item 3

соответствует

  • элемент списка 1
  • элемент списка 2
    • элемент списка 2.1
      • элемент списка 2.1.1
    • элемент списка 2.2
    • элемент списка 2.3
  • элемент списка 3

, как показано следующее html:

<ul>
    <li>
        list item 1
    </li>
    <li>
        list item 2
        <ul>
            <li>
                list item 2.1
                <ul>
                    <li>list item 2.1.1</li>
                </ul>
            </li>
            <li>list item 2.2</li>
            <li>list item 2.3</li>
        </ul>
    </li>
    <li>
        list item 3
    </li>
</ul>

Ответы [ 2 ]

5 голосов
/ 23 января 2009

Следующее преобразование :

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

 <xsl:strip-space elements="*"/>

 <xsl:variable name="vBlanks"
  select="'                                        '"/>
 <xsl:variable name="vnNestSpaces" select="2"/>


    <xsl:template match="li">
      <xsl:variable name="vNestLevel"
           select="count(ancestor::li)"/>
      <xsl:value-of select=
       "concat('&#xA;',
               substring($vBlanks,1,$vnNestSpaces*$vNestLevel),
               '*  ', normalize-space(text()[1])
               )"/>
      <xsl:apply-templates select="*"/>
    </xsl:template>
</xsl:stylesheet>

при применении к исходному документу XML :

<ul>
    <li> list item 1
    </li>
    <li> list item 2        
        <ul>
            <li> list item 2.1                
                <ul>
                    <li>list item 2.1.1</li>
                </ul>
            </li>
            <li>list item 2.2</li>
            <li>list item 2.3</li>
        </ul>
    </li>
    <li> list item 3    </li>
</ul>

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

*  list item 1
*  list item 2
  *  list item 2.1
    *  list item 2.1.1
  *  list item 2.2
  *  list item 2.3
*  list item 3

Обратите внимание на следующее :

  1. Требуемый отступ определяется значением count(ancesstor::li).

  2. Пространство для отступа берется непосредственно из достаточно большой пустой строки (содержит достаточно пробелов для 20 уровней вложенности). нет необходимости рекурсивно выводить пробелы один за другим .

  3. Преобразование более эффективно из-за 2. выше.

  4. Обратите внимание на использование функции XPath substring().

2 голосов
/ 22 января 2009

Вот как я заставил это работать:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="//li">
        <xsl:call-template name="loop">
            <xsl:with-param name="maxcount" select="count(ancestor::li)"/>
            <xsl:with-param name="initial-value" select="0"/>
        </xsl:call-template>
        <xsl:text>* </xsl:text>
        <xsl:value-of select="normalize-space(text())"/>
        <xsl:text>&#xd;</xsl:text>
        <xsl:apply-templates select="ul/li" />
    </xsl:template>
    <xsl:template name="loop">
        <xsl:param name="maxcount"/>
        <xsl:param name="initial-value"/>
        <xsl:if test="$initial-value &lt; $maxcount">
            <xsl:text>&#x9;</xsl:text>
            <xsl:call-template name="loop">
                <xsl:with-param name="maxcount" select="$maxcount"/>
                <xsl:with-param name="initial-value" select="$initial-value+1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Вот как это ломается:

<xsl:output method="text"/>
<xsl:strip-space elements="*"/>

Вы должны убедиться, что вывод XSLT является текстом, и вы также хотите удалить любые существующие пробелы.

<xsl:template match="//li">
    ...
</xsl:template>

Это ваш основной шаблон, который будет соответствовать каждому <li> в документе. Первый шаг в этом шаблоне - вывести соответствующее количество символов табуляции (не стесняйтесь, чтобы это было пробелами или чем угодно). Это можно сделать, вызвав собственный шаблон loop, который будет рекурсивно вызывать себя, с циклом от initial-value до maxcount, выводя символ табуляции (&#x9;) на каждой итерации.

<xsl:text>* </xsl:text>
<xsl:value-of select="normalize-space(text())"/>
<xsl:text>&#xd;</xsl:text>

Этот блок просто выводит текст с * перед и новой строкой (&#xd;) после. Обратите внимание, что я использовал функцию text() вместо ., чтобы получить значение узла. Если вы этого не сделаете, выходные данные родительского узла будут (как и должно быть в соответствии с рекомендацией W3C) объединить все дочерние текстовые узлы с родительским.

<xsl:apply-templates select="ul/li" />

Наконец, мы рекурсивно вызываем текущий шаблон, но явно ссылаемся на следующий <li>, который является прямым потомком <ul> - это удерживает нас от случайного вызова шаблона дважды для одного и того же родительского элемента.

...